label.autoadd_temp = Add Temperature Factor annotation to alignment
label.structure_viewer = Default structure viewer
label.double_click_to_browse = Double-click to browse for file
-label.chimera_path = Path to Chimera program
+label.chimera_path = Path to {0} program
label.chimera_path_tip = Jalview will first try any path entered here, else standard installation locations.<br>Double-click to browse for file.
label.invalid_chimera_path = Chimera path not found or not executable
label.chimera_missing = Chimera structure viewer not found.<br/>Please enter the path to Chimera (if installed),<br/>or download and install UCSF Chimera.
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}
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
exception.unable_to_detect_internet_connection=Jalview no puede detectar una conexión a Internet
-label.chimera_path=Ruta de acceso a Chimera
+label.chimera_path=Ruta de acceso a {0}
warn.delete_all=<html>Borrar todas las secuencias cerrará la ventana del alineamiento.<br>Confirmar o Cancelar.
label.select_all=Seleccionar Todos
label.alpha_helix=Hélice Alfa
for (ChimeraModel chimeraModel : modelList)
{
// get model color
- Color modelColor = getModelColor(chimeraModel);
+ Color modelColor = isChimeraX() ? null : getModelColor(chimeraModel);
if (modelColor != null)
{
chimeraModel.setModelColor(modelColor);
// chimeraSend("repr stick "+newModel.toSpec());
// Create the information we need for the navigator
- if (type != ModelType.SMILES)
+ if (type != ModelType.SMILES && !isChimeraX())
{
addResidues(chimeraModel);
}
public void stopListening()
{
- sendChimeraCommand("listen stop models ; listen stop selection ", false);
+ // TODO send this command when viewer connection is closed in Jalview
+ String command = isChimeraX
+ ? "info notify stop models jalview; info notify stop selection jalview"
+ : "listen stop models ; listen stop selection ";
+ sendChimeraCommand(command, false);
}
/**
*/
public void startListening(String uri)
{
- sendChimeraCommand("listen start models url " + uri
- + ";listen start select prefix SelectionChanged url " + uri,
- false);
+ /*
+ * listen for model changes
+ */
+ String command = isChimeraX
+ ? ("info notify start models prefix ModelChanged jalview url "
+ + uri)
+ : ("listen start models url " + uri);
+ sendChimeraCommand(command, false);
+
+ /*
+ * listen for selection changes
+ */
+ command = isChimeraX
+ ? ("info notify start selection jalview prefix SelectionChanged url "
+ + uri)
+ : ("listen start select prefix SelectionChanged url " + uri);
+ sendChimeraCommand(command, false);
}
/**
public List<String> getSelectedResidueSpecs()
{
List<String> selectedResidues = new ArrayList<>();
- List<String> chimeraReply = sendChimeraCommand(
- "list selection level residue", true);
+
+ /*
+ * skip for now if ChimeraX - request times out
+ */
+ if (isChimeraX)
+ {
+ return selectedResidues;
+ }
+
+ // in fact 'listinfo' (undocumented) works in ChimeraX
+ String command = (isChimeraX
+ ? "info"
+ : "list") + " selection level residue";
+ List<String> chimeraReply = sendChimeraCommand(command, true);
if (chimeraReply != null)
{
/*
- * expect 0, 1 or more lines of the format
+ * expect 0, 1 or more lines of the format either
+ * Chimera:
* residue id #0:43.A type GLY
- * where we are only interested in the atomspec #0.43.A
+ * ChimeraX:
+ * residue id /A:89 name THR index 88
+ * We are only interested in the atomspec (third token of the reply)
*/
for (String inputLine : chimeraReply)
{
String[] inputLineParts = inputLine.split("\\s+");
- if (inputLineParts.length == 5)
+ if (inputLineParts.length >= 5)
{
selectedResidues.add(inputLineParts[2]);
}
public List<ChimeraModel> getModelList()
{
List<ChimeraModel> modelList = new ArrayList<>();
- List<String> list = sendChimeraCommand("list models type molecule",
- true);
+ String command = "list models type "
+ + (isChimeraX ? "AtomicStructure" : "molecule");
+ List<String> list = sendChimeraCommand(command, true);
if (list != null)
{
for (String modelLine : list)
{
- ChimeraModel chimeraModel = new ChimeraModel(modelLine);
- modelList.add(chimeraModel);
+ try
+ {
+ ChimeraModel chimeraModel = new ChimeraModel(modelLine);
+ modelList.add(chimeraModel);
+ } catch (NullPointerException e)
+ {
+ // hack for now
+ }
}
}
return modelList;
{
// ensure symbolic links are resolved
chimeraPath = Paths.get(chimeraPath).toRealPath().toString();
+ isChimeraX = chimeraPath.toLowerCase().contains("chimerax");
File path = new File(chimeraPath);
// uncomment the next line to simulate Chimera not installed
// path = new File(chimeraPath + "x");
args.add(chimeraPath);
// shows Chimera output window but suppresses REST responses:
// args.add("--debug");
- args.add("--start");
- args.add("RESTServer");
+ if (isChimeraX())
+ {
+ args.add("--cmd");
+ args.add("remote rest start");
+ }
+ else
+ {
+ args.add("--start");
+ args.add("RESTServer");
+ }
ProcessBuilder pb = new ProcessBuilder(args);
chimera = pb.start();
error = "";
{
responses.append("\n" + response);
// expect: REST server on host 127.0.0.1 port port_number
+ // ChimeraX is the same except "REST server started on host..."
if (response.startsWith("REST server"))
{
String[] tokens = response.split(" ");
- if (tokens.length == 7 && "port".equals(tokens[5]))
+ for (int i = 0; i < tokens.length - 1; i++)
{
- port = Integer.parseInt(tokens[6]);
- break;
+ if ("port".equals(tokens[i]))
+ {
+ port = Integer.parseInt(tokens[i + 1]);
+ break;
+ }
}
}
+ if (port > 0)
+ {
+ break; // hack for hanging readLine()
+ }
response = lineReader.readLine();
}
} catch (Exception e)
public List<String> getAttrList()
{
List<String> attributes = new ArrayList<>();
- final List<String> reply = sendChimeraCommand("list resattr", true);
+ String command = (isChimeraX ? "info " : "list ") + "resattr";
+ final List<String> reply = sendChimeraCommand(command, true);
if (reply != null)
{
for (String inputLine : reply)
private volatile boolean busy = false;
+ private boolean isChimeraX;
+
/**
* Send a command to Chimera.
*
*/
public List<String> sendChimeraCommand(String command, boolean reply)
{
- // System.out.println("chimeradebug>> " + command);
+ System.out.println("chimeradebug>> " + command);
if (!isChimeraLaunched() || command == null
|| "".equals(command.trim()))
{
{
String restUrl = "http://127.0.0.1:" + this.chimeraRestPort + "/run";
List<NameValuePair> commands = new ArrayList<>(1);
+ String method = isChimeraX() ? "GET" : "POST";
+ if ("GET".equals(method))
+ {
+ command = command.replace(" ", "+").replace("#", "%23")
+ .replace("|", "%7C").replace(";", "%3B");
+ }
commands.add(new BasicNameValuePair("command", command));
List<String> reply = new ArrayList<>();
BufferedReader response = null;
try
{
- response = HttpClientUtils.doHttpUrlPost(restUrl, commands, CONNECTION_TIMEOUT_MS,
- REST_REPLY_TIMEOUT_MS);
+ response = "GET".equals(method)
+ ? HttpClientUtils.doHttpGet(restUrl, commands,
+ CONNECTION_TIMEOUT_MS, REST_REPLY_TIMEOUT_MS)
+ : HttpClientUtils.doHttpUrlPost(restUrl, commands,
+ CONNECTION_TIMEOUT_MS, REST_REPLY_TIMEOUT_MS);
String line = "";
while ((line = response.readLine()) != null)
{
{
return chimera;
}
+
+ public boolean isChimeraX()
+ {
+ return isChimeraX;
+ }
+
+ public void setChimeraX(boolean b)
+ {
+ isChimeraX = b;
+ }
}
StructureSettings defaultSettings = null;
// TODO: [Optional] Change priority of Chimera paths
- public static List<String> getChimeraPaths()
+ public static List<String> getChimeraPaths(boolean isChimeraX)
{
List<String> pathList = new ArrayList<>();
/*
* Jalview addition: check if path set in user preferences.
*/
- String userPath = Cache.getDefault(Preferences.CHIMERA_PATH, null);
+ String userPath = Cache
+ .getDefault(isChimeraX ? Preferences.CHIMERAX_PATH
+ : Preferences.CHIMERA_PATH, null);
if (userPath != null)
{
pathList.add(0, userPath);
}
+ // FIXME get an updated StructureManager for code for ChimeraX paths
+ String chimera = isChimeraX ? "ChimeraX" : "chimera";
+
// Add default installation paths
String os = System.getProperty("os.name");
if (os.startsWith("Linux"))
{
- pathList.add("/usr/local/chimera/bin/chimera");
- pathList.add("/usr/local/bin/chimera");
- pathList.add("/usr/bin/chimera");
- pathList.add(System.getProperty("user.home") + "/opt/bin/chimera");
+ pathList.add("/usr/local/chimera/bin/" + chimera);
+ pathList.add("/usr/local/bin/" + chimera);
+ pathList.add("/usr/bin/" + chimera);
+ pathList.add(System.getProperty("user.home") + "/opt/bin/" + chimera);
}
else if (os.startsWith("Windows"))
{
for (String version : new String[] { "1.11", "1.11.1", "1.11.2",
"1.12", "1.12.1", "1.12.2", "1.13" })
{
- pathList.add(root + "\\Chimera " + version + "\\bin\\chimera");
+ pathList.add(root + "\\Chimera " + version + "\\bin\\" + chimera);
pathList.add(
- root + "\\Chimera " + version + "\\bin\\chimera.exe");
+ root + "\\Chimera " + version + "\\bin\\" + chimera
+ + ".exe");
}
}
}
else if (os.startsWith("Mac"))
{
- pathList.add("/Applications/Chimera.app/Contents/MacOS/chimera");
+ pathList.add("/Applications/Chimera.app/Contents/MacOS/" + chimera);
}
return pathList;
}
import jalview.api.AlignmentViewPanel;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
-import jalview.schemes.ColourSchemeI;
import jalview.structures.models.AAStructureBindingModel;
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
*/
void raiseViewer();
+ AlignmentViewPanel getAlignmentPanel();
+
+ /**
+ * Answers true if the given alignment view is used to colour structures by
+ * sequence, false if not
+ *
+ * @param ap
+ * @return
+ */
+ boolean isUsedForColourBy(AlignmentViewPanel ap);
+
+ /**
+ * If implemented, shows a command line console in the structure viewer
+ *
+ * @param show
+ * true to show, false to hide
+ */
+ void showConsole(boolean show);
+
+ /**
+ * Remove references to the given alignment view for this structure viewer
+ *
+ * @param avp
+ */
+ void removeAlignmentPanel(AlignmentViewPanel avp);
+
+ /**
+ * Updates the progress bar if there is one. Call stopProgressBar with the
+ * returned handle to remove the message.
+ *
+ * @param msg
+ * @return handle
+ */
+ long startProgressBar(String msg);
+
+ /**
+ * Ends the progress bar with the specified handle, leaving a message (if not
+ * null) on the status bar
+ *
+ * @param msg
+ * @param handle
+ */
+ void stopProgressBar(String msg, long handle);
+
}
* without an additional javascript library to exchange messages between the
* distinct applets. See http://issues.jalview.org/browse/JAL-621
*
- * @param viewer
+ * @param jmolViewer
* JmolViewer instance
* @param sequenceIds
* - sequence Ids to search for associations
else if (protocol == DataSourceType.FILE
|| protocol == DataSourceType.URL)
{
- jmb.viewer.openFile(pdbentry.getFile());
+ jmb.jmolViewer.openFile(pdbentry.getFile());
}
else
{
throw new Exception(MessageManager.getString(
"exception.invalid_datasource_couldnt_obtain_reader"));
}
- jmb.viewer.openReader(pdbentry.getFile(), pdbentry.getId(),
+ jmb.jmolViewer.openReader(pdbentry.getFile(), pdbentry.getId(),
freader);
} catch (Exception e)
{
}
}
}
- jmb.centerViewer(toshow);
+ jmb.showChains(toshow);
}
void closeViewer()
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)
{
{
currentSize = this.getSize();
- if (jmb.viewer == null)
+ if (jmb.jmolViewer == null)
{
g.setColor(Color.black);
g.fillRect(0, 0, currentSize.width, currentSize.height);
}
else
{
- jmb.viewer.renderScreenImage(g, currentSize.width,
+ jmb.jmolViewer.renderScreenImage(g, currentSize.width,
currentSize.height);
}
}
*
* }
*/
- public void setJalviewColourScheme(UserColourScheme ucs)
+ public void colourByJalviewColourScheme(UserColourScheme ucs)
{
- jmb.setJalviewColourScheme(ucs);
+ jmb.colourByJalviewColourScheme(ucs);
}
public AlignmentPanel getAlignmentPanelFor(AlignmentI alignment)
}
@Override
- public jalview.api.FeatureRenderer getFeatureRenderer(
- AlignmentViewPanel alignment)
- {
- return appletJmolBinding.ap.getFeatureRenderer();
- }
-
- @Override
public jalview.api.SequenceRenderer getSequenceRenderer(
AlignmentViewPanel alignment)
{
Container consolePanel, String buttonsToShow)
{
JmolAppConsoleInterface appc = new AppletConsole();
- appc.start(viewer);
+ appc.start(jmolViewer);
return appc;
}
{
return null;
}
+
+ @Override
+ protected void sendAsynchronousCommand(String command, String progressMsg)
+ {
+ // TODO Auto-generated method stub
+
+ }
}
package jalview.appletgui;
import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
}
@Override
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
- {
- AlignmentPanel alignPanel = (AlignmentPanel) alignment;
- if (alignPanel.av.isShowSequenceFeatures())
- {
- return alignPanel.getFeatureRenderer();
- }
- else
- {
- return null;
- }
- }
-
-
- @Override
public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
{
return ((AlignmentPanel) alignment).getSequenceRenderer();
}
@Override
- public void releaseReferences(Object svl)
+ public Map<String, Object> getJSpecViewProperty(String arg0)
{
+ return null;
}
@Override
- public Map<String, Object> getJSpecViewProperty(String arg0)
+ protected void sendAsynchronousCommand(String command, String progressMsg)
{
- return null;
+ // TODO Auto-generated method stub
+
}
}
}
else if (jmol != null)
{
- jmol.setJalviewColourScheme(ucs);
+ jmol.colourByJalviewColourScheme(ucs);
}
else if (pdbcanvas != null)
{
*/
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;
import jalview.datamodel.SequenceI;
import jalview.gui.IProgressIndicator;
+import jalview.gui.StructureViewer.ViewerType;
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.StructureCommandsI.SuperposeData;
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;
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;
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
{
private String lastMessage;
- boolean allChainsSelected = false;
-
/*
* when true, try to search the associated datamodel for sequences that are
* associated with any unknown structures in the Jmol view.
*/
private boolean associateNewStructs = false;
- Vector<String> atomsPicked = new Vector<>();
-
- private List<String> chainNames;
-
- Hashtable<String, String> chainFile;
-
- /*
- * the default or current model displayed if the model cannot be identified
- * from the selection message
- */
- int frameNo = 0;
-
- // protected JmolGenericPopup jmolpopup; // not used - remove?
+ private Vector<String> atomsPicked = new Vector<>();
- String lastCommand;
+ private String lastCommand;
- boolean loadedInline;
+ private boolean loadedInline;
- StringBuffer resetLastRes = new StringBuffer();
+ private StringBuffer resetLastRes = new StringBuffer();
- public Viewer viewer;
+ public Viewer jmolViewer;
public JalviewJmolBinding(StructureSelectionManager ssm,
PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
DataSourceType protocol)
{
super(ssm, pdbentry, sequenceIs, protocol);
+ setStructureCommands(new JmolCommands());
/*
* viewer = JmolViewer.allocateViewer(renderPanel, new SmarterJmolAdapter(),
* "jalviewJmol", ap.av.applet .getDocumentBase(),
{
super(ssm, seqs);
- viewer = theViewer;
- viewer.setJmolStatusListener(this);
- viewer.addSelectionListener(this);
+ jmolViewer = theViewer;
+ jmolViewer.setJmolStatusListener(this);
+ jmolViewer.addSelectionListener(this);
+ setStructureCommands(new JmolCommands());
}
/**
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<String> 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
getSsm().removeStructureViewerListener(this, this.getStructureFiles());
- viewer.dispose();
+ jmolViewer.dispose();
lastCommand = null;
- viewer = null;
+ jmolViewer = null;
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.
- */
- public void superposeStructures(AlignmentI alignment)
- {
- superposeStructures(alignment, -1, null);
- }
-
- /**
- * superpose the structures associated with sequences in the alignment
- * according to their corresponding positions. ded)
- *
- * @param refStructure
- * - select which pdb file to use as reference (default is -1 - the
- * first structure in the alignment)
- */
- public void superposeStructures(AlignmentI alignment, int refStructure)
- {
- superposeStructures(alignment, refStructure, null);
- }
-
- /**
- * superpose the structures associated with sequences in the alignment
- * according to their corresponding positions. ded)
- *
- * @param refStructure
- * - select which pdb file to use as reference (default is -1 - the
- * first structure in the alignment)
- * @param hiddenCols
- * TODO
- */
- public void superposeStructures(AlignmentI alignment, int refStructure,
- HiddenColumns hiddenCols)
- {
- superposeStructures(new AlignmentI[] { alignment },
- new int[]
- { refStructure }, new HiddenColumns[] { hiddenCols });
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String superposeStructures(AlignmentI[] _alignment,
- int[] _refStructure, HiddenColumns[] _hiddenCols)
+ public List<String> executeCommand(String command, boolean getReply)
{
- while (viewer.isScriptExecuting())
- {
- try
- {
- Thread.sleep(10);
- } catch (InterruptedException i)
- {
- }
- }
-
- /*
- * get the distinct structure files modelled
- * (a file with multiple chains may map to multiple sequences)
- */
- String[] files = getStructureFiles();
- if (!waitForFileLoad(files))
+ if (command == null)
{
return null;
}
-
- StringBuilder selectioncom = new StringBuilder(256);
- // In principle - nSeconds specifies the speed of animation for each
- // superposition - but is seems to behave weirdly, so we don't specify it.
- String nSeconds = " ";
- if (files.length > 10)
- {
- nSeconds = " 0.005 ";
- }
- else
- {
- nSeconds = " " + (2.0 / files.length) + " ";
- // if (nSeconds).substring(0,5)+" ";
- }
-
- // see JAL-1345 - should really automatically turn off the animation for
- // large numbers of structures, but Jmol doesn't seem to allow that.
- // nSeconds = " ";
- // union of all aligned positions are collected together.
- for (int a = 0; a < _alignment.length; a++)
- {
- int refStructure = _refStructure[a];
- AlignmentI alignment = _alignment[a];
- HiddenColumns hiddenCols = _hiddenCols[a];
- if (a > 0 && selectioncom.length() > 0 && !selectioncom
- .substring(selectioncom.length() - 1).equals("|"))
- {
- selectioncom.append("|");
- }
- // process this alignment
- if (refStructure >= files.length)
- {
- System.err.println(
- "Invalid reference structure value " + refStructure);
- refStructure = -1;
- }
-
- /*
- * 'matched' bit j will be set for visible alignment columns j where
- * all sequences have a residue with a mapping to the PDB structure
- */
- BitSet matched = new BitSet();
- for (int m = 0; m < alignment.getWidth(); m++)
- {
- if (hiddenCols == null || hiddenCols.isVisible(m))
- {
- matched.set(m);
- }
- }
-
- SuperposeData[] structures = new SuperposeData[files.length];
- for (int f = 0; f < files.length; f++)
- {
- structures[f] = new SuperposeData(alignment.getWidth());
- }
-
- /*
- * Calculate the superposable alignment columns ('matched'), and the
- * corresponding structure residue positions (structures.pdbResNo)
- */
- int candidateRefStructure = findSuperposableResidues(alignment,
- matched, structures);
- if (refStructure < 0)
- {
- /*
- * If no reference structure was specified, pick the first one that has
- * a mapping in the alignment
- */
- refStructure = candidateRefStructure;
- }
-
- String[] selcom = new String[files.length];
- int nmatched = matched.cardinality();
- if (nmatched < 4)
- {
- return (MessageManager.formatMessage("label.insufficient_residues",
- nmatched));
- }
-
- /*
- * generate select statements to select regions to superimpose structures
- */
- {
- // TODO extract method to construct selection statements
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
- {
- String chainCd = ":" + structures[pdbfnum].chain;
- int lpos = -1;
- boolean run = false;
- StringBuilder molsel = new StringBuilder();
- molsel.append("{");
-
- int nextColumnMatch = matched.nextSetBit(0);
- while (nextColumnMatch != -1)
- {
- int pdbResNo = structures[pdbfnum].pdbResNo[nextColumnMatch];
- if (lpos != pdbResNo - 1)
- {
- // discontinuity
- if (lpos != -1)
- {
- molsel.append(lpos);
- molsel.append(chainCd);
- molsel.append("|");
- }
- run = false;
- }
- else
- {
- // continuous run - and lpos >-1
- if (!run)
- {
- // at the beginning, so add dash
- molsel.append(lpos);
- molsel.append("-");
- }
- run = true;
- }
- lpos = pdbResNo;
- nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
- }
- /*
- * add final selection phrase
- */
- if (lpos != -1)
- {
- molsel.append(lpos);
- molsel.append(chainCd);
- molsel.append("}");
- }
- if (molsel.length() > 1)
- {
- selcom[pdbfnum] = molsel.toString();
- selectioncom.append("((");
- selectioncom.append(selcom[pdbfnum].substring(1,
- selcom[pdbfnum].length() - 1));
- selectioncom.append(" )& ");
- selectioncom.append(pdbfnum + 1);
- selectioncom.append(".1)");
- if (pdbfnum < files.length - 1)
- {
- selectioncom.append("|");
- }
- }
- else
- {
- selcom[pdbfnum] = null;
- }
- }
- }
- StringBuilder command = new StringBuilder(256);
- // command.append("set spinFps 10;\n");
-
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
- {
- if (pdbfnum == refStructure || selcom[pdbfnum] == null
- || selcom[refStructure] == null)
- {
- continue;
- }
- command.append("echo ");
- command.append("\"Superposing (");
- command.append(structures[pdbfnum].pdbId);
- command.append(") against reference (");
- command.append(structures[refStructure].pdbId);
- command.append(")\";\ncompare " + nSeconds);
- command.append("{");
- command.append(Integer.toString(1 + pdbfnum));
- command.append(".1} {");
- command.append(Integer.toString(1 + refStructure));
- // conformation=1 excludes alternate locations for CA (JAL-1757)
- command.append(
- ".1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS ");
-
- // for (int s = 0; s < 2; s++)
- // {
- // command.append(selcom[(s == 0 ? pdbfnum : refStructure)]);
- // }
- command.append(selcom[pdbfnum]);
- command.append(selcom[refStructure]);
- command.append(" ROTATE TRANSLATE;\n");
- }
- if (selectioncom.length() > 0)
- {
- // 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; ");
- // selcom.append("; ribbons; ");
- String cmdString = command.toString();
- // System.out.println("Superimpose command(s):\n" + cmdString);
-
- evalStateCommand(cmdString);
- }
- }
- if (selectioncom.length() > 0)
- {// finally, mark all regions that were superposed.
- if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
- {
- selectioncom.setLength(selectioncom.length() - 1);
- }
- // System.out.println("Select regions:\n" + selectioncom.toString());
- evalStateCommand("select *; cartoons off; backbone; select ("
- + selectioncom.toString() + "); cartoons; ");
- // evalStateCommand("select *; backbone; select "+selcom.toString()+";
- // cartoons; center "+selcom.toString());
- }
-
- return null;
- }
-
- public void evalStateCommand(String command)
- {
jmolHistory(false);
if (lastCommand == null || !lastCommand.equals(command))
{
- viewer.evalStringQuiet(command + "\n");
+ jmolViewer.evalStringQuiet(command + "\n");
}
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)
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 = viewer.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
- * Jalview knows about.
- */
- 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 -
public synchronized String[] getStructureFiles()
{
List<String> mset = new ArrayList<>();
- if (viewer == null)
+ if (jmolViewer == null)
{
return new String[0];
}
if (modelFileNames == null)
{
- int modelCount = viewer.ms.mc;
+ int modelCount = jmolViewer.ms.mc;
String filePath = null;
for (int i = 0; i < modelCount; ++i)
{
- filePath = viewer.ms.getModelFileName(i);
+ filePath = jmolViewer.ms.getModelFileName(i);
if (!mset.contains(filePath))
{
mset.add(filePath);
{
if (resetLastRes.length() > 0)
{
- viewer.evalStringQuiet(resetLastRes.toString());
+ jmolViewer.evalStringQuiet(resetLastRes.toString());
resetLastRes.setLength(0);
}
for (AtomSpec atom : atoms)
jmolHistory(false);
StringBuilder cmd = new StringBuilder(64);
- cmd.append("select " + pdbResNum); // +modelNum
+ cmd.append("select ").append(String.valueOf(pdbResNum)); // +modelNum
- resetLastRes.append("select " + pdbResNum); // +modelNum
+ resetLastRes.append("select ").append(String.valueOf(pdbResNum)); // +modelNum
cmd.append(":");
resetLastRes.append(":");
resetLastRes.append(chain);
}
{
- cmd.append(" /" + (mdlNum + 1));
- resetLastRes.append("/" + (mdlNum + 1));
+ cmd.append(" /").append(String.valueOf(mdlNum + 1));
+ resetLastRes.append("/").append(String.valueOf(mdlNum + 1));
}
cmd.append(";wireframe 100;" + cmd.toString() + " and not hetero;");
cmd.append("spacefill 200;select none");
- viewer.evalStringQuiet(cmd.toString());
+ jmolViewer.evalStringQuiet(cmd.toString());
jmolHistory(true);
}
- boolean debug = true;
+ private boolean debug = true;
private void jmolHistory(boolean enable)
{
- viewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
+ jmolViewer.evalStringQuiet("History " + ((debug || enable) ? "on" : "off"));
}
public void loadInline(String string)
// Then, construct pass a reader for the string to Jmol.
// ((org.jmol.Viewer.Viewer) viewer).loadModelFromFile(fullPathName,
// fileName, null, reader, false, null, null, 0);
- viewer.openStringInline(string);
+ jmolViewer.openStringInline(string);
}
protected void mouseOverStructure(int atomIndex, final String strInfo)
chainId = " ";
}
- String pdbfilename = modelFileNames[frameNo]; // default is first or current
- // model
+ String pdbfilename = modelFileNames[0]; // default is first model
if (mdlSep > -1)
{
if (chainSeparator1 == -1)
if (pdbfilename == null)
{
- pdbfilename = new File(viewer.ms.getModelFileName(mnumber))
+ pdbfilename = new File(jmolViewer.ms.getModelFileName(mnumber))
.getAbsolutePath();
}
}
sb.append(";set hoverLabel \"").append(toks.nextToken()).append(" ")
.append(toks.nextToken());
sb.append("|").append(label).append("\"");
- evalStateCommand(sb.toString());
+ executeCommand(sb.toString(), false);
}
}
if (!atomsPicked.contains(picked))
{
- viewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
+ jmolViewer.evalStringQuiet("select " + picked + ";label %n %r:%c");
atomsPicked.addElement(picked);
}
else
{
- viewer.evalString("select " + picked + ";label off");
+ jmolViewer.evalString("select " + picked + ";label off");
atomsPicked.removeElement(picked);
}
jmolHistory(true);
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
// calculate essential attributes for the pdb data imported inline.
// prolly need to resolve modelnumber properly - for now just use our
// 'best guess'
- pdbfile = viewer.getData(
+ pdbfile = jmolViewer.getData(
"" + (1 + _modelFileNameMap[modelnum]) + ".0", "PDB");
}
// search pdbentries and sequences to find correct pdbentry for this
// 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;
}
// this is a foreign pdb file that jalview doesn't know about - add
// it to the dataset and try to find a home - either on a matching
// sequence or as a new sequence.
- String pdbcontent = viewer.getData("/" + (modelnum + 1) + ".1",
+ String pdbcontent = jmolViewer.getData("/" + (modelnum + 1) + ".1",
"PDB");
// parse pdb file into a chain, etc.
// locate best match for pdb in associated views and add mapping to
// }
if (!isLoadingFromArchive())
{
- viewer.evalStringQuiet(
+ jmolViewer.evalStringQuiet(
"model *; select backbone;restrict;cartoon;wireframe off;spacefill off");
}
// register ourselves as a listener and notify the gui that it needs to
setLoadingFromArchive(false);
}
- @Override
- public List<String> getChainNames()
- {
- return chainNames;
- }
-
protected IProgressIndicator getIProgressIndicator()
{
return null;
}
- @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<String> 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");
public abstract void showUrl(String url, String target);
/**
- * called when the binding thinks the UI needs to be refreshed after a Jmol
- * state change. this could be because structures were loaded, or because an
- * error has occured.
- */
- public abstract void refreshGUI();
-
- /**
* called to show or hide the associated console window container.
*
* @param show
{
commandOptions = "";
}
- viewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
+ jmolViewer = (Viewer) JmolViewer.allocateViewer(renderPanel,
(jmolfileio ? new SmarterJmolAdapter() : null),
htmlName + ((Object) this).toString(), documentBase, codeBase,
commandOptions, this);
- viewer.setJmolStatusListener(this); // extends JmolCallbackListener
+ jmolViewer.setJmolStatusListener(this); // extends JmolCallbackListener
console = createJmolConsole(consolePanel, buttonsToShow);
if (consolePanel != null)
protected org.jmol.api.JmolAppConsoleInterface console = null;
@Override
- public void setBackgroundColour(java.awt.Color col)
- {
- jmolHistory(false);
- viewer.evalStringQuiet("background [" + col.getRed() + ","
- + col.getGreen() + "," + col.getBlue() + "];");
- jmolHistory(true);
- }
-
- @Override
public int[] resizeInnerPanel(String data)
{
// Jalview doesn't honour resize panel requests
{
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;
+ }
+
+ @Override
+ protected ViewerType getViewerType()
+ {
+ return ViewerType.JMOL;
+ }
}
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.structure.AtomSpecModel;
+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;
/**
- * 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";
+
+ private static final String CMD_COLOUR_BY_CHAIN = "select *;color chain";
+
+ private static final String PIPE = "|";
+
+ private static final String HYPHEN = "-";
+
+ private static final String COLON = ":";
+
+ private static final String SLASH = "/";
/**
- * Jmol utility which constructs the commands to colour chains by the given
- * alignment
+ * {@inheritDoc}
*
- * @returns Object[] { Object[] { <model being coloured>,
+ * @return
+ */
+ @Override
+ public int getModelStartNo()
+ {
+ return 1;
+ }
+
+ /**
+ * Returns a string representation of the given colour suitable for inclusion
+ * in Jmol commands
*
+ * @param c
+ * @return
*/
- public static StructureMappingcommandSet[] getColourBySequenceCommand(
- StructureSelectionManager ssm, String[] files,
+ protected String getColourString(Color c)
+ {
+ return c == null ? null
+ : String.format("[%d,%d,%d]", c.getRed(), c.getGreen(),
+ c.getBlue());
+ }
+
+
+ public String[] colourBySequence(StructureSelectionManager ssm,
+ String[] files,
SequenceI[][] sequence, SequenceRenderer sr,
AlignmentViewPanel viewPanel)
{
+ // TODO delete method
+
FeatureRenderer fr = viewPanel.getFeatureRenderer();
FeatureColourFinder finder = new FeatureColourFinder(fr);
AlignViewportI viewport = viewPanel.getAlignViewport();
HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
AlignmentI al = viewport.getAlignment();
- List<StructureMappingcommandSet> cset = new ArrayList<StructureMappingcommandSet>();
+ List<String> cset = new ArrayList<>();
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
- StringBuffer command = new StringBuffer();
- StructureMappingcommandSet smc;
- ArrayList<String> str = new ArrayList<String>();
+ StringBuilder command = new StringBuilder(128);
+ List<String> str = new ArrayList<>();
if (mapping == null || mapping.length < 1)
{
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;
}
String newSelcom = (mapping[m].getChain() != " "
? ":" + mapping[m].getChain()
- : "") + "/" + (pdbfnum + 1) + ".1" + ";color["
- + col.getRed() + "," + col.getGreen() + ","
- + col.getBlue() + "]";
+ : "") + "/" + (pdbfnum + 1) + ".1" + ";color"
+ + getColourString(col);
if (command.length() > newSelcom.length() && command
.substring(command.length() - newSelcom.length())
.equals(newSelcom))
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'
;
} 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);
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<String, Color> colours)
+ {
+ StringBuilder cmd = new StringBuilder(128);
+ cmd.append("select *;color white;");
+ cmd.append(super.colourByResidues(colours));
+
+ return cmd.toString();
+ }
+
+ @Override
+ public String setBackgroundColour(Color col)
+ {
+ return "background " + getColourString(col);
+ }
+
+ @Override
+ public String focusView()
+ {
+ return "zoom 0";
+ }
+
+ @Override
+ public String showChains(List<String> 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;
+ }
+
+ /**
+ * Returns a command to superpose atoms in {@code atomSpec} to those in
+ * {@code refAtoms}, restricted to alpha carbons only (Phosphorous for rna).
+ * For example
+ *
+ * <pre>
+ * compare {2.1} {1.1} SUBSET {(*.CA | *.P) and conformation=1}
+ * ATOMS {1-87:A}{2-54:A|61-94:A} ROTATE TRANSLATE 1.0;
+ * </pre>
+ *
+ * where {@code conformation=1} excludes ALTLOC atom locations, and 1.0 is the
+ * time in seconds to animate the action. For this example, atoms in model 2
+ * are moved towards atoms in model 1.
+ * <p>
+ * The two atomspecs should each be for one model only, but may have more than
+ * one chain. The number of atoms specified should be the same for both
+ * models, though if not, Jmol may make a 'best effort' at superposition.
+ *
+ * @see https://chemapps.stolaf.edu/jmol/docs/#compare
+ */
+ @Override
+ public String superposeStructures(AtomSpecModel refAtoms,
+ AtomSpecModel atomSpec)
+ {
+ StringBuilder sb = new StringBuilder(64);
+ int refModel = refAtoms.getModels().iterator().next();
+ int model2 = atomSpec.getModels().iterator().next();
+ sb.append(String.format("compare {%d.1} {%d.1}", model2, refModel));
+ sb.append(" SUBSET {(*.CA | *.P) and conformation=1} ATOMS {");
+
+ /*
+ * command examples don't include modelspec with atoms, getAtomSpec does;
+ * it works, so leave it as it is for simplicity
+ */
+ sb.append(getAtomSpec(atomSpec, true)).append("}{");
+ sb.append(getAtomSpec(refAtoms, true)).append("}");
+ sb.append(" ROTATE TRANSLATE ");
+ sb.append(getCommandSeparator());
+
+ /*
+ * show residues used for superposition as ribbon
+ */
+ sb.append("select ").append(getAtomSpec(atomSpec, false)).append("|");
+ sb.append(getAtomSpec(refAtoms, false)).append(getCommandSeparator())
+ .append("cartoons");
+
+ return sb.toString();
+ }
+
+ @Override
+ public String openCommandFile(String path)
+ {
+ /*
+ * https://chemapps.stolaf.edu/jmol/docs/#script
+ * not currently used in Jalview
+ */
+ return "script " + path;
+ }
+
+ @Override
+ public String saveSession(String filepath)
+ {
+ /*
+ * https://chemapps.stolaf.edu/jmol/docs/#write
+ * not currently used in Jalview
+ */
+ return "write \"" + filepath + "\"";
+ }
+
+ @Override
+ protected String getColourCommand(String atomSpec, Color colour)
+ {
+ StringBuilder sb = new StringBuilder(atomSpec.length()+20);
+ sb.append("select ").append(atomSpec).append(getCommandSeparator())
+ .append("color").append(getColourString(colour));
+ return sb.toString();
+ }
+
+ @Override
+ protected String getResidueSpec(String residue)
+ {
+ return residue;
+ }
+
+ /**
+ * Generates a Jmol atomspec string like
+ *
+ * <pre>
+ * 2-5:A/1.1,8:A/1.1,5-10:B/2.1
+ * </pre>
+ *
+ * Parameter {@code alphaOnly} is not used here - this restriction is made by
+ * a separate clause in the {@code compare} (superposition) command.
+ */
+ @Override
+ public String getAtomSpec(AtomSpecModel model, boolean alphaOnly)
+ {
+ StringBuilder sb = new StringBuilder(128);
+
+ boolean first = true;
+ for (int modelNo : model.getModels())
+ {
+ for (String chain : model.getChains(modelNo))
+ {
+ for (int[] range : model.getRanges(modelNo, chain))
+ {
+ if (!first)
+ {
+ sb.append(PIPE);
+ }
+ first = false;
+ if (range[0] == range[1])
+ {
+ sb.append(range[0]);
+ }
+ else
+ {
+ sb.append(range[0]).append(HYPHEN).append(range[1]);
+ }
+ sb.append(COLON).append(chain.trim()).append(SLASH);
+ sb.append(String.valueOf(modelNo)).append(".1");
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ @Override
+ public String showBackbone()
+ {
+ return "select *; cartoons off; backbone";
+ }
}
+++ /dev/null
-/*
- * 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 <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.ext.rbvi.chimera;
-
-import jalview.util.IntRangeComparator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-/**
- * A class to model a Chimera atomspec pattern, for example
- *
- * <pre>
- * #0:15.A,28.A,54.A,63.A,70-72.A,83-84.A,97-98.A|#1:2.A,6.A,11.A,13-14.A,70.A,82.A,96-97.A
- * </pre>
- *
- * where
- * <ul>
- * <li>#0 is a model number</li>
- * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
- * <li>.A is a chain identifier</li>
- * <li>residue ranges are separated by comma</li>
- * <li>atomspecs for distinct models are separated by | (or)</li>
- * </ul>
- *
- * <pre>
- * @see http://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
- * </pre>
- */
-public class AtomSpecModel
-{
- private Map<Integer, Map<String, List<int[]>>> atomSpec;
-
- /**
- * Constructor
- */
- public AtomSpecModel()
- {
- atomSpec = new TreeMap<Integer, Map<String, List<int[]>>>();
- }
-
- /**
- * Adds one contiguous range to this atom spec
- *
- * @param model
- * @param startPos
- * @param endPos
- * @param chain
- */
- public void addRange(int model, int startPos, int endPos, String chain)
- {
- /*
- * Get/initialize map of data for the colour and model
- */
- Map<String, List<int[]>> modelData = atomSpec.get(model);
- if (modelData == null)
- {
- atomSpec.put(model, modelData = new TreeMap<String, List<int[]>>());
- }
-
- /*
- * Get/initialize map of data for colour, model and chain
- */
- List<int[]> chainData = modelData.get(chain);
- if (chainData == null)
- {
- chainData = new ArrayList<int[]>();
- modelData.put(chain, chainData);
- }
-
- /*
- * Add the start/end positions
- */
- chainData.add(new int[] { startPos, endPos });
- // TODO add intelligently, using a RangeList class
- }
-
- /**
- * Returns the range(s) formatted as a Chimera atomspec
- *
- * @return
- */
- public String getAtomSpec()
- {
- StringBuilder sb = new StringBuilder(128);
- boolean firstModel = true;
- for (Integer model : atomSpec.keySet())
- {
- if (!firstModel)
- {
- sb.append("|");
- }
- firstModel = false;
- sb.append("#").append(model).append(":");
-
- boolean firstPositionForModel = true;
- final Map<String, List<int[]>> modelData = atomSpec.get(model);
-
- for (String chain : modelData.keySet())
- {
- chain = " ".equals(chain) ? chain : chain.trim();
-
- List<int[]> rangeList = modelData.get(chain);
-
- /*
- * sort ranges into ascending start position order
- */
- Collections.sort(rangeList, IntRangeComparator.ASCENDING);
-
- int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
- int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
-
- Iterator<int[]> iterator = rangeList.iterator();
- while (iterator.hasNext())
- {
- int[] range = iterator.next();
- if (range[0] <= end + 1)
- {
- /*
- * range overlaps or is contiguous with the last one
- * - so just extend the end position, and carry on
- * (unless this is the last in the list)
- */
- end = Math.max(end, range[1]);
- }
- else
- {
- /*
- * we have a break so append the last range
- */
- appendRange(sb, start, end, chain, firstPositionForModel);
- firstPositionForModel = false;
- start = range[0];
- end = range[1];
- }
- }
-
- /*
- * and append the last range
- */
- if (!rangeList.isEmpty())
- {
- appendRange(sb, start, end, chain, firstPositionForModel);
- firstPositionForModel = false;
- }
- }
- }
- return sb.toString();
- }
-
- /**
- * @param sb
- * @param start
- * @param end
- * @param chain
- * @param firstPositionForModel
- */
- protected void appendRange(StringBuilder sb, int start, int end,
- String chain, boolean firstPositionForModel)
- {
- if (!firstPositionForModel)
- {
- sb.append(",");
- }
- if (end == start)
- {
- sb.append(start);
- }
- else
- {
- sb.append(start).append("-").append(end);
- }
-
- sb.append(".");
- if (!" ".equals(chain)) {
- sb.append(chain);
- }
- }
-}
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.AtomSpecModel;
+import jalview.structure.StructureCommandsBase;
import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.util.ColorUtils;
-import jalview.util.Comparison;
+import jalview.util.IntRangeComparator;
import java.awt.Color;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
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
- * @return
- */
- public static StructureMappingcommandSet[] getColourBySequenceCommand(
- StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr,
- AlignmentViewPanel viewPanel)
- {
- Map<Object, AtomSpecModel> colourMap = buildColoursMap(ssm, files,
- sequence, sr, viewPanel);
-
- List<String> colourCommands = buildColourCommands(colourMap);
-
- StructureMappingcommandSet cs = new StructureMappingcommandSet(
- ChimeraCommands.class, null,
- colourCommands.toArray(new String[colourCommands.size()]));
-
- return new StructureMappingcommandSet[] { cs };
- }
-
- /**
- * Traverse the map of colours/models/chains/positions to construct a list of
- * 'color' commands (one per distinct colour used). The format of each command
- * is
- *
- * <pre>
- * <blockquote>
- * color colorname #modelnumber:range.chain
- * e.g. color #00ff00 #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
- * </blockquote>
- * </pre>
- *
- * @param colourMap
- * @return
- */
- protected static List<String> buildColourCommands(
- Map<Object, AtomSpecModel> colourMap)
- {
- /*
- * This version concatenates all commands into a single String (semi-colon
- * delimited). If length limit issues arise, refactor to return one color
- * command per colour.
- */
- List<String> commands = new ArrayList<>();
- StringBuilder sb = new StringBuilder(256);
- boolean firstColour = true;
- for (Object key : colourMap.keySet())
- {
- Color colour = (Color) key;
- String colourCode = ColorUtils.toTkCode(colour);
- if (!firstColour)
- {
- sb.append("; ");
- }
- sb.append("color ").append(colourCode).append(" ");
- firstColour = false;
- final AtomSpecModel colourData = colourMap.get(colour);
- sb.append(colourData.getAtomSpec());
- }
- commands.add(sb.toString());
- return commands;
- }
+ 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";
- /**
- * 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<Integer, Map<String, List<int[]>>> 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(":");
+ private static final String CMD_COLOUR_BY_CHAIN = "rainbow chain";
- final Map<String, List<int[]>> 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();
- }
+ // Chimera clause to exclude alternate locations in atom selection
+ private static final String NO_ALTLOCS = "&~@.B-Z&~@.2-9";
- /**
- * <pre>
- * 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)
- * </pre>
- */
- protected static Map<Object, AtomSpecModel> buildColoursMap(
- StructureSelectionManager ssm, String[] files,
- SequenceI[][] sequence, SequenceRenderer sr,
- AlignmentViewPanel viewPanel)
+ @Override
+ public String getColourCommand(String atomSpec, Color colour)
{
- FeatureRenderer fr = viewPanel.getFeatureRenderer();
- FeatureColourFinder finder = new FeatureColourFinder(fr);
- AlignViewportI viewport = viewPanel.getAlignViewport();
- HiddenColumns cs = viewport.getAlignment().getHiddenColumns();
- AlignmentI al = viewport.getAlignment();
- Map<Object, AtomSpecModel> 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;
+ // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/color.html
+ String colourCode = getColourString(colour);
+ return "color " + colourCode + " " + atomSpec;
}
/**
- * 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
- * <ul>
- * <li>a colour, when building a 'colour structure by sequence' command</li>
- * <li>a feature value, when building a 'set Chimera attributes from features'
- * command</li>
- * </ul>
+ * Returns a colour formatted suitable for use in viewer command syntax
*
- * @param map
- * @param value
- * @param model
- * @param startPos
- * @param endPos
- * @param chain
+ * @param colour
+ * @return
*/
- protected static void addAtomSpecRange(Map<Object, AtomSpecModel> map,
- Object value, int model, int startPos, int endPos, String chain)
+ protected String getColourString(Color colour)
{
- /*
- * 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);
+ return ColorUtils.toTkCode(colour);
}
/**
* 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.
+ * corresponding to features in Jalview. Attribute names are the Jalview feature
+ * type, with a "jv_" prefix.
*
* @param ssm
* @param files
* @param viewPanel
* @return
*/
- public static StructureMappingcommandSet getSetAttributeCommandsForFeatures(
+ @Override
+ public String[] setAttributesForFeatures(
StructureSelectionManager ssm, String[] files, SequenceI[][] seqs,
AlignmentViewPanel viewPanel)
{
Map<String, Map<Object, AtomSpecModel>> featureMap = buildFeaturesMap(
ssm, files, seqs, viewPanel);
- List<String> commands = buildSetAttributeCommands(featureMap);
-
- StructureMappingcommandSet cs = new StructureMappingcommandSet(
- ChimeraCommands.class, null,
- commands.toArray(new String[commands.size()]));
-
- return cs;
+ return setAttributes(featureMap);
}
/**
* @param viewPanel
* @return
*/
- protected static Map<String, Map<Object, AtomSpecModel>> buildFeaturesMap(
+ protected Map<String, Map<Object, AtomSpecModel>> buildFeaturesMap(
StructureSelectionManager ssm, String[] files, SequenceI[][] seqs,
AlignmentViewPanel viewPanel)
{
AlignmentI alignment = viewPanel.getAlignment();
for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
{
+ final int modelNumber = pdbfnum + getModelStartNo();
StructureMapping[] mapping = ssm.getMapping(files[pdbfnum]);
if (mapping == null || mapping.length < 1)
if (!visibleFeatures.isEmpty())
{
scanSequenceFeatures(visibleFeatures, structureMapping, seq,
- theMap, pdbfnum);
+ theMap, modelNumber);
}
if (showLinkedFeatures)
{
scanComplementFeatures(complementRenderer, structureMapping,
- seq, theMap, pdbfnum);
+ seq, theMap, modelNumber);
}
}
}
*
* <pre>
* <blockquote> setattr r <featureName> " " #modelnumber:range.chain
- * e.g. setattr r jv:chain <value> #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
+ * e.g. setattr r jv_chain <value> #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
* </blockquote>
* </pre>
*
* @param featureMap
* @return
*/
- protected static List<String> buildSetAttributeCommands(
+ protected String[] setAttributes(
Map<String, Map<Object, AtomSpecModel>> featureMap)
{
List<String> commands = new ArrayList<>();
* 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);
+ AtomSpecModel atomSpecModel = values.get(value);
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());
+ String cmd = setAttribute(attributeName, featureValue,
+ atomSpecModel);
+ commands.add(cmd);
}
}
- return commands;
+ return commands.toArray(new String[commands.size()]);
+ }
+
+ /**
+ * Returns a viewer command to set the given residue attribute value on
+ * residues specified by the AtomSpecModel, for example
+ *
+ * <pre>
+ * setatr res jv_chain 'primary' #1:12-34,48-55.B
+ * </pre>
+ *
+ * @param attributeName
+ * @param attributeValue
+ * @param atomSpecModel
+ * @return
+ */
+ protected String setAttribute(String attributeName,
+ String attributeValue,
+ AtomSpecModel atomSpecModel)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("setattr res ").append(attributeName).append(" '")
+ .append(attributeValue).append("' ");
+ sb.append(getAtomSpec(atomSpecModel, false));
+ return sb.toString();
}
/**
*
* @param featureType
* @return
- *
- * <pre>
- * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/setattr.html
- * </pre>
+ * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/setattr.html
*/
protected static String makeAttributeName(String featureType)
{
return attName;
}
+ @Override
+ public String colourByChain()
+ {
+ return CMD_COLOUR_BY_CHAIN;
+ }
+
+ @Override
+ public String colourByCharge()
+ {
+ return CMD_COLOUR_BY_CHARGE;
+ }
+
+ @Override
+ public String getResidueSpec(String residue)
+ {
+ return "::" + residue;
+ }
+
+ @Override
+ public String setBackgroundColour(Color col)
+ {
+ // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/set.html#bgcolor
+ return "set bgColor " + ColorUtils.toTkCode(col);
+ }
+
+ @Override
+ public String focusView()
+ {
+ // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/focus.html
+ return "focus";
+ }
+
+ @Override
+ public String showChains(List<String> 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;
+ }
+
+ @Override
+ public String superposeStructures(AtomSpecModel spec, AtomSpecModel ref)
+ {
+ /*
+ * Form Chimera match command to match spec to ref
+ *
+ * match #1:1-30.B,81-100.B@CA #0:21-40.A,61-90.A@CA
+ *
+ * @see
+ * https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
+ */
+ StringBuilder cmd = new StringBuilder();
+ String atomSpec = getAtomSpec(spec, true);
+ String refSpec = getAtomSpec(ref, true);
+ cmd.append("match ").append(atomSpec).append(" ").append(refSpec);
+
+ /*
+ * show superposed residues as ribbon, others as chain
+ */
+ // fixme this should precede the loop over all alignments/structures
+ cmd.append(";~display all; chain @CA|P");
+ cmd.append("; ribbon ");
+ cmd.append(atomSpec).append("|").append(refSpec).append("; focus");
+
+ return cmd.toString();
+ }
+
+ @Override
+ public String openCommandFile(String path)
+ {
+ // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/filetypes.html
+ return "open cmd:" + path;
+ }
+
+ @Override
+ public String saveSession(String filepath)
+ {
+ // https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/save.html
+ return "save " + filepath;
+ }
+
+ /**
+ * Returns the range(s) modelled by {@code atomSpec} formatted as a Chimera
+ * atomspec string, e.g.
+ *
+ * <pre>
+ * #0:15.A,28.A,54.A,70-72.A|#1:2.A,6.A,11.A,13-14.A
+ * </pre>
+ *
+ * where
+ * <ul>
+ * <li>#0 is a model number</li>
+ * <li>15 or 70-72 is a residue number, or range of residue numbers</li>
+ * <li>.A is a chain identifier</li>
+ * <li>residue ranges are separated by comma</li>
+ * <li>atomspecs for distinct models are separated by | (or)</li>
+ * </ul>
+ *
+ * <pre>
+ *
+ * @param model
+ * @param alphaOnly
+ * @return
+ * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
+ */
+ @Override
+ public String getAtomSpec(AtomSpecModel atomSpec, boolean alphaOnly)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModel = true;
+ for (Integer model : atomSpec.getModels())
+ {
+ if (!firstModel)
+ {
+ sb.append("|");
+ }
+ firstModel = false;
+ appendModel(sb, model, atomSpec, alphaOnly);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * A helper method to append an atomSpec string for atoms in the given model
+ *
+ * @param sb
+ * @param model
+ * @param atomSpec
+ * @param alphaOnly
+ */
+ protected void appendModel(StringBuilder sb, Integer model,
+ AtomSpecModel atomSpec, boolean alphaOnly)
+ {
+ sb.append("#").append(model).append(":");
+
+ boolean firstPositionForModel = true;
+
+ for (String chain : atomSpec.getChains(model))
+ {
+ chain = " ".equals(chain) ? chain : chain.trim();
+
+ List<int[]> rangeList = atomSpec.getRanges(model, chain);
+
+ /*
+ * sort ranges into ascending start position order
+ */
+ Collections.sort(rangeList, IntRangeComparator.ASCENDING);
+
+ int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+ int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+
+ Iterator<int[]> iterator = rangeList.iterator();
+ while (iterator.hasNext())
+ {
+ int[] range = iterator.next();
+ if (range[0] <= end + 1)
+ {
+ /*
+ * range overlaps or is contiguous with the last one
+ * - so just extend the end position, and carry on
+ * (unless this is the last in the list)
+ */
+ end = Math.max(end, range[1]);
+ }
+ else
+ {
+ /*
+ * we have a break so append the last range
+ */
+ appendRange(sb, start, end, chain, firstPositionForModel, false);
+ firstPositionForModel = false;
+ start = range[0];
+ end = range[1];
+ }
+ }
+
+ /*
+ * and append the last range
+ */
+ if (!rangeList.isEmpty())
+ {
+ appendRange(sb, start, end, chain, firstPositionForModel, false);
+ firstPositionForModel = false;
+ }
+ }
+ if (alphaOnly)
+ {
+ /*
+ * restrict to alpha carbon, no alternative locations
+ * (needed to ensuring matching atom counts for superposition)
+ */
+ sb.append("@CA|P").append(NO_ALTLOCS);
+ }
+ }
+
+ @Override
+ public String showBackbone()
+ {
+ return "~display all;chain @CA|P";
+ }
+
}
{
// dumpRequest(request);
String message = request.getParameter(CHIMERA_NOTIFICATION);
- if (SELECTION_CHANGED.equals(message))
+ if (message == null)
{
- this.chimeraBinding.highlightChimeraSelection();
+ message = request.getParameter("chimerax_notification");
}
- else if (message != null && message.startsWith(MODEL_CHANGED))
+ if (message != null)
{
- processModelChanged(message.substring(MODEL_CHANGED.length()));
- }
- else
- {
- System.err.println("Unexpected chimeraNotification: " + message);
+ if (message.startsWith("SelectionChanged"))
+ {
+ this.chimeraBinding.highlightChimeraSelection();
+ }
+ else if (message.startsWith(MODEL_CHANGED))
+ {
+ System.err.println(message);
+ processModelChanged(message.substring(MODEL_CHANGED.length()));
+ }
+ else
+ {
+ System.err.println("Unexpected chimeraNotification: " + message);
+ }
}
}
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ext.rbvi.chimera;
+
+import jalview.structure.AtomSpecModel;
+import jalview.util.ColorUtils;
+import jalview.util.IntRangeComparator;
+
+import java.awt.Color;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Routines for generating ChimeraX commands for Jalview/ChimeraX binding
+ */
+public class ChimeraXCommands extends ChimeraCommands
+{
+ private static final String CMD_COLOUR_BY_CHARGE = "color white;color :ASP,GLU red;color :LYS,ARG blue;color :CYS yellow";
+
+ @Override
+ public String colourByCharge()
+ {
+ return CMD_COLOUR_BY_CHARGE;
+ }
+
+ @Override
+ public String getResidueSpec(String residue)
+ {
+ return ":" + residue;
+ }
+
+ @Override
+ public String setBackgroundColour(Color col)
+ {
+ // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/set.html
+ return "set bgColor " + ColorUtils.toTkCode(col);
+ }
+
+ @Override
+ public String getColourCommand(String atomSpec, Color colour)
+ {
+ // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/color.html
+ String colourCode = getColourString(colour);
+
+ return "color " + atomSpec + " " + colourCode;
+ }
+
+ @Override
+ public String focusView()
+ {
+ // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/view.html
+ return "view";
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return
+ */
+ @Override
+ public int getModelStartNo()
+ {
+ return 1;
+ }
+
+ /**
+ * Returns a viewer command to set the given residue attribute value on
+ * residues specified by the AtomSpecModel, for example
+ *
+ * <pre>
+ * setattr #0/A:3-9,14-20,39-43 res jv_strand 'strand' create true
+ * </pre>
+ *
+ * @param attributeName
+ * @param attributeValue
+ * @param atomSpecModel
+ * @return
+ */
+ @Override
+ protected String setAttribute(String attributeName,
+ String attributeValue, AtomSpecModel atomSpecModel)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ sb.append("setattr ").append(getAtomSpec(atomSpecModel, false));
+ sb.append(" res ").append(attributeName).append(" '")
+ .append(attributeValue).append("'");
+ sb.append(" create true");
+ return sb.toString();
+ }
+
+ @Override
+ public String openCommandFile(String path)
+ {
+ // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/open.html
+ return "open " + path;
+ }
+
+ @Override
+ public String saveSession(String filepath)
+ {
+ // https://www.cgl.ucsf.edu/chimerax/docs/user/commands/save.html
+ return "save session " + filepath;
+ }
+
+ /**
+ * Returns the range(s) formatted as a ChimeraX atomspec, for example
+ * <p>
+ * #1/A:2-20,30-40/B:10-20|#2/A:12-30
+ *
+ * @return
+ */
+ @Override
+ public String getAtomSpec(AtomSpecModel atomSpec, boolean alphaOnly)
+ {
+ StringBuilder sb = new StringBuilder(128);
+ boolean firstModel = true;
+ for (Integer model : atomSpec.getModels())
+ {
+ if (!firstModel)
+ {
+ sb.append("|");
+ }
+ firstModel = false;
+ appendModel(sb, model, atomSpec);
+ if (alphaOnly)
+ {
+ sb.append("@CA|P");
+ }
+ // todo: is there ChimeraX syntax to exclude altlocs?
+ }
+ return sb.toString();
+ }
+
+ /**
+ * A helper method to append an atomSpec string for atoms in the given model
+ *
+ * @param sb
+ * @param model
+ * @param atomSpec
+ */
+ protected void appendModel(StringBuilder sb, Integer model,
+ AtomSpecModel atomSpec)
+ {
+ sb.append("#").append(model);
+
+ for (String chain : atomSpec.getChains(model))
+ {
+ boolean firstPositionForChain = true;
+ sb.append("/").append(chain.trim()).append(":");
+ List<int[]> rangeList = atomSpec.getRanges(model, chain);
+
+ /*
+ * sort ranges into ascending start position order
+ */
+ Collections.sort(rangeList, IntRangeComparator.ASCENDING);
+
+ int start = rangeList.isEmpty() ? 0 : rangeList.get(0)[0];
+ int end = rangeList.isEmpty() ? 0 : rangeList.get(0)[1];
+
+ Iterator<int[]> iterator = rangeList.iterator();
+ while (iterator.hasNext())
+ {
+ int[] range = iterator.next();
+ if (range[0] <= end + 1)
+ {
+ /*
+ * range overlaps or is contiguous with the last one
+ * - so just extend the end position, and carry on
+ * (unless this is the last in the list)
+ */
+ end = Math.max(end, range[1]);
+ }
+ else
+ {
+ /*
+ * we have a break so append the last range
+ */
+ appendRange(sb, start, end, chain, firstPositionForChain, true);
+ start = range[0];
+ end = range[1];
+ firstPositionForChain = false;
+ }
+ }
+
+ /*
+ * and append the last range
+ */
+ if (!rangeList.isEmpty())
+ {
+ appendRange(sb, start, end, chain, firstPositionForChain, true);
+ }
+ firstPositionForChain = false;
+ }
+ }
+
+ @Override
+ public String showBackbone()
+ {
+ return "~display all;show @CA|P pbonds";
+ }
+
+ @Override
+ public String superposeStructures(AtomSpecModel spec, AtomSpecModel ref)
+ {
+ /*
+ * Form ChimeraX match command to match spec to ref
+ *
+ * match #1/A:2-94 toAtoms #2/A:1-93
+ *
+ * @see
+ * https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
+ */
+ StringBuilder cmd = new StringBuilder();
+ String atomSpec = getAtomSpec(spec, true);
+ String refSpec = getAtomSpec(ref, true);
+ cmd.append("align ").append(atomSpec).append(" toAtoms ")
+ .append(refSpec);
+
+ /*
+ * show superposed residues as ribbon, others as chain
+ */
+ cmd.append("; ribbon ");
+ cmd.append(getAtomSpec(spec, false)).append("|");
+ cmd.append(getAtomSpec(ref, false)).append("; view");
+
+ return cmd.toString();
+ }
+
+}
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;
import jalview.datamodel.SearchResultsI;
import jalview.datamodel.SequenceFeature;
import jalview.datamodel.SequenceI;
+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.StructureCommandsI.SuperposeData;
import jalview.structure.StructureSelectionManager;
import jalview.structures.models.AAStructureBindingModel;
import jalview.util.MessageManager;
-import java.awt.Color;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
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;
import java.util.Map;
// 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<String> chainNames = new ArrayList<String>();
-
- private Hashtable<String, String> chainFile = new Hashtable<String, String>();
-
/*
* Object through which we talk to Chimera
*/
- private ChimeraManager viewer;
+ private ChimeraManager chimeraManager;
/*
* Object which listens to Chimera notifications
private AbstractRequestHandler chimeraListener;
/*
- * set if chimera state is being restored from some source - instructs binding
- * not to apply default display style when structure set is updated for first
- * time.
- */
- private boolean loadingFromArchive = false;
-
- /*
- * flag to indicate if the Chimera viewer should ignore sequence colouring
- * events from the structure manager because the GUI is still setting up
- */
- private boolean loadingFinished = true;
-
- /*
* Map of ChimeraModel objects keyed by PDB full local file name
*/
- private Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<String, List<ChimeraModel>>();
+ protected Map<String, List<ChimeraModel>> chimeraMaps = new LinkedHashMap<>();
String lastHighlightCommand;
- /*
- * incremented every time a load notification is successfully handled -
- * lightweight mechanism for other threads to detect when they can start
- * referring to new structures.
- */
- private long loadNotifiesHandled = 0;
-
private Thread chimeraMonitor;
/**
* Open a PDB structure file in Chimera and set up mappings from Jalview.
*
- * We check if the PDB model id is already loaded in Chimera, if so don't
- * reopen it. This is the case if Chimera has opened a saved session file.
+ * We check if the PDB model id is already loaded in Chimera, if so don't reopen
+ * it. This is the case if Chimera has opened a saved session file.
*
* @param pe
* @return
String file = pe.getFile();
try
{
- List<ChimeraModel> modelsToMap = new ArrayList<ChimeraModel>();
- List<ChimeraModel> oldList = viewer.getModelList();
+ List<ChimeraModel> modelsToMap = new ArrayList<>();
+ List<ChimeraModel> oldList = chimeraManager.getModelList();
boolean alreadyOpen = false;
/*
*/
if (!alreadyOpen)
{
- viewer.openModel(file, pe.getId(), ModelType.PDB_MODEL);
- List<ChimeraModel> newList = viewer.getModelList();
- // JAL-1728 newList.removeAll(oldList) does not work
- for (ChimeraModel cm : newList)
- {
- if (cm.getModelName().equals(pe.getId()))
- {
- modelsToMap.add(cm);
- }
- }
+ chimeraManager.openModel(file, pe.getId(), ModelType.PDB_MODEL);
+ addChimeraModel(pe, modelsToMap);
}
chimeraMaps.put(file, modelsToMap);
}
/**
+ * Adds the ChimeraModel corresponding to the given PDBEntry, based on model
+ * name matching PDB id
+ *
+ * @param pe
+ * @param modelsToMap
+ */
+ protected void addChimeraModel(PDBEntry pe,
+ List<ChimeraModel> modelsToMap)
+ {
+ /*
+ * Chimera: query for actual models and find the one with
+ * matching model name - already set in viewer.openModel()
+ */
+ List<ChimeraModel> newList = chimeraManager.getModelList();
+ // JAL-1728 newList.removeAll(oldList) does not work
+ for (ChimeraModel cm : newList)
+ {
+ if (cm.getModelName().equals(pe.getId()))
+ {
+ modelsToMap.add(cm);
+ }
+ }
+ }
+
+ /**
* Constructor
*
* @param ssm
DataSourceType protocol)
{
super(ssm, pdbentry, sequenceIs, protocol);
- viewer = new ChimeraManager(new StructureManager(true));
+ chimeraManager = new ChimeraManager(new StructureManager(true));
+ chimeraManager.setChimeraX(ViewerType.CHIMERAX.equals(getViewerType()));
+ setStructureCommands(new ChimeraCommands());
+ }
+
+ @Override
+ protected ViewerType getViewerType()
+ {
+ return ViewerType.CHIMERA;
}
/**
- * Starts a thread that waits for the Chimera process to finish, so that we
- * can then close the associated resources. This avoids leaving orphaned
- * Chimera viewer panels in Jalview if the user closes Chimera.
+ * Starts a thread that waits for the Chimera process to finish, so that we can
+ * then close the associated resources. This avoids leaving orphaned Chimera
+ * viewer panels in Jalview if the user closes Chimera.
*/
protected void startChimeraProcessMonitor()
{
- final Process p = viewer.getChimeraProcess();
+ final Process p = chimeraManager.getChimeraProcess();
chimeraMonitor = new Thread(new Runnable()
{
}
/**
- * Start a dedicated HttpServer to listen for Chimera notifications, and tell
- * it to start listening
+ * Start a dedicated HttpServer to listen for Chimera notifications, and tell it
+ * to start listening
*/
public void startChimeraListener()
{
try
{
chimeraListener = new ChimeraListener(this);
- viewer.startListening(chimeraListener.getUri());
+ chimeraManager.startListening(chimeraListener.getUri());
} catch (BindException e)
{
System.err.println(
}
/**
- * Tells Chimera to display only the specified chains
- *
- * @param toshow
- */
- public void showChains(List<String> 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.
*/
getSsm().removeStructureViewerListener(this, this.getStructureFiles());
if (closeChimera)
{
- viewer.exitChimera();
+ chimeraManager.exitChimera();
}
if (this.chimeraListener != null)
{
chimeraListener.shutdown();
chimeraListener = null;
}
- viewer = null;
+ chimeraManager = null;
if (chimeraMonitor != null)
{
releaseUIResources();
}
- @Override
- public void colourByChain()
- {
- colourBySequence = false;
- sendAsynchronousCommand("rainbow chain", COLOURING_CHIMERA);
- }
-
- /**
- * Constructs and sends a Chimera command to colour by charge
- * <ul>
- * <li>Aspartic acid and Glutamic acid (negative charge) red</li>
- * <li>Lysine and Arginine (positive charge) blue</li>
- * <li>Cysteine - yellow</li>
- * <li>all others - white</li>
- * </ul>
- */
- @Override
- public void colourByCharge()
- {
- colourBySequence = false;
- String command = "color white;color red ::ASP;color red ::GLU;color blue ::LYS;color blue ::ARG;color yellow ::CYS";
- sendAsynchronousCommand(command, COLOURING_CHIMERA);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String superposeStructures(AlignmentI[] _alignment,
- int[] _refStructure, HiddenColumns[] _hiddenCols)
- {
- StringBuilder allComs = new StringBuilder(128);
- String[] files = getStructureFiles();
-
- if (!waitForFileLoad(files))
- {
- return null;
- }
-
- refreshPdbEntries();
- StringBuilder selectioncom = new StringBuilder(256);
- for (int a = 0; a < _alignment.length; a++)
- {
- int refStructure = _refStructure[a];
- AlignmentI alignment = _alignment[a];
- HiddenColumns hiddenCols = _hiddenCols[a];
-
- if (refStructure >= files.length)
- {
- System.err.println("Ignoring invalid reference structure value "
- + refStructure);
- refStructure = -1;
- }
-
- /*
- * 'matched' bit i will be set for visible alignment columns i where
- * all sequences have a residue with a mapping to the PDB structure
- */
- BitSet matched = new BitSet();
- for (int m = 0; m < alignment.getWidth(); m++)
- {
- if (hiddenCols == null || hiddenCols.isVisible(m))
- {
- matched.set(m);
- }
- }
-
- SuperposeData[] structures = new SuperposeData[files.length];
- for (int f = 0; f < files.length; f++)
- {
- structures[f] = new SuperposeData(alignment.getWidth());
- }
-
- /*
- * Calculate the superposable alignment columns ('matched'), and the
- * corresponding structure residue positions (structures.pdbResNo)
- */
- int candidateRefStructure = findSuperposableResidues(alignment,
- matched, structures);
- if (refStructure < 0)
- {
- /*
- * If no reference structure was specified, pick the first one that has
- * a mapping in the alignment
- */
- refStructure = candidateRefStructure;
- }
-
- int nmatched = matched.cardinality();
- if (nmatched < 4)
- {
- return MessageManager.formatMessage("label.insufficient_residues",
- nmatched);
- }
-
- /*
- * Generate select statements to select regions to superimpose structures
- */
- String[] selcom = new String[files.length];
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
- {
- String chainCd = "." + structures[pdbfnum].chain;
- int lpos = -1;
- boolean run = false;
- StringBuilder molsel = new StringBuilder();
-
- int nextColumnMatch = matched.nextSetBit(0);
- while (nextColumnMatch != -1)
- {
- int pdbResNum = structures[pdbfnum].pdbResNo[nextColumnMatch];
- if (lpos != pdbResNum - 1)
- {
- /*
- * discontiguous - append last residue now
- */
- if (lpos != -1)
- {
- molsel.append(String.valueOf(lpos));
- molsel.append(chainCd);
- molsel.append(",");
- }
- run = false;
- }
- else
- {
- /*
- * extending a contiguous run
- */
- if (!run)
- {
- /*
- * start the range selection
- */
- molsel.append(String.valueOf(lpos));
- molsel.append("-");
- }
- run = true;
- }
- lpos = pdbResNum;
- nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
- }
-
- /*
- * and terminate final selection
- */
- if (lpos != -1)
- {
- molsel.append(String.valueOf(lpos));
- molsel.append(chainCd);
- }
- if (molsel.length() > 1)
- {
- selcom[pdbfnum] = molsel.toString();
- selectioncom.append("#").append(String.valueOf(pdbfnum))
- .append(":");
- selectioncom.append(selcom[pdbfnum]);
- selectioncom.append(" ");
- if (pdbfnum < files.length - 1)
- {
- selectioncom.append("| ");
- }
- }
- else
- {
- selcom[pdbfnum] = null;
- }
- }
-
- StringBuilder command = new StringBuilder(256);
- for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
- {
- if (pdbfnum == refStructure || selcom[pdbfnum] == null
- || selcom[refStructure] == null)
- {
- continue;
- }
- if (command.length() > 0)
- {
- command.append(";");
- }
-
- /*
- * Form Chimera match command, from the 'new' structure to the
- * 'reference' structure e.g. (50 residues, chain B/A, alphacarbons):
- *
- * match #1:1-30.B,81-100.B@CA #0:21-40.A,61-90.A@CA
- *
- * @see
- * https://www.cgl.ucsf.edu/chimera/docs/UsersGuide/midas/match.html
- */
- command.append("match ").append(getModelSpec(pdbfnum)).append(":");
- command.append(selcom[pdbfnum]);
- command.append("@").append(
- structures[pdbfnum].isRna ? PHOSPHORUS : ALPHACARBON);
- // JAL-1757 exclude alternate CA locations
- command.append(NO_ALTLOCS);
- command.append(" ").append(getModelSpec(refStructure)).append(":");
- command.append(selcom[refStructure]);
- command.append("@").append(
- structures[refStructure].isRna ? PHOSPHORUS : ALPHACARBON);
- command.append(NO_ALTLOCS);
- }
- if (selectioncom.length() > 0)
- {
- if (debug)
- {
- System.out.println("Select regions:\n" + selectioncom.toString());
- System.out.println(
- "Superimpose command(s):\n" + command.toString());
- }
- allComs.append("~display all; chain @CA|P; ribbon ")
- .append(selectioncom.toString())
- .append(";" + command.toString());
- }
- }
-
- String error = null;
- if (selectioncom.length() > 0)
- {
- // TODO: visually distinguish regions that were superposed
- if (selectioncom.substring(selectioncom.length() - 1).equals("|"))
- {
- selectioncom.setLength(selectioncom.length() - 1);
- }
- if (debug)
- {
- System.out.println("Select regions:\n" + selectioncom.toString());
- }
- allComs.append("; ~display all; chain @CA|P; ribbon ")
- .append(selectioncom.toString()).append("; focus");
- List<String> chimeraReplies = sendChimeraCommand(allComs.toString(),
- true);
- for (String reply : chimeraReplies)
- {
- if (reply.toLowerCase().contains("unequal numbers of atoms"))
- {
- error = reply;
- }
- }
- }
- return error;
- }
-
/**
* Helper method to construct model spec in Chimera format:
* <ul>
{
if (pdbfnum < 0 || pdbfnum >= getPdbCount())
{
- return "";
+ return "#" + pdbfnum; // temp hack for ChimeraX
}
/*
*/
public boolean launchChimera()
{
- if (viewer.isChimeraLaunched())
+ if (chimeraManager.isChimeraLaunched())
{
return true;
}
- boolean launched = viewer
- .launchChimera(StructureManager.getChimeraPaths());
+ boolean launched = chimeraManager.launchChimera(getChimeraPaths());
if (launched)
{
startChimeraProcessMonitor();
}
/**
+ * Returns a list of candidate paths to the Chimera program executable
+ *
+ * @return
+ */
+ protected List<String> getChimeraPaths()
+ {
+ return StructureManager.getChimeraPaths(false);
+ }
+
+ /**
* Answers true if the Chimera process is still running, false if ended or not
* started.
*
*/
public boolean isChimeraRunning()
{
- return viewer.isChimeraLaunched();
+ return chimeraManager.isChimeraLaunched();
}
/**
* Send a command to Chimera, and optionally log and return any responses.
- * <p>
- * Does nothing, and returns null, if the command is the same as the last one
- * sent [why?].
*
* @param command
* @param getResponse
*/
- public List<String> sendChimeraCommand(final String command,
+ @Override
+ public List<String> executeCommand(final String command,
boolean getResponse)
{
- if (viewer == null)
+ if (chimeraManager == null || command == null)
{
// ? thread running after viewer shut down
return null;
}
List<String> reply = null;
- viewerCommandHistory(false);
- if (true /*lastCommand == null || !lastCommand.equals(command)*/)
+ // trim command or it may never find a match in the replyLog!!
+ List<String> lastReply = chimeraManager
+ .sendChimeraCommand(command.trim(), getResponse);
+ if (getResponse)
{
- // trim command or it may never find a match in the replyLog!!
- List<String> lastReply = viewer.sendChimeraCommand(command.trim(),
- getResponse);
- if (getResponse)
+ reply = lastReply;
+ if (debug)
{
- reply = lastReply;
- if (debug)
- {
- log("Response from command ('" + command + "') was:\n"
- + lastReply);
- }
+ log("Response from command ('" + command + "') was:\n" + lastReply);
}
}
- viewerCommandHistory(true);
return reply;
}
/**
- * Send a Chimera command asynchronously in a new thread. If the progress
- * message is not null, display this message while the command is executing.
- *
- * @param command
- * @param progressMsg
- */
- protected abstract void sendAsynchronousCommand(String command,
- 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);
- }
-
- /**
* @param command
*/
protected void executeWhenReady(String command)
{
waitForChimera();
- sendChimeraCommand(command, false);
+ executeCommand(command, false);
waitForChimera();
}
private void waitForChimera()
{
- while (viewer != null && viewer.isBusy())
+ while (chimeraManager != null && chimeraManager.isBusy())
{
try
{
}
}
- // End StructureListener
- // //////////////////////////
-
- /**
- * instruct the Jalview binding to update the pdbentries vector if necessary
- * prior to matching the viewer's contents to the list of structure files
- * Jalview knows about.
- */
- public abstract void refreshPdbEntries();
-
- /**
- * 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 -
- * use getPdbFile to get number of unique models.
- */
- private int _modelFileNameMap[];
-
- // ////////////////////////////////
- // /StructureListener
@Override
public synchronized String[] getStructureFiles()
{
- if (viewer == null)
+ if (chimeraManager == null)
{
return new String[0];
}
}
/**
- * Construct and send a command to highlight zero, one or more atoms. We do
- * this by sending an "rlabel" command to show the residue label at that
- * position.
+ * Construct and send a command to highlight zero, one or more atoms. We do this
+ * by sending an "rlabel" command to show the residue label at that position.
*/
@Override
public void highlightAtoms(List<AtomSpec> atoms)
return;
}
+ boolean forChimeraX = chimeraManager.isChimeraX();
StringBuilder cmd = new StringBuilder(128);
boolean first = true;
boolean found = false;
{
if (first)
{
- cmd.append("rlabel #").append(cms.get(0).getModelNumber())
- .append(":");
+ cmd.append(forChimeraX ? "label #" : "rlabel #");
}
else
{
cmd.append(",");
}
first = false;
- cmd.append(pdbResNum);
- if (!chain.equals(" "))
+ if (forChimeraX)
{
- cmd.append(".").append(chain);
+ cmd.append(cms.get(0).getModelNumber())
+ .append("/").append(chain).append(":").append(pdbResNum);
+ }
+ else
+ {
+ cmd.append(cms.get(0).getModelNumber())
+ .append(":").append(pdbResNum);
+ if (!chain.equals(" ") && !forChimeraX)
+ {
+ cmd.append(".").append(chain);
+ }
}
found = true;
}
*/
if (lastHighlightCommand != null)
{
- viewer.sendChimeraCommand("~" + lastHighlightCommand, false);
+ chimeraManager.sendChimeraCommand("~" + lastHighlightCommand, false);
}
if (found)
{
- viewer.sendChimeraCommand(command, false);
+ chimeraManager.sendChimeraCommand(command, false);
}
this.lastHighlightCommand = command;
}
/*
* Ask Chimera for its current selection
*/
- List<String> selection = viewer.getSelectedResidueSpecs();
+ List<String> selection = chimeraManager.getSelectedResidueSpecs();
/*
* Parse model number, residue and chain for each selected position,
protected List<AtomSpec> convertStructureResiduesToAlignment(
List<String> structureSelection)
{
- List<AtomSpec> atomSpecs = new ArrayList<AtomSpec>();
+ boolean chimeraX = chimeraManager.isChimeraX();
+ List<AtomSpec> atomSpecs = new ArrayList<>();
for (String atomSpec : structureSelection)
{
try
{
- AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ AtomSpec spec = AtomSpec.fromChimeraAtomspec(atomSpec, chimeraX);
String pdbfilename = getPdbFileForModel(spec.getModelNumber());
spec.setPdbFile(pdbfilename);
atomSpecs.add(spec);
System.err.println("## Chimera log: " + message);
}
- private void viewerCommandHistory(boolean enable)
- {
- // log("(Not yet implemented) History "
- // + ((debug || enable) ? "on" : "off"));
- }
-
- public long getLoadNotifiesHandled()
- {
- return loadNotifiesHandled;
- }
-
- @Override
- public void setJalviewColourScheme(ColourSchemeI cs)
- {
- colourBySequence = false;
-
- if (cs == null)
- {
- return;
- }
-
- // Chimera expects RBG values in the range 0-1
- final double normalise = 255D;
- viewerCommandHistory(false);
- StringBuilder command = new StringBuilder(128);
-
- List<String> 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("color " + col.getRed() / normalise + ","
- + col.getGreen() / normalise + "," + col.getBlue() / normalise
- + " ::" + resName + ";");
- }
-
- 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
- * error has occurred.
- */
- public abstract void refreshGUI();
-
- @Override
- public void setLoadingFromArchive(boolean loadingFromArchive)
- {
- this.loadingFromArchive = loadingFromArchive;
- }
-
- /**
- *
- * @return true if Chimeral is still restoring state or loading is still going
- * on (see setFinsihedLoadingFromArchive)
- */
- @Override
- public boolean isLoadingFromArchive()
- {
- return loadingFromArchive && !loadingFinished;
- }
-
- /**
- * modify flag which controls if sequence colouring events are honoured by the
- * binding. Should be true for normal operation
- *
- * @param finishedLoading
- */
- @Override
- public void setFinishedLoadingFromArchive(boolean finishedLoading)
- {
- loadingFinished = finishedLoading;
- }
-
- /**
- * Send the Chimera 'background solid <color>" command.
- *
- * @see https
- * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/background
- * .html
- * @param col
- */
- @Override
- public void setBackgroundColour(Color col)
- {
- viewerCommandHistory(false);
- double normalise = 255D;
- final String command = "background solid " + col.getRed() / normalise
- + "," + col.getGreen() / normalise + ","
- + col.getBlue() / normalise + ";";
- viewer.sendChimeraCommand(command, false);
- viewerCommandHistory(true);
- }
-
/**
* Ask Chimera to save its session to the given file. Returns true if
* successful, else false.
{
if (isChimeraRunning())
{
- List<String> reply = viewer.sendChimeraCommand("save " + filepath,
- true);
+ /*
+ * Chimera: https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/save.html
+ * ChimeraX: https://www.cgl.ucsf.edu/chimerax/docs/user/commands/save.html
+ */
+ String command = getCommandGenerator().saveSession(filepath);
+ List<String> reply = chimeraManager.sendChimeraCommand(command, true);
if (reply.contains("Session written"))
{
return true;
/**
* Ask Chimera to open a session file. Returns true if successful, else false.
- * The filename must have a .py extension for this command to work.
+ * The filename must have a .py (Chimera) or .cxs (ChimeraX) extension for
+ * this command to work.
*
* @param filepath
* @return
*/
public boolean openSession(String filepath)
{
- sendChimeraCommand("open " + filepath, true);
+ /*
+ * 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
+ */
+ 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<String> getChainNames()
- {
- return chainNames;
- }
-
- /**
- * Send a 'focus' command to Chimera to recentre the visible display
- */
- public void focusView()
- {
- sendChimeraCommand("focus", false);
- }
-
- /**
* Send a 'show' command for all atoms in the currently selected columns
*
* TODO: pull up to abstract structure viewer interface
public int sendFeaturesToViewer(AlignmentViewPanel avp)
{
// TODO refactor as required to pull up to an interface
- AlignmentI alignment = avp.getAlignment();
-
String[] files = getStructureFiles();
if (files == null)
{
return 0;
}
- StructureMappingcommandSet commandSet = ChimeraCommands
- .getSetAttributeCommandsForFeatures(getSsm(), files,
- getSequence(), avp);
- String[] commands = commandSet.commands;
+ String[] commands = getCommandGenerator()
+ .setAttributesForFeatures(getSsm(), files, getSequence(), avp);
if (commands.length > 10)
{
sendCommandsByFile(commands);
}
/**
- * Write commands to a temporary file, and send a command to Chimera to open
- * the file as a commands script. For use when sending a large number of
- * separate commands would overload the REST interface mechanism.
+ * Write commands to a temporary file, and send a command to Chimera to open the
+ * file as a commands script. For use when sending a large number of separate
+ * commands would overload the REST interface mechanism.
*
* @param commands
*/
{
try
{
- File tmp = File.createTempFile("chim", ".com");
+ File tmp = File.createTempFile("chim", getCommandFileExtension());
tmp.deleteOnExit();
PrintWriter out = new PrintWriter(new FileOutputStream(tmp));
for (String command : commands)
out.flush();
out.close();
String path = tmp.getAbsolutePath();
- sendAsynchronousCommand("open cmd:" + path, null);
+ String command = getCommandGenerator().openCommandFile(path);
+ sendAsynchronousCommand(command, null);
} catch (IOException e)
{
System.err.println("Sending commands to Chimera via file failed with "
}
/**
+ * Returns the file extension required for a file of commands to be read by
+ * the structure viewer
+ * @return
+ */
+ protected String getCommandFileExtension()
+ {
+ return ".com";
+ }
+
+ /**
* Get Chimera residues which have the named attribute, find the mapped
* positions in the Jalview sequence(s), and set as sequence features
*
// fails for 'average.bfactor' (which is bad):
String cmd = "list residues attr '" + attName + "'";
- List<String> residues = sendChimeraCommand(cmd, true);
+ List<String> residues = executeCommand(cmd, true);
boolean featureAdded = createFeaturesForAttributes(attName, residues);
if (featureAdded)
{
boolean featureAdded = false;
String featureGroup = getViewerFeatureGroup();
+ boolean chimeraX = chimeraManager.isChimeraX();
for (String residue : residues)
{
try
{
- spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ spec = AtomSpec.fromChimeraAtomspec(atomSpec, chimeraX);
} catch (IllegalArgumentException e)
{
System.err.println("Problem parsing atomspec " + atomSpec);
return CHIMERA_FEATURE_GROUP;
}
- public Hashtable<String, String> getChainFile()
+ @Override
+ public int getModelNoForFile(String pdbFile)
+ {
+ List<ChimeraModel> foundModels = chimeraMaps.get(pdbFile);
+ if (foundModels != null && !foundModels.isEmpty())
+ {
+ return foundModels.get(0).getModelNumber();
+ }
+ return -1;
+ }
+
+ /**
+ * Answers a (possibly empty) list of attribute names in Chimera[X], excluding
+ * any which were added from Jalview
+ *
+ * @return
+ */
+ public List<String> getChimeraAttributes()
{
- return chainFile;
+ List<String> atts = chimeraManager.getAttrList();
+ Iterator<String> it = atts.iterator();
+ while (it.hasNext())
+ {
+ if (it.next().startsWith(ChimeraCommands.NAMESPACE_PREFIX))
+ {
+ /*
+ * attribute added from Jalview - exclude it
+ */
+ it.remove();
+ }
+ }
+ return atts;
}
- public List<ChimeraModel> getChimeraModelByChain(String chain)
+ /**
+ * Returns the file extension to use for a saved viewer session file
+ *
+ * @return
+ */
+ public String getSessionFileExtension()
{
- return chimeraMaps.get(chainFile.get(chain));
+ return ".py";
}
- public int getModelNoForChain(String chain)
+ public String getHelpURL()
{
- List<ChimeraModel> foundModels = getChimeraModelByChain(chain);
- if (foundModels != null && !foundModels.isEmpty())
- {
- return foundModels.get(0).getModelNumber();
- }
- return -1;
+ return "https://www.cgl.ucsf.edu/chimera/docs/UsersGuide";
}
}
addKeyListener();
- final List<AlignmentPanel> selviews = new ArrayList<>();
+ final List<AlignmentViewPanel> selviews = new ArrayList<>();
final List<AlignmentPanel> origview = new ArrayList<>();
final String menuLabel = MessageManager
.getString("label.copy_format_from");
*/
package jalview.gui;
+import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.PDBEntry;
import jalview.gui.StructureViewer.ViewerType;
import jalview.structures.models.AAStructureBindingModel;
import jalview.util.BrowserLauncher;
+import jalview.util.ImageMaker;
import jalview.util.MessageManager;
import jalview.util.Platform;
import jalview.ws.dbsources.Pdb;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
-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;
.getString("label.let_jmol_manage_structure_colours"));
}
- IProgressIndicator progressBar = null;
-
- @Override
- protected IProgressIndicator getIProgressIndicator()
- {
- return progressBar;
- }
-
/**
* display a single PDB structure in a new Jmol view
*
public AppJmol(PDBEntry pdbentry, SequenceI[] seq, String[] chains,
final AlignmentPanel ap)
{
- progressBar = ap.alignFrame;
+ setProgressIndicator(ap.alignFrame);
openNewJmol(ap, alignAddedStructures, new PDBEntry[] { pdbentry },
new SequenceI[][]
PDBEntry[] pdbentrys,
SequenceI[][] seqs)
{
- progressBar = ap.alignFrame;
+ setProgressIndicator(ap.alignFrame);
jmb = new AppJmolBinding(this, ap.getStructureSelectionManager(),
pdbentrys, seqs, null);
addAlignmentPanel(ap);
{
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<String> 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
try
{
- jmb.evalStateCommand(command);
+ jmb.executeCommand(command, false);
} catch (OutOfMemoryError oomerror)
{
new OOMWarning("When trying to add structures to the Jmol viewer!",
}
// refresh the sequence colours for the new structure(s)
- for (AlignmentPanel ap : _colourwith)
+ for (AlignmentViewPanel ap : _colourwith)
{
jmb.updateColours(ap);
}
@Override
public void run()
{
- if (jmb.viewer.isScriptExecuting())
+ if (jmb.jmolViewer.isScriptExecuting())
{
SwingUtilities.invokeLater(this);
try
}
else
{
- alignStructs_withAllAlignPanels();
+ alignStructsWithAllAlignPanels();
}
}
});
AlignmentI pdbseq = null;
pdbid = jmb.getPdbEntry(pi).getId();
long hdl = pdbid.hashCode() - System.currentTimeMillis();
- if (progressBar != null)
- {
- progressBar.setProgressBar(MessageManager
- .formatMessage("status.fetching_pdb", new String[]
- { pdbid }), hdl);
- }
+ setProgressMessage(MessageManager
+ .formatMessage("status.fetching_pdb", new String[]
+ { pdbid }), hdl);
try
{
pdbseq = pdbclient.getSequenceRecords(pdbid);
errormsgs.append("'").append(pdbid).append("'");
} finally
{
- if (progressBar != null)
- {
- progressBar.setProgressBar(
- MessageManager.getString("label.state_completed"),
- hdl);
- }
+ setProgressMessage(
+ MessageManager.getString("label.state_completed"), hdl);
}
if (pdbseq != null)
{
}
@Override
- public void eps_actionPerformed(ActionEvent e)
+ public void eps_actionPerformed()
{
- makePDBImage(jalview.util.ImageMaker.TYPE.EPS);
+ makePDBImage(ImageMaker.TYPE.EPS);
}
@Override
- public void png_actionPerformed(ActionEvent e)
+ public void png_actionPerformed()
{
- makePDBImage(jalview.util.ImageMaker.TYPE.PNG);
+ makePDBImage(ImageMaker.TYPE.PNG);
}
- void makePDBImage(jalview.util.ImageMaker.TYPE type)
+ void makePDBImage(ImageMaker.TYPE type)
{
int width = getWidth();
int height = getHeight();
- jalview.util.ImageMaker im;
+ ImageMaker im;
- if (type == jalview.util.ImageMaker.TYPE.PNG)
+ if (type == ImageMaker.TYPE.PNG)
{
- im = new jalview.util.ImageMaker(this,
- jalview.util.ImageMaker.TYPE.PNG, "Make PNG image from view",
+ im = new ImageMaker(this, ImageMaker.TYPE.PNG,
+ "Make PNG image from view",
width, height, null, null, null, 0, false);
}
- else if (type == jalview.util.ImageMaker.TYPE.EPS)
+ else if (type == ImageMaker.TYPE.EPS)
{
- im = new jalview.util.ImageMaker(this,
- jalview.util.ImageMaker.TYPE.EPS, "Make EPS file from view",
+ im = new ImageMaker(this, ImageMaker.TYPE.EPS,
+ "Make EPS file from view",
width, height, null, this.getTitle(), null, 0, false);
}
else
{
-
im = new jalview.util.ImageMaker(this,
- jalview.util.ImageMaker.TYPE.SVG, "Make SVG file from PCA",
+ ImageMaker.TYPE.SVG, "Make SVG file from PCA",
width, height, null, this.getTitle(), null, 0, false);
}
if (im.getGraphics() != null)
{
- jmb.viewer.renderScreenImage(im.getGraphics(), width, height);
+ jmb.jmolViewer.renderScreenImage(im.getGraphics(), width, height);
im.writeImage();
}
}
@Override
- public void showHelp_actionPerformed(ActionEvent actionEvent)
+ public void showHelp_actionPerformed()
{
try
{
.openURL("http://jmol.sourceforge.net/docs/JmolUserGuide/");
} catch (Exception ex)
{
+ System.err.println("Show Jmol help failed with: " + ex.getMessage());
}
}
+ @Override
public void showConsole(boolean showConsole)
{
-
if (showConsole)
{
if (splitPane == null)
}
}
}
- else if (jmb == null || jmb.viewer == null || !jmb.isFinishedInit())
+ else if (jmb == null || jmb.jmolViewer == null || !jmb.isFinishedInit())
{
g.setColor(Color.black);
g.fillRect(0, 0, currentSize.width, currentSize.height);
}
else
{
- jmb.viewer.renderScreenImage(g, currentSize.width,
+ jmb.jmolViewer.renderScreenImage(g, currentSize.width,
currentSize.height);
}
}
@Override
public String getStateInfo()
{
- return jmb == null ? null : jmb.viewer.getStateInfo();
+ return jmb == null ? null : jmb.jmolViewer.getStateInfo();
}
@Override
import java.awt.Container;
import java.util.Map;
+import javax.swing.JComponent;
+
import org.jmol.api.JmolAppConsoleInterface;
import org.jmol.java.BS;
import org.openscience.jmol.app.jmolpanel.console.AppConsole;
public class AppJmolBinding extends JalviewJmolBinding
{
- private AppJmol appJmolWindow;
-
public AppJmolBinding(AppJmol appJmol, StructureSelectionManager sSm,
PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
DataSourceType protocol)
{
super(sSm, pdbentry, sequenceIs, protocol);
- appJmolWindow = appJmol;
- }
-
- @Override
- protected IProgressIndicator getIProgressIndicator()
- {
- return appJmolWindow.progressBar;
+ setViewer(appJmol);
}
@Override
@Override
public void run()
{
- appJmolWindow.updateTitleAndMenus();
- appJmolWindow.revalidate();
+ JalviewStructureDisplayI theViewer = getViewer();
+ theViewer.updateTitleAndMenus();
+ ((JComponent) theViewer).revalidate();
}
});
}
@Override
- public void updateColours(Object source)
- {
- AlignmentPanel ap = (AlignmentPanel) source;
- // ignore events from panels not used to colour this view
- if (!appJmolWindow.isUsedforcolourby(ap))
- {
- return;
- }
- if (!isLoadingFromArchive())
- {
- colourBySequence(ap);
- }
- }
-
- @Override
public void notifyScriptTermination(String strStatus, int msWalltime)
{
// todo - script termination doesn't happen ?
@Override
public void selectionChanged(BS arg0)
{
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public void refreshPdbEntries()
- {
- // TODO Auto-generated method stub
-
}
@Override
public void showConsole(boolean b)
{
- appJmolWindow.showConsole(b);
+ getViewer().showConsole(b);
}
@Override
protected JmolAppConsoleInterface createJmolConsole(
Container consolePanel, String buttonsToShow)
{
- viewer.setJmolCallbackListener(this);
- return new AppConsole(viewer, consolePanel, buttonsToShow);
+ jmolViewer.setJmolCallbackListener(this);
+ return new AppConsole(jmolViewer, consolePanel, buttonsToShow);
}
@Override
protected void releaseUIResources()
{
- appJmolWindow = null;
+ setViewer(null);
closeConsole();
}
{
if (svl instanceof SeqPanel)
{
- appJmolWindow.removeAlignmentPanel(((SeqPanel) svl).ap);
+ getViewer().removeAlignmentPanel(((SeqPanel) svl).ap);
}
}
// TODO Auto-generated method stub
return null;
}
-
- @Override
- public JalviewStructureDisplayI getViewer()
- {
- return appJmolWindow;
- }
-
- @Override
- public jalview.api.FeatureRenderer getFeatureRenderer(
- AlignmentViewPanel alignment)
- {
- AlignmentPanel ap = (alignment == null)
- ? appJmolWindow.getAlignmentPanel()
- : (AlignmentPanel) alignment;
- if (ap.av.isShowSequenceFeatures())
- {
- return ap.av.getAlignPanel().getSeqPanel().seqCanvas.fr;
- }
-
- return null;
- }
}
*/
package jalview.gui;
+import jalview.api.AlignmentViewPanel;
import jalview.api.FeatureRenderer;
import jalview.bin.Cache;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
-import jalview.ext.rbvi.chimera.ChimeraCommands;
import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Random;
-import javax.swing.JCheckBoxMenuItem;
import javax.swing.JInternalFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
{
private JalviewChimeraBinding jmb;
- private IProgressIndicator progressBar = null;
-
/*
* Path to Chimera session file. This is set when an open Jalview/Chimera
* session is saved, or on restore from a Jalview project (if it holds the
*/
private String chimeraSessionFile = null;
- private Random random = new Random();
-
private int myWidth = 500;
private int myHeight = 150;
*/
protected void buildAttributesMenu(JMenu attributesMenu)
{
- List<String> atts = jmb.sendChimeraCommand("list resattr", true);
- if (atts == null)
- {
- return;
- }
+ List<String> atts = jmb.getChimeraAttributes();
attributesMenu.removeAll();
Collections.sort(atts);
- for (String att : atts)
+ for (String attName : atts)
{
- final String attName = att.split(" ")[1];
-
- /*
- * ignore 'jv_*' attributes, as these are Jalview features that have
- * been transferred to residue attributes in Chimera!
- */
- if (!attName.startsWith(ChimeraCommands.NAMESPACE_PREFIX))
+ JMenuItem menuItem = new JMenuItem(attName);
+ menuItem.addActionListener(new ActionListener()
{
- JMenuItem menuItem = new JMenuItem(attName);
- menuItem.addActionListener(new ActionListener()
+ @Override
+ public void actionPerformed(ActionEvent e)
{
- @Override
- public void actionPerformed(ActionEvent e)
- {
- getChimeraAttributes(attName);
- }
- });
- attributesMenu.add(menuItem);
- }
+ getChimeraAttributes(attName);
+ }
+ });
+ attributesMenu.add(menuItem);
}
}
/**
* Send a command to Chimera to create residue attributes for Jalview features
* <p>
- * The syntax is: setattr r <attName> <attValue> <atomSpec>
+ * The syntax is: setattr r <attName> <attValue> <atomSpec>
* <p>
- * For example: setattr r jv:chain "Ferredoxin-1, Chloroplastic" #0:94.A
+ * For example: setattr r jv_chain "Ferredoxin-1, Chloroplastic" #0:94.A
*/
protected void sendFeaturesToChimera()
{
*/
protected void createProgressBar()
{
- if (progressBar == null)
+ if (getProgressIndicator() == null)
{
- progressBar = new ProgressBar(statusPanel, statusBar);
+ setProgressIndicator(new ProgressBar(statusPanel, statusBar));
}
}
SequenceI[][] seqs)
{
createProgressBar();
- jmb = new JalviewChimeraBindingModel(this,
- ap.getStructureSelectionManager(), pdbentrys, seqs, null);
+ jmb = newBindingModel(ap, pdbentrys, seqs);
addAlignmentPanel(ap);
useAlignmentPanelForColourbyseq(ap);
}
+ protected JalviewChimeraBindingModel newBindingModel(AlignmentPanel ap,
+ PDBEntry[] pdbentrys, SequenceI[][] seqs)
+ {
+ return new JalviewChimeraBindingModel(this,
+ ap.getStructureSelectionManager(), pdbentrys, seqs, null);
+ }
+
/**
* Create a new viewer from saved session state data including Chimera session
* file
}
/**
- * Show only the selected chain(s) in the viewer
- */
- @Override
- void showSelectedChains()
- {
- List<String> 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.
pdb = jmb.getSsm().setMapping(jmb.getSequence()[pos],
jmb.getChains()[pos], pe.getFile(), protocol,
- progressBar);
+ getProgressIndicator());
stashFoundChains(pdb, pe.getFile());
} catch (OutOfMemoryError oomerror)
}
// refresh the sequence colours for the new structure(s)
- for (AlignmentPanel ap : _colourwith)
+ for (AlignmentViewPanel ap : _colourwith)
{
jmb.updateColours(ap);
}
@Override
public void run()
{
- alignStructs_withAllAlignPanels();
+ alignStructsWithAllAlignPanels();
}
}).start();
}
String chid = new String(
pdb.getId() + ":" + pdb.getChains().elementAt(i).id);
jmb.getChainNames().add(chid);
- jmb.getChainFile().put(chid, file);
+ jmb.addChainFile(chid, file);
}
}
return filePath;
}
- /**
- * Convenience method to update the progress bar if there is one. Be sure to
- * call stopProgressBar with the returned handle to remove the message.
- *
- * @param msg
- * @param handle
- */
- public long startProgressBar(String msg)
- {
- // TODO would rather have startProgress/stopProgress as the
- // IProgressIndicator interface
- long tm = random.nextLong();
- if (progressBar != null)
- {
- progressBar.setProgressBar(msg, tm);
- }
- return tm;
- }
-
- /**
- * End the progress bar with the specified handle, leaving a message (if not
- * null) on the status bar
- *
- * @param msg
- * @param handle
- */
- public void stopProgressBar(String msg, long handle)
- {
- if (progressBar != null)
- {
- progressBar.setProgressBar(msg, handle);
- }
- }
-
@Override
- public void eps_actionPerformed(ActionEvent e)
+ public void eps_actionPerformed()
{
throw new Error(MessageManager
.getString("error.eps_generation_not_implemented"));
}
@Override
- public void png_actionPerformed(ActionEvent e)
+ public void png_actionPerformed()
{
throw new Error(MessageManager
.getString("error.png_generation_not_implemented"));
}
@Override
- public void showHelp_actionPerformed(ActionEvent actionEvent)
+ public void showHelp_actionPerformed()
{
try
{
- BrowserLauncher
- .openURL("https://www.cgl.ucsf.edu/chimera/docs/UsersGuide");
+ String url = jmb.getHelpURL();
+ BrowserLauncher.openURL(url);
} catch (IOException ex)
{
+ System.err
+ .println("Show Chimera help failed with: " + ex.getMessage());
}
}
{
if (pathUsed == null)
{
- File tempFile = File.createTempFile("chimera", ".py");
+ String suffix = jmb.getSessionFileExtension();
+ File tempFile = File.createTempFile("chimera", suffix);
tempFile.deleteOnExit();
pathUsed = tempFile.getPath();
}
{
return "Chimera";
}
-
- /**
- * Sends commands to align structures according to associated alignment(s).
- *
- * @return
- */
- @Override
- protected String alignStructs_withAllAlignPanels()
- {
- String reply = super.alignStructs_withAllAlignPanels();
- if (reply != null)
- {
- statusBar.setText("Superposition failed: " + reply);
- }
- return reply;
- }
-
- @Override
- protected IProgressIndicator getIProgressIndicator()
- {
- return progressBar;
- }
}
--- /dev/null
+package jalview.gui;
+
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+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
+{
+
+ public ChimeraXViewFrame(PDBEntry pdb, SequenceI[] seqsForPdb,
+ String[] chains, AlignmentPanel ap)
+ {
+ super(pdb, seqsForPdb, chains, ap);
+ }
+
+ public ChimeraXViewFrame(PDBEntry[] pdbsForFile, boolean superposeAdded,
+ SequenceI[][] theSeqs, AlignmentPanel ap)
+ {
+ super(pdbsForFile, superposeAdded, theSeqs, ap);
+ }
+
+ @Override
+ public ViewerType getViewerType()
+ {
+ return ViewerType.CHIMERAX;
+ }
+
+ @Override
+ protected String getViewerName()
+ {
+ return "ChimeraX";
+ }
+
+ @Override
+ protected JalviewChimeraBindingModel newBindingModel(AlignmentPanel ap,
+ PDBEntry[] pdbentrys, SequenceI[][] seqs)
+ {
+ return new JalviewChimeraXBindingModel(this,
+ ap.getStructureSelectionManager(), pdbentrys, seqs, null);
+ }
+
+}
import jalview.ext.rbvi.chimera.JalviewChimeraBinding;
import jalview.io.DataSourceType;
import jalview.structure.StructureSelectionManager;
-import jalview.viewmodel.seqfeatures.FeatureRendererModel;
+import javax.swing.JComponent;
import javax.swing.SwingUtilities;
public class JalviewChimeraBindingModel extends JalviewChimeraBinding
{
- private ChimeraViewFrame cvf;
-
public JalviewChimeraBindingModel(ChimeraViewFrame chimeraViewFrame,
StructureSelectionManager ssm, PDBEntry[] pdbentry,
SequenceI[][] sequenceIs, DataSourceType protocol)
{
super(ssm, pdbentry, sequenceIs, protocol);
- cvf = chimeraViewFrame;
- }
-
- @Override
- public FeatureRendererModel getFeatureRenderer(AlignmentViewPanel alignment)
- {
- AlignmentPanel ap = (alignment == null) ? cvf.getAlignmentPanel()
- : (AlignmentPanel) alignment;
- if (ap.av.isShowSequenceFeatures())
- {
- return ap.getSeqPanel().seqCanvas.fr;
- }
-
- return null;
+ setViewer(chimeraViewFrame);
}
@Override
@Override
public void run()
{
- cvf.updateTitleAndMenus();
- cvf.revalidate();
+ JalviewStructureDisplayI theViewer = getViewer();
+ theViewer.updateTitleAndMenus();
+ ((JComponent) theViewer).revalidate();
}
});
}
-
- @Override
- public void updateColours(Object source)
- {
- AlignmentPanel ap = (AlignmentPanel) source;
- // ignore events from panels not used to colour this view
- if (!cvf.isUsedforcolourby(ap))
- {
- return;
- }
- if (!isLoadingFromArchive())
- {
- colourBySequence(ap);
- }
- }
-
- @Override
- public void releaseReferences(Object svl)
- {
- }
-
- @Override
- protected void releaseUIResources()
- {
- }
-
- @Override
- public void refreshPdbEntries()
- {
- }
-
- /**
- * Send an asynchronous command to Chimera, in a new thread, optionally with
- * an 'in progress' message in a progress bar somewhere
- */
- @Override
- protected void sendAsynchronousCommand(final String command,
- final String progressMsg)
- {
- final long handle = progressMsg == null ? 0
- : cvf.startProgressBar(progressMsg);
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- try
- {
- sendChimeraCommand(command, false);
- } finally
- {
- if (progressMsg != null)
- {
- cvf.stopProgressBar(null, handle);
- }
- }
- }
- });
- }
-
- @Override
- public JalviewStructureDisplayI getViewer()
- {
- return cvf;
- }
}
--- /dev/null
+package jalview.gui;
+
+import jalview.datamodel.PDBEntry;
+import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.ChimeraXCommands;
+import jalview.gui.StructureViewer.ViewerType;
+import jalview.io.DataSourceType;
+import jalview.structure.StructureSelectionManager;
+
+import java.util.List;
+
+import ext.edu.ucsf.rbvi.strucviz2.ChimeraModel;
+import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
+import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType;
+
+public class JalviewChimeraXBindingModel extends JalviewChimeraBindingModel
+{
+
+ public JalviewChimeraXBindingModel(ChimeraViewFrame chimeraViewFrame,
+ StructureSelectionManager ssm, PDBEntry[] pdbentry,
+ SequenceI[][] sequenceIs, DataSourceType protocol)
+ {
+ super(chimeraViewFrame, ssm, pdbentry, sequenceIs, protocol);
+ setStructureCommands(new ChimeraXCommands());
+ }
+
+ @Override
+ protected List<String> getChimeraPaths()
+ {
+ return StructureManager.getChimeraPaths(true);
+ }
+
+ @Override
+ protected void addChimeraModel(PDBEntry pe,
+ List<ChimeraModel> modelsToMap)
+ {
+ /*
+ * ChimeraX hack: force chimera model name to pdbId here
+ */
+ int modelNumber = chimeraMaps.size() + 1;
+ String command = "setattr #" + modelNumber + " models name "
+ + pe.getId();
+ executeCommand(command, false);
+ modelsToMap.add(new ChimeraModel(pe.getId(), ModelType.PDB_MODEL,
+ modelNumber, 0));
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * @return
+ */
+ @Override
+ protected String getCommandFileExtension()
+ {
+ return ".cxc";
+ }
+
+ /**
+ * Returns the file extension to use for a saved viewer session file
+ *
+ * @return
+ */
+ @Override
+ public String getSessionFileExtension()
+ {
+ return ".cxs";
+ }
+
+ @Override
+ public String getHelpURL()
+ {
+ return "http://www.rbvi.ucsf.edu/chimerax/docs/user/index.html";
+ }
+
+ @Override
+ protected ViewerType getViewerType()
+ {
+ return ViewerType.CHIMERAX;
+ }
+
+}
public static final String CHIMERA_PATH = "CHIMERA_PATH";
+ public static final String CHIMERAX_PATH = "CHIMERAX_PATH";
+
public static final String SORT_ANNOTATIONS = "SORT_ANNOTATIONS";
public static final String SHOW_AUTOCALC_ABOVE = "SHOW_AUTOCALC_ABOVE";
addSecondaryStructure.setEnabled(structSelected);
addTempFactor.setSelected(Cache.getDefault(ADD_TEMPFACT_ANN, false));
addTempFactor.setEnabled(structSelected);
- structViewer.setSelectedItem(
- Cache.getDefault(STRUCTURE_DISPLAY, ViewerType.JMOL.name()));
- chimeraPath.setText(Cache.getDefault(CHIMERA_PATH, ""));
+ String viewerType = Cache.getDefault(STRUCTURE_DISPLAY, ViewerType.JMOL.name());
+ structViewer.setSelectedItem(viewerType);
+ boolean isChimeraX = viewerType.equals(ViewerType.CHIMERAX.name());
+ if (viewerType.equals(ViewerType.JMOL.name()))
+ {
+ chimeraPath.setText("");
+ }
+ else
+ {
+ chimeraPath.setText(Cache
+ .getDefault(isChimeraX ? CHIMERAX_PATH : CHIMERA_PATH, ""));
+ }
chimeraPath.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
- validateChimeraPath();
+ if (validateChimeraPath())
+ {
+ Cache.setProperty(structViewer.getSelectedItem()
+ .equals(ViewerType.CHIMERAX.name())
+ ? CHIMERAX_PATH
+ : CHIMERA_PATH, chimeraPath.getText());
+ }
}
});
doReset.addActionListener(onReset);
// filter to display only custom urls
- final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<TableModel, Object>()
+ final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<>()
{
@Override
public boolean include(
Boolean.toString(structFromPdb.isSelected()));
Cache.applicationProperties.setProperty(STRUCTURE_DISPLAY,
structViewer.getSelectedItem().toString());
- Cache.setOrRemove(CHIMERA_PATH, chimeraPath.getText());
+ boolean isChimeraX = structViewer.getSelectedItem().toString()
+ .equals(ViewerType.CHIMERAX.name());
+ Cache.setOrRemove(isChimeraX ? CHIMERAX_PATH : CHIMERA_PATH,
+ chimeraPath.getText());
Cache.applicationProperties.setProperty("MAP_WITH_SIFTS",
Boolean.toString(siftsMapping.isSelected()));
SiftsSettings.setMapWithSifts(siftsMapping.isSelected());
}
/**
- * If Chimera is selected, check it can be found on default or user-specified
- * path, if not show a warning/help dialog.
+ * If Chimera or ChimeraX is selected, check it can be found on default or
+ * user-specified path, if not show a warning/help dialog.
*/
@Override
protected void structureViewer_actionPerformed(String selectedItem)
{
- if (!selectedItem.equals(ViewerType.CHIMERA.name()))
+ if (selectedItem.equals(ViewerType.JMOL.name()))
{
+ chimeraPath.setEnabled(false);
+ chimeraPathLabel.setEnabled(false);
return;
}
boolean found = false;
+ chimeraPath.setEnabled(true);
+ chimeraPathLabel.setEnabled(true);
+ chimeraPathLabel.setText(MessageManager
+ .formatMessage("label.chimera_path", selectedItem));
/*
- * Try user-specified and standard paths for Chimera executable.
+ * Try user-specified and standard paths for Chimera executable
*/
- List<String> paths = StructureManager.getChimeraPaths();
+ boolean isChimeraX = selectedItem.equals(ViewerType.CHIMERAX.name());
+ chimeraPath.setText(Cache
+ .getDefault(isChimeraX ? CHIMERAX_PATH : CHIMERA_PATH, ""));
+
+ List<String> paths = StructureManager.getChimeraPaths(isChimeraX);
paths.add(0, chimeraPath.getText());
for (String path : paths)
{
public enum ViewerType
{
- JMOL, CHIMERA
+ JMOL, CHIMERA, CHIMERAX
};
/**
sview = new ChimeraViewFrame(pdbsForFile, superposeAdded, theSeqs,
ap);
}
+ else if (viewerType.equals(ViewerType.CHIMERAX))
+ {
+ sview = new ChimeraXViewFrame(pdbsForFile, superposeAdded, theSeqs,
+ ap);
+ }
else
{
Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
{
sview = new ChimeraViewFrame(pdb, seqsForPdb, null, ap);
}
+ else if (viewerType.equals(ViewerType.CHIMERAX))
+ {
+ sview = new ChimeraXViewFrame(pdb, seqsForPdb, null, ap);
+ }
else
{
Cache.log.error(UNKNOWN_VIEWER_TYPE + getViewerType().toString());
import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
-import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
import jalview.gui.StructureViewer.ViewerType;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Random;
import java.util.Vector;
import javax.swing.ButtonGroup;
/**
* list of alignment panels to use for superposition
*/
- protected Vector<AlignmentPanel> _alignwith = new Vector<>();
+ protected Vector<AlignmentViewPanel> _alignwith = new Vector<>();
/**
* list of alignment panels that are used for colouring structures by aligned
* sequences
*/
- protected Vector<AlignmentPanel> _colourwith = new Vector<>();
+ protected Vector<AlignmentViewPanel> _colourwith = new Vector<>();
private String viewId = null;
*/
protected volatile boolean seqColoursApplied = false;
+ private IProgressIndicator progressBar = null;
+
+ private Random random = new Random();
+
/**
* Default constructor
*/
return _aps.contains(ap2.av.getSequenceSetId());
}
- public boolean isUsedforaligment(AlignmentPanel ap2)
+ public boolean isUsedforaligment(AlignmentViewPanel ap2)
{
return (_alignwith != null) && _alignwith.contains(ap2);
}
- public boolean isUsedforcolourby(AlignmentPanel ap2)
+ @Override
+ public boolean isUsedForColourBy(AlignmentViewPanel ap2)
{
return (_colourwith != null) && _colourwith.contains(ap2);
}
}
}
+ @Override
public AlignmentPanel getAlignmentPanel()
{
return ap;
*
* @param nap
*/
- public void removeAlignmentPanel(AlignmentPanel nap)
+ @Override
+ public void removeAlignmentPanel(AlignmentViewPanel nap)
{
try
{
public abstract ViewerType getViewerType();
- protected abstract IProgressIndicator getIProgressIndicator();
-
/**
* add a new structure (with associated sequences and chains) to this viewer,
* retrieving it if necessary first.
* create the mappings
*/
apanel.getStructureSelectionManager().setMapping(seq, chains,
- pdbFilename, DataSourceType.FILE, getIProgressIndicator());
+ pdbFilename, DataSourceType.FILE, getProgressIndicator());
/*
* alert the FeatureRenderer to show new (PDB RESNUM) features
}
}
- abstract void showSelectedChains();
-
/**
* Action on selecting one of Jalview's registered colour schemes
*/
ColourSchemeI cs = ColourSchemes.getInstance()
.getColourScheme(colourSchemeName, getAlignmentPanel().av, al,
null);
- getBinding().setJalviewColourScheme(cs);
+ getBinding().colourByJalviewColourScheme(cs);
}
/**
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- viewerColour_actionPerformed(actionEvent);
+ viewerColour_actionPerformed();
}
});
colourMenu.add(viewerColour);
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- background_actionPerformed(actionEvent);
+ background_actionPerformed();
}
});
colourMenu.add(backGround);
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- seqColour_actionPerformed(actionEvent);
+ seqColour_actionPerformed();
}
});
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- chainColour_actionPerformed(actionEvent);
+ chainColour_actionPerformed();
}
});
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- chargeColour_actionPerformed(actionEvent);
+ chargeColour_actionPerformed();
}
});
else
{
// update the Chimera display now.
- seqColour_actionPerformed(null);
+ seqColour_actionPerformed();
}
}
});
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
* the operation.
*/
@Override
- protected String alignStructs_actionPerformed(ActionEvent actionEvent)
- {
- return alignStructs_withAllAlignPanels();
- }
-
- protected String alignStructs_withAllAlignPanels()
+ protected String alignStructsWithAllAlignPanels()
{
if (getAlignmentPanel() == null)
{
String reply = null;
try
{
- AlignmentI[] als = new Alignment[_alignwith.size()];
- HiddenColumns[] alc = new HiddenColumns[_alignwith.size()];
- int[] alm = new int[_alignwith.size()];
- int a = 0;
-
- for (AlignmentPanel alignPanel : _alignwith)
- {
- als[a] = alignPanel.av.getAlignment();
- alm[a] = -1;
- alc[a++] = alignPanel.av.getAlignment().getHiddenColumns();
- }
- reply = getBinding().superposeStructures(als, alm, alc);
- if (reply != null)
+ reply = getBinding().superposeStructures(_alignwith);
+ if (reply != null && !reply.isEmpty())
{
String text = MessageManager
.formatMessage("error.superposition_failed", reply);
} catch (Exception e)
{
StringBuffer sp = new StringBuffer();
- for (AlignmentPanel alignPanel : _alignwith)
+ for (AlignmentViewPanel alignPanel : _alignwith)
{
- sp.append("'" + alignPanel.alignFrame.getTitle() + "' ");
+ sp.append("'" + alignPanel.getViewName() + "' ");
}
Cache.log.info("Couldn't align structures with the " + sp.toString()
+ "associated alignment panels.", e);
}
@Override
- public void background_actionPerformed(ActionEvent actionEvent)
+ public void background_actionPerformed()
{
Color col = JColorChooser.showDialog(this,
MessageManager.getString("label.select_background_colour"),
}
@Override
- public void viewerColour_actionPerformed(ActionEvent actionEvent)
+ public void viewerColour_actionPerformed()
{
if (viewerColour.isSelected())
{
}
@Override
- public void chainColour_actionPerformed(ActionEvent actionEvent)
+ public void chainColour_actionPerformed()
{
chainColour.setSelected(true);
getBinding().colourByChain();
}
@Override
- public void chargeColour_actionPerformed(ActionEvent actionEvent)
+ public void chargeColour_actionPerformed()
{
chargeColour.setSelected(true);
getBinding().colourByCharge();
}
@Override
- public void seqColour_actionPerformed(ActionEvent actionEvent)
+ public void seqColour_actionPerformed()
{
AAStructureBindingModel binding = getBinding();
binding.setColourBySequence(seqColour.isSelected());
}
}
// Set the colour using the current view for the associated alignframe
- for (AlignmentPanel alignPanel : _colourwith)
+ for (AlignmentViewPanel alignPanel : _colourwith)
{
binding.colourBySequence(alignPanel);
}
}
@Override
- public void pdbFile_actionPerformed(ActionEvent actionEvent)
+ public void pdbFile_actionPerformed()
{
JalviewFileChooser chooser = new JalviewFileChooser(
Cache.getProperty("LAST_DIRECTORY"));
}
@Override
- public void viewMapping_actionPerformed(ActionEvent actionEvent)
+ public void viewMapping_actionPerformed()
{
CutAndPasteTransfer cap = new CutAndPasteTransfer();
try
if (!binding.isLoadingFromArchive())
{
- seqColour_actionPerformed(null);
+ seqColour_actionPerformed();
}
}
toFront();
}
+ @Override
+ public long startProgressBar(String msg)
+ {
+ // TODO would rather have startProgress/stopProgress as the
+ // IProgressIndicator interface
+ long tm = random.nextLong();
+ if (progressBar != null)
+ {
+ progressBar.setProgressBar(msg, tm);
+ }
+ return tm;
+ }
+
+ @Override
+ public void stopProgressBar(String msg, long handle)
+ {
+ if (progressBar != null)
+ {
+ progressBar.setProgressBar(msg, handle);
+ }
+ }
+
+ protected IProgressIndicator getProgressIndicator()
+ {
+ return progressBar;
+ }
+
+ protected void setProgressIndicator(IProgressIndicator pi)
+ {
+ progressBar = pi;
+ }
+
+ protected void setProgressMessage(String message, long id)
+ {
+ if (progressBar != null)
+ {
+ progressBar.setProgressBar(message, id);
+ }
+ }
+
+ @Override
+ public void showConsole(boolean show)
+ {
+ // default does nothing
+ }
+
+ /**
+ * Show only the selected chain(s) in the viewer
+ */
+ protected void showSelectedChains()
+ {
+ List<String> 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);
+ }
+
}
*/
package jalview.gui;
+import jalview.api.AlignmentViewPanel;
import jalview.util.MessageManager;
import java.awt.Component;
private ViewSetProvider _allviews;
- private List<AlignmentPanel> _selectedviews;
+ private List<AlignmentViewPanel> _selectedviews;
private ItemListener _handler;
* selection/deselection state
*/
public ViewSelectionMenu(String title, final ViewSetProvider allviews,
- final List<AlignmentPanel> selectedviews,
+ final List<AlignmentViewPanel> selectedviews,
final ItemListener handler)
{
super(title);
import jalview.structure.AtomSpec;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.util.HttpUtils;
// Form a colour command from the given alignment panel for each distinct
// structure
- ArrayList<String[]> ccomands = new ArrayList<String[]>();
- ArrayList<String> pdbfn = new ArrayList<String>();
- StructureMappingcommandSet[] colcommands = JmolCommands
- .getColourBySequenceCommand(ssm, modelSet, sequence, sr,
+ ArrayList<String[]> ccomands = new ArrayList<>();
+ ArrayList<String> 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;
protected JComboBox<String> structViewer = new JComboBox<>();
+ protected JLabel chimeraPathLabel;
+
protected JTextField chimeraPath = new JTextField();
protected ButtonGroup mappingMethod = new ButtonGroup();
structureTab.setBorder(new TitledBorder(
MessageManager.getString("label.structure_options")));
structureTab.setLayout(null);
- final int width = 400;
+ final int width = 420;
final int height = 22;
final int lineSpacing = 25;
int ypos = 15;
viewerLabel.setFont(LABEL_FONT);
viewerLabel.setHorizontalAlignment(SwingConstants.LEFT);
viewerLabel.setText(MessageManager.getString("label.structure_viewer"));
- viewerLabel.setBounds(new Rectangle(10, ypos, 200, height));
+ viewerLabel.setBounds(new Rectangle(10, ypos, 220, height));
structureTab.add(viewerLabel);
structViewer.setFont(LABEL_FONT);
- structViewer.setBounds(new Rectangle(160, ypos, 120, height));
+ structViewer.setBounds(new Rectangle(190, ypos, 120, height));
structViewer.addItem(ViewerType.JMOL.name());
structViewer.addItem(ViewerType.CHIMERA.name());
+ structViewer.addItem(ViewerType.CHIMERAX.name());
structViewer.addActionListener(new ActionListener()
{
@Override
structureTab.add(structViewer);
ypos += lineSpacing;
- JLabel pathLabel = new JLabel();
- pathLabel.setFont(new java.awt.Font("SansSerif", 0, 11));
- pathLabel.setHorizontalAlignment(SwingConstants.LEFT);
- pathLabel.setText(MessageManager.getString("label.chimera_path"));
- pathLabel.setBounds(new Rectangle(10, ypos, 140, height));
- structureTab.add(pathLabel);
+ chimeraPathLabel = new JLabel();
+ chimeraPathLabel.setFont(LABEL_FONT);// new Font("SansSerif", 0, 11));
+ chimeraPathLabel.setHorizontalAlignment(SwingConstants.LEFT);
+ chimeraPathLabel.setText(MessageManager
+ .formatMessage("label.chimera_path", "Chimera(X)"));
+ chimeraPathLabel.setBounds(new Rectangle(10, ypos, 170, height));
+ chimeraPathLabel.setEnabled(false);
+ structureTab.add(chimeraPathLabel);
chimeraPath.setFont(LABEL_FONT);
chimeraPath.setText("");
+ chimeraPath.setEnabled(false);
final String tooltip = JvSwingUtils.wrapTooltip(true,
MessageManager.getString("label.chimera_path_tip"));
chimeraPath.setToolTipText(tooltip);
- chimeraPath.setBounds(new Rectangle(160, ypos, 300, height));
+ chimeraPath.setBounds(new Rectangle(190, ypos, 290, height));
chimeraPath.addMouseListener(new MouseAdapter()
{
@Override
public void mouseClicked(MouseEvent e)
{
- if (e.getClickCount() == 2)
+ if (chimeraPath.isEnabled() && e.getClickCount() == 2)
{
String chosen = openFileChooser();
if (chosen != null)
MessageManager.getString("label.mapping_method"));
mmTitledBorder.setTitleFont(LABEL_FONT);
mappingPanel.setBorder(mmTitledBorder);
- mappingPanel.setBounds(new Rectangle(10, ypos, 452, 45));
+ mappingPanel.setBounds(new Rectangle(10, ypos, 472, 45));
// GridLayout mappingLayout = new GridLayout();
mappingPanel.setLayout(new GridLayout());
mappingPanel.add(nwMapping);
ypos += lineSpacing;
FTSDataColumnPreferences docFieldPref = new FTSDataColumnPreferences(
PreferenceSource.PREFERENCES, PDBFTSRestClient.getInstance());
- docFieldPref.setBounds(new Rectangle(10, ypos, 450, 120));
+ docFieldPref.setBounds(new Rectangle(10, ypos, 470, 120));
structureTab.add(docFieldPref);
return structureTab;
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- pdbFile_actionPerformed(actionEvent);
+ pdbFile_actionPerformed();
}
});
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- png_actionPerformed(actionEvent);
+ png_actionPerformed();
}
});
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- eps_actionPerformed(actionEvent);
+ eps_actionPerformed();
}
});
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- viewMapping_actionPerformed(actionEvent);
+ viewMapping_actionPerformed();
}
});
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- showHelp_actionPerformed(actionEvent);
+ showHelp_actionPerformed();
}
});
alignStructs = new JMenuItem();
@Override
public void actionPerformed(ActionEvent actionEvent)
{
- alignStructs_actionPerformed(actionEvent);
+ alignStructsWithAllAlignPanels();
}
});
{
}
- protected void viewerColour_actionPerformed(ActionEvent actionEvent)
+ protected void viewerColour_actionPerformed()
{
}
- protected abstract String alignStructs_actionPerformed(
- ActionEvent actionEvent);
+ protected abstract String alignStructsWithAllAlignPanels();
- public void pdbFile_actionPerformed(ActionEvent actionEvent)
+ public void pdbFile_actionPerformed()
{
}
- public void png_actionPerformed(ActionEvent actionEvent)
+ public void png_actionPerformed()
{
}
- public void eps_actionPerformed(ActionEvent actionEvent)
+ public void eps_actionPerformed()
{
}
- public void viewMapping_actionPerformed(ActionEvent actionEvent)
+ public void viewMapping_actionPerformed()
{
}
- public void seqColour_actionPerformed(ActionEvent actionEvent)
+ public void seqColour_actionPerformed()
{
}
- public void chainColour_actionPerformed(ActionEvent actionEvent)
+ public void chainColour_actionPerformed()
{
}
- public void chargeColour_actionPerformed(ActionEvent actionEvent)
+ public void chargeColour_actionPerformed()
{
}
- public void background_actionPerformed(ActionEvent actionEvent)
+ public void background_actionPerformed()
{
}
- public void showHelp_actionPerformed(ActionEvent actionEvent)
+ public void showHelp_actionPerformed()
{
}
final String viewId = viewFrame.getViewId();
state.setViewId(viewId);
state.setAlignwithAlignPanel(viewFrame.isUsedforaligment(ap));
- state.setColourwithAlignPanel(viewFrame.isUsedforcolourby(ap));
+ state.setColourwithAlignPanel(viewFrame.isUsedForColourBy(ap));
state.setColourByJmol(viewFrame.isColouredByViewer());
state.setType(viewFrame.getViewerType().toString());
// pdb.addStructureState(state);
* Parses a Chimera atomspec e.g. #1:12.A to construct an AtomSpec model (with
* null pdb file name)
*
+ * <pre>
+ * Chimera format:
+ * #1.2:12-20.A model 1, submodel 2, chain A, atoms 12-20
+ * ChimeraX format:
+ * #1.2/A:12-20
+ * </pre>
+ *
* @param spec
+ * @param chimeraX
* @return
* @throw IllegalArgumentException if the spec cannot be parsed, or represents
* more than one residue
+ * @see https://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec.html
+ * @see http://rbvi.ucsf.edu/chimerax/docs/user/commands/atomspec.html
*/
- public static AtomSpec fromChimeraAtomspec(String spec)
+ public static AtomSpec fromChimeraAtomspec(String spec, boolean chimeraX)
{
- int colonPos = spec.indexOf(":");
- if (colonPos == -1)
+ int modelSeparatorPos = spec.indexOf(chimeraX ? "/" : ":");
+ if (modelSeparatorPos == -1)
{
throw new IllegalArgumentException(spec);
}
int hashPos = spec.indexOf("#");
- if (hashPos == -1 && colonPos != 0)
+ if (hashPos == -1 && modelSeparatorPos != 0)
{
// # is missing but something precedes : - reject
throw new IllegalArgumentException(spec);
}
- String modelSubmodel = spec.substring(hashPos + 1, colonPos);
- int dotPos = modelSubmodel.indexOf(".");
+ String modelSubmodel = spec.substring(hashPos + 1, modelSeparatorPos);
int modelId = 0;
try
{
- modelId = Integer.valueOf(dotPos == -1 ? modelSubmodel
- : modelSubmodel.substring(0, dotPos));
+ int subModelPos = modelSubmodel.indexOf(".");
+ modelId = Integer.valueOf(
+ subModelPos > 0 ? modelSubmodel.substring(0, subModelPos)
+ : modelSubmodel);
} catch (NumberFormatException e)
{
// ignore, default to model 0
}
- String residueChain = spec.substring(colonPos + 1);
- dotPos = residueChain.indexOf(".");
+ /*
+ * now process what follows the model, either
+ * Chimera: atoms.chain
+ * ChimeraX: chain:atoms
+ */
+ String atomsAndChain = spec.substring(modelSeparatorPos + 1);
+ String[] tokens = atomsAndChain.split(chimeraX ? "\\:" : "\\.");
+ String atoms = tokens.length == 1 ? atomsAndChain
+ : (chimeraX ? tokens[1] : tokens[0]);
int resNum = 0;
try
{
- resNum = Integer.parseInt(dotPos == -1 ? residueChain
- : residueChain.substring(0, dotPos));
+ resNum = Integer.parseInt(atoms);
} catch (NumberFormatException e)
{
// could be a range e.g. #1:4-7.B
throw new IllegalArgumentException(spec);
}
- String chainId = dotPos == -1 ? "" : residueChain.substring(dotPos + 1);
+ String chainId = tokens.length == 1 ? ""
+ : (chimeraX ? tokens[0] : tokens[1]);
return new AtomSpec(modelId, chainId, resNum, 0);
}
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.structure;
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A class to model a set of models, chains and atom range positions
+ *
+ */
+public class AtomSpecModel
+{
+ /*
+ * { modelNo, {chainCode, List<from-to> ranges} }
+ */
+ private Map<Integer, Map<String, BitSet>> atomSpec;
+
+ /**
+ * Constructor
+ */
+ public AtomSpecModel()
+ {
+ atomSpec = new TreeMap<>();
+ }
+
+ /**
+ * Adds one contiguous range to this atom spec
+ *
+ * @param model
+ * @param startPos
+ * @param endPos
+ * @param chain
+ */
+ public void addRange(int model, int startPos, int endPos, String chain)
+ {
+ /*
+ * Get/initialize map of data for the colour and model
+ */
+ Map<String, BitSet> modelData = atomSpec.get(model);
+ if (modelData == null)
+ {
+ atomSpec.put(model, modelData = new TreeMap<>());
+ }
+
+ /*
+ * Get/initialize map of data for colour, model and chain
+ */
+ BitSet chainData = modelData.get(chain);
+ if (chainData == null)
+ {
+ chainData = new BitSet();
+ modelData.put(chain, chainData);
+ }
+
+ /*
+ * Add the start/end positions
+ */
+ chainData.set(startPos, endPos + 1);
+ }
+
+ public Iterable<Integer> getModels()
+ {
+ return atomSpec.keySet();
+ }
+
+ public Iterable<String> getChains(Integer model)
+ {
+ return atomSpec.containsKey(model) ? atomSpec.get(model).keySet()
+ : null;
+ }
+
+ /**
+ * Returns a (possibly empty) ordered list of contiguous atom ranges for the
+ * given model and chain.
+ *
+ * @param model
+ * @param chain
+ * @return
+ */
+ public List<int[]> getRanges(Integer model, String chain)
+ {
+ List<int[]> ranges = new ArrayList<>();
+ if (atomSpec.containsKey(model))
+ {
+ BitSet bs = atomSpec.get(model).get(chain);
+ int start = 0;
+ if (bs != null)
+ {
+ start = bs.nextSetBit(start);
+ int end = 0;
+ while (start != -1)
+ {
+ end = bs.nextClearBit(start);
+ ranges.add(new int[] { start, end - 1 });
+ start = bs.nextSetBit(end);
+ }
+ }
+ }
+ return ranges;
+ }
+}
--- /dev/null
+package jalview.structure;
+
+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.SequenceI;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
+import jalview.util.Comparison;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/**
+ * A base class holding methods useful to all classes that implement commands
+ * for structure viewers
+ *
+ * @author gmcarstairs
+ *
+ */
+public abstract class StructureCommandsBase implements StructureCommandsI
+{
+ private static final String CMD_SEPARATOR = ";";
+
+ /**
+ * Returns something that separates concatenated commands
+ *
+ * @return
+ */
+ protected static String getCommandSeparator()
+ {
+ return CMD_SEPARATOR;
+ }
+
+ @Override
+ public String[] setAttributesForFeatures(StructureSelectionManager ssm,
+ String[] files, SequenceI[][] sequence, AlignmentViewPanel avp)
+ {
+ // default does nothing, override where this is implemented
+ return null;
+ }
+
+ /**
+ * Returns the lowest model number used by the structure viewer
+ *
+ * @return
+ */
+ @Override
+ public 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
+ * <ul>
+ * <li>a colour, when building a 'colour structure by sequence' command</li>
+ * <li>a feature value, when building a 'set Chimera attributes from features'
+ * command</li>
+ * </ul>
+ *
+ * @param map
+ * @param value
+ * @param model
+ * @param startPos
+ * @param endPos
+ * @param chain
+ */
+ public static final void addAtomSpecRange(Map<Object, AtomSpecModel> 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);
+ }
+
+ /**
+ * Traverse the map of colours/models/chains/positions to construct a list of
+ * 'color' commands (one per distinct colour used). The format of each command
+ * is specific to the structure viewer.
+ *
+ * @param colourMap
+ * @return
+ */
+ @Override
+ public String[] colourBySequence(Map<Object, AtomSpecModel> colourMap)
+ {
+ /*
+ * This version concatenates all commands into a single String (semi-colon
+ * delimited). If length limit issues arise, refactor to return one color
+ * command per colour.
+ */
+ List<String> commands = new ArrayList<>();
+ StringBuilder sb = new StringBuilder(256);
+ boolean firstColour = true;
+ for (Object key : colourMap.keySet())
+ {
+ Color colour = (Color) key;
+ if (!firstColour)
+ {
+ sb.append(getCommandSeparator()).append(" ");
+ }
+ firstColour = false;
+ final AtomSpecModel colourData = colourMap.get(colour);
+ sb.append(getColourCommand(colourData, colour));
+ }
+ commands.add(sb.toString());
+
+ return commands.toArray(new String[commands.size()]);
+ }
+
+ /**
+ * Returns a command to colour the atoms represented by {@code atomSpecModel}
+ * with the colour specified by {@code colourCode}.
+ *
+ * @param atomSpecModel
+ * @param colour
+ * @return
+ */
+ protected String getColourCommand(AtomSpecModel atomSpecModel, Color colour)
+ {
+ String atomSpec = getAtomSpec(atomSpecModel, false);
+ return getColourCommand(atomSpec, colour);
+ }
+
+ /**
+ * Returns a command to colour the atoms described (in viewer command syntax)
+ * by {@code atomSpec} with the colour specified by {@code colourCode}
+ *
+ * @param atomSpec
+ * @param colour
+ * @return
+ */
+ protected abstract String getColourCommand(String atomSpec, Color colour);
+
+ @Override
+ public String colourByResidues(Map<String, Color> colours)
+ {
+ StringBuilder cmd = new StringBuilder(12 * colours.size());
+
+ for (Entry<String, Color> entry : colours.entrySet())
+ {
+ String residue = entry.getKey();
+ String atomSpec = getResidueSpec(residue);
+ cmd.append(getColourCommand(atomSpec, entry.getValue()));
+ cmd.append(getCommandSeparator());
+ }
+ return cmd.toString();
+ }
+
+ /**
+ * Helper method to append one start-end range to an atomspec string
+ *
+ * @param sb
+ * @param start
+ * @param end
+ * @param chain
+ * @param firstPositionForModel
+ */
+ protected void appendRange(StringBuilder sb, int start, int end,
+ String chain, boolean firstPositionForModel, boolean isChimeraX)
+ {
+ if (!firstPositionForModel)
+ {
+ sb.append(",");
+ }
+ if (end == start)
+ {
+ sb.append(start);
+ }
+ else
+ {
+ sb.append(start).append("-").append(end);
+ }
+
+ if (!isChimeraX)
+ {
+ sb.append(".");
+ if (!" ".equals(chain))
+ {
+ sb.append(chain);
+ }
+ }
+ }
+
+ /**
+ * Returns the atom specifier meaning all occurrences of the given residue
+ *
+ * @param residue
+ * @return
+ */
+ protected abstract String getResidueSpec(String residue);
+}
--- /dev/null
+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;
+ }
+}
--- /dev/null
+package jalview.structure;
+
+import jalview.api.AlignmentViewPanel;
+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
+{
+ /**
+ * Data bean class to simplify parameterisation in superposeStructures
+ */
+ public class SuperposeData
+ {
+ public String filename;
+
+ public String pdbId;
+
+ public String chain = "";
+
+ public boolean isRna;
+
+ /*
+ * The pdb residue number (if any) mapped to columns of the alignment
+ */
+ public int[] pdbResNo; // or use SparseIntArray?
+
+ public int modelNo;
+
+ /**
+ * Constructor
+ *
+ * @param width
+ * width of alignment (number of columns that may potentially
+ * participate in superposition)
+ * @param model
+ * structure viewer model number
+ */
+ public SuperposeData(int width, int model)
+ {
+ pdbResNo = new int[width];
+ modelNo = model;
+ }
+ }
+
+ /**
+ * Returns the command to colour by chain
+ *
+ * @return
+ */
+ String colourByChain();
+
+ /**
+ * Returns the command to colour residues using a charge-based scheme:
+ * <ul>
+ * <li>Aspartic acid and Glutamic acid (negative charge) red</li>
+ * <li>Lysine and Arginine (positive charge) blue</li>
+ * <li>Cysteine - yellow</li>
+ * <li>all others - white</li>
+ * </ul>
+ *
+ * @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<String, Color> 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). Parameter is
+ * a map from Color to a model of all residues assigned that colour.
+ *
+ * @param colourMap
+ * @return
+ */
+
+ String[] colourBySequence(Map<Object, AtomSpecModel> colourMap);
+
+ /**
+ * 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<String> toShow);
+
+ /**
+ * Returns zero, one or more commands to set attributes on mapped residues in
+ * the structure viewer for any features present and displayed in Jalview
+ *
+ * @param ssm
+ * @param files
+ * @param sequence
+ * @param avp
+ * @return
+ */
+ String[] setAttributesForFeatures(StructureSelectionManager ssm,
+ String[] files, SequenceI[][] sequence, AlignmentViewPanel avp);
+
+ /**
+ * Returns a command to superpose structures by closest positioning of
+ * residues in {@code atomSpec} to the corresponding residues in {@ refAtoms}.
+ * If wanted, this may include commands to visually highlight the residues
+ * that were used for the superposition.
+ *
+ * @param refAtoms
+ * @param atomSpec
+ * @return
+ */
+ String superposeStructures(AtomSpecModel refAtoms,
+ AtomSpecModel atomSpec);
+
+ /**
+ * Returns a command to open a file of commands at the given path
+ *
+ * @param path
+ * @return
+ */
+ String openCommandFile(String path);
+
+ /**
+ * Returns a command to save the current viewer session state to the given
+ * file
+ *
+ * @param filepath
+ * @return
+ */
+ String saveSession(String filepath);
+
+ /**
+ * Returns a representation of the atom set represented by the model, in
+ * viewer syntax format. If {@code alphaOnly} is true, this is restricted to
+ * Alpha Carbon (peptide) or Phosphorous (rna) only
+ *
+ * @param model
+ * @param alphaOnly
+ * @return
+ */
+ String getAtomSpec(AtomSpecModel model, boolean alphaOnly);
+
+ /**
+ * Returns the lowest model number used by the structure viewer (likely 0 or
+ * 1)
+ *
+ * @return
+ */
+ // TODO remove by refactoring so command generation is purely driven by
+ // AtomSpecModel objects derived in the binding classes?
+ int getModelStartNo();
+
+ /**
+ * Show only the backbone of the peptide (cartoons in Jmol, chain in Chimera)
+ *
+ * @return
+ */
+ String showBackbone();
+}
*/
package jalview.structures.models;
+import jalview.api.AlignViewportI;
import jalview.api.AlignmentViewPanel;
+import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.api.StructureSelectionManagerProvider;
import jalview.api.structures.JalviewStructureDisplayI;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.SequenceI;
+import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
+import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.schemes.ColourSchemeI;
+import jalview.schemes.ResidueProperties;
import jalview.structure.AtomSpec;
+import jalview.structure.AtomSpecModel;
+import jalview.structure.StructureCommandsI;
+import jalview.structure.StructureCommandsI.SuperposeData;
import jalview.structure.StructureListener;
import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
import jalview.util.Comparison;
import jalview.util.MessageManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
+
+import javax.swing.SwingUtilities;
/**
*
extends SequenceStructureBindingModel
implements StructureListener, StructureSelectionManagerProvider
{
+ private static final int MIN_POS_TO_SUPERPOSE = 4;
+
+ private static final String COLOURING_STRUCTURES = MessageManager
+ .getString("status.colouring_structures");
+
+ /*
+ * the Jalview panel through which the user interacts
+ * with the structure viewer
+ */
+ private JalviewStructureDisplayI viewer;
+
+ /*
+ * helper that generates command syntax
+ */
+ private StructureCommandsI commandGenerator;
private StructureSelectionManager ssm;
/*
+ * modelled chains, formatted as "pdbid:chainCode"
+ */
+ private List<String> chainNames;
+
+ /*
+ * lookup of pdb file name by key "pdbid:chainCode"
+ */
+ private Map<String, String> chainFile;
+
+ /*
* distinct PDB entries (pdb files) associated
* with sequences
*/
public String fileLoadingError;
/**
- * Data bean class to simplify parameterisation in superposeStructures
- */
- protected class SuperposeData
- {
- /**
- * Constructor with alignment width argument
- *
- * @param width
- */
- public SuperposeData(int width)
- {
- pdbResNo = new int[width];
- }
-
- public String filename;
-
- public String pdbId;
-
- public String chain = "";
-
- public boolean isRna;
-
- /*
- * The pdb residue number (if any) mapped to each column of the alignment
- */
- public int[] pdbResNo;
- }
-
- /**
* Constructor
*
* @param ssm
{
this.ssm = ssm;
this.sequence = seqs;
+ chainNames = new ArrayList<>();
+ chainFile = new HashMap<>();
}
/**
PDBEntry[] pdbentry, SequenceI[][] sequenceIs,
DataSourceType protocol)
{
- this.ssm = ssm;
- this.sequence = sequenceIs;
+ this(ssm, sequenceIs);
this.nucleotide = Comparison.isNucleotide(sequenceIs);
this.pdbEntry = pdbentry;
this.protocol = protocol;
*/
protected void releaseUIResources()
{
+ }
+ @Override
+ public void releaseReferences(Object svl)
+ {
}
public boolean isColourBySequence()
return colourBySequence;
}
+ /**
+ * Called when the binding thinks the UI needs to be refreshed after a
+ * structure viewer state change. This could be because structures were
+ * loaded, or because an error has occurred. Default does nothing, override as
+ * required.
+ */
+ public void refreshGUI()
+ {
+ }
+
+ /**
+ * 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
+ * Jalview knows about. By default does nothing, override as required.
+ */
+ public void refreshPdbEntries()
+ {
+ }
+
public void setColourBySequence(boolean colourBySequence)
{
this.colourBySequence = colourBySequence;
{ Integer.valueOf(pe).toString() }));
}
final String nullChain = "TheNullChain";
- List<SequenceI> s = new ArrayList<SequenceI>();
- List<String> c = new ArrayList<String>();
+ List<SequenceI> s = new ArrayList<>();
+ List<String> c = new ArrayList<>();
if (getChains() == null)
{
setChains(new String[getPdbCount()][]);
public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
SequenceI[][] seq, String[][] chns)
{
- List<PDBEntry> v = new ArrayList<PDBEntry>();
- List<int[]> rtn = new ArrayList<int[]>();
+ List<PDBEntry> v = new ArrayList<>();
+ List<int[]> rtn = new ArrayList<>();
for (int i = 0; i < getPdbCount(); i++)
{
v.add(getPdbEntry(i));
* for the same structure)
*/
s = seqCountForPdbFile;
- break;
+ break; // fixme break out of two loops here!
}
}
}
}
/**
- * Returns a list of chains mapped in this viewer.
+ * Returns a list of chains mapped in this viewer, formatted as
+ * "pdbid:chainCode"
*
* @return
*/
- public abstract List<String> getChainNames();
+ public List<String> getChainNames()
+ {
+ return chainNames;
+ }
/**
* Returns the Jalview panel hosting the structure viewer (if any)
*/
public JalviewStructureDisplayI getViewer()
{
- return null;
+ return viewer;
}
- public abstract void setJalviewColourScheme(ColourSchemeI cs);
+ public void setViewer(JalviewStructureDisplayI v)
+ {
+ viewer = v;
+ }
/**
* Constructs and sends a command to align structures against a reference
* structure, based on one or more sequence alignments. May optionally return
- * an error or warning message for the alignment command.
- *
- * @param alignments
- * an array of alignments to process
- * @param structureIndices
- * an array of corresponding reference structures (index into pdb
- * file array); if a negative value is passed, the first PDB file
- * mapped to an alignment sequence is used as the reference for
- * superposition
- * @param hiddenCols
- * an array of corresponding hidden columns for each alignment
+ * an error or warning message for the alignment command(s).
+ *
+ * @param alignWith
+ * an array of one or more alignment views to process
* @return
*/
- public abstract String superposeStructures(AlignmentI[] alignments,
- int[] structureIndices, HiddenColumns[] hiddenCols);
+ public String superposeStructures(List<AlignmentViewPanel> alignWith)
+ {
+ String error = "";
+ String[] files = getStructureFiles();
+
+ if (!waitForFileLoad(files))
+ {
+ return null;
+ }
+ refreshPdbEntries();
+
+ for (AlignmentViewPanel view : alignWith)
+ {
+ AlignmentI alignment = view.getAlignment();
+ HiddenColumns hiddenCols = alignment.getHiddenColumns();
- public abstract void setBackgroundColour(Color col);
+ /*
+ * 'matched' bit i will be set for visible alignment columns i where
+ * all sequences have a residue with a mapping to their PDB structure
+ */
+ BitSet matched = new BitSet();
+ final int width = alignment.getWidth();
+ for (int m = 0; m < width; m++)
+ {
+ if (hiddenCols == null || hiddenCols.isVisible(m))
+ {
+ matched.set(m);
+ }
+ }
- protected abstract StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, AlignmentViewPanel avp);
+ SuperposeData[] structures = new SuperposeData[files.length];
+ for (int f = 0; f < files.length; f++)
+ {
+ structures[f] = new SuperposeData(width,
+ f + commandGenerator.getModelStartNo());
+ }
+
+ /*
+ * Calculate the superposable alignment columns ('matched'), and the
+ * corresponding structure residue positions (structures.pdbResNo)
+ */
+ int refStructure = findSuperposableResidues(alignment,
+ matched, structures);
+
+ /*
+ * require at least 4 positions to be able to execute superposition
+ */
+ int nmatched = matched.cardinality();
+ if (nmatched < MIN_POS_TO_SUPERPOSE)
+ {
+ String msg = MessageManager.formatMessage("label.insufficient_residues",
+ nmatched);
+ error += view.getViewName() + ": " + msg + "; ";
+ continue;
+ }
+
+ /*
+ * get a model of the superposable residues in the reference structure
+ */
+ AtomSpecModel refAtoms = getAtomSpec(structures[refStructure],
+ matched);
+
+ /*
+ * Show all as backbone before doing superposition(s)
+ * (residues used for matching will be shown as ribbon)
+ */
+ executeCommand(commandGenerator.showBackbone(), false);
+
+ /*
+ * superpose each (other) structure to the reference in turn
+ */
+ for (int i = 0; i < structures.length; i++)
+ {
+ if (i != refStructure)
+ {
+ AtomSpecModel atomSpec = getAtomSpec(structures[i], matched);
+ String commands = commandGenerator.superposeStructures(refAtoms,
+ atomSpec);
+ List<String> replies = executeCommands(true, commands);
+ for (String reply : replies)
+ {
+ // return this error (Chimera only) to the user
+ if (reply.toLowerCase().contains("unequal numbers of atoms"))
+ {
+ error += "; " + reply;
+ }
+ }
+ }
+ }
+ }
+
+ return error;
+ }
+
+ private AtomSpecModel getAtomSpec(SuperposeData superposeData,
+ BitSet matched)
+ {
+ AtomSpecModel model = new AtomSpecModel();
+ int nextColumnMatch = matched.nextSetBit(0);
+ while (nextColumnMatch != -1)
+ {
+ int pdbResNum = superposeData.pdbResNo[nextColumnMatch];
+ model.addRange(superposeData.modelNo, pdbResNum, pdbResNum,
+ superposeData.chain);
+ nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1);
+ }
+
+ return model;
+ }
/**
* returns the current sequenceRenderer that should be used to colour the
public abstract SequenceRenderer getSequenceRenderer(
AlignmentViewPanel alignment);
- protected abstract void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands);
+ /**
+ * Sends a command to the structure viewer to colour each chain with a
+ * distinct colour (to the extent supported by the viewer)
+ */
+ public void colourByChain()
+ {
+ colourBySequence = false;
+
+ // TODO: JAL-628 colour chains distinctly across all visible models
+
+ executeCommand(commandGenerator.colourByChain(), false,
+ COLOURING_STRUCTURES);
+ }
+
+ /**
+ * Sends a command to the structure viewer to colour each chain with a
+ * distinct colour (to the extent supported by the viewer)
+ */
+ public void colourByCharge()
+ {
+ colourBySequence = false;
+
+ executeCommand(commandGenerator.colourByCharge(), false,
+ COLOURING_STRUCTURES);
+ }
+
+ /**
+ * Sends a command to the structure to apply a colour scheme (defined in
+ * Jalview but not necessarily applied to the alignment), which defines a
+ * colour per residue letter. More complex schemes (e.g. that depend on
+ * consensus) cannot be used here and are ignored.
+ *
+ * @param cs
+ */
+ public void colourByJalviewColourScheme(ColourSchemeI cs)
+ {
+ colourBySequence = false;
+
+ if (cs == null || !cs.isSimple())
+ {
+ return;
+ }
+
+ /*
+ * build a map of {Residue3LetterCode, Color}
+ */
+ Map<String, Color> colours = new HashMap<>();
+ List<String> residues = ResidueProperties.getResidues(isNucleotide(),
+ false);
+ for (String resName : residues)
+ {
+ char res = resName.length() == 3
+ ? ResidueProperties.getSingleCharacterCode(resName)
+ : resName.charAt(0);
+ Color colour = cs.findColour(res, 0, null, null, 0f);
+ colours.put(resName, colour);
+ }
+
+ /*
+ * pass to the command constructor, and send the command
+ */
+ String cmd = commandGenerator.colourByResidues(colours);
+ executeCommand(cmd, false, COLOURING_STRUCTURES);
+ }
+
+ public void setBackgroundColour(Color col)
+ {
+ String cmd = commandGenerator.setBackgroundColour(col);
+ executeCommand(cmd, false, null);
+ }
+
+ /**
+ * Sends one command to the structure viewer. If {@code getReply} is true, the
+ * command is sent synchronously, otherwise in a deferred thread.
+ * <p>
+ * If a progress message is supplied, this is displayed before command
+ * execution, and removed afterwards.
+ *
+ * @param cmd
+ * @param getReply
+ * @param msg
+ * @return
+ */
+ private List<String> executeCommand(String cmd, boolean getReply,
+ String msg)
+ {
+ if (getReply)
+ {
+ return executeSynchronous(cmd, msg, getReply);
+ }
+ else
+ {
+ executeAsynchronous(cmd, msg);
+ return null;
+ }
+ }
+
+ /**
+ * Sends the command in the current thread. If a message is supplied, this is
+ * shown before the thread is started, and removed when it completes. May
+ * return a reply to the command if requested.
+ *
+ * @param cmd
+ * @param msg
+ * @param getReply
+ * @return
+ */
+ private List<String> executeSynchronous(String cmd, String msg, boolean getReply)
+ {
+ final JalviewStructureDisplayI theViewer = getViewer();
+ final long handle = msg == null ? 0 : theViewer.startProgressBar(msg);
+ try
+ {
+ return executeCommand(cmd, getReply);
+ } finally
+ {
+ if (msg != null)
+ {
+ theViewer.stopProgressBar(null, handle);
+ }
+ }
+ }
+
+ /**
+ * Sends the command in a separate thread. If a message is supplied, this is
+ * shown before the thread is started, and removed when it completes. No value
+ * is returned.
+ *
+ * @param cmd
+ * @param msg
+ */
+ private void executeAsynchronous(String cmd, String msg)
+ {
+ final JalviewStructureDisplayI theViewer = getViewer();
+ final long handle = msg == null ? 0 : theViewer.startProgressBar(msg);
+
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ executeCommand(cmd, false);
+ } finally
+ {
+ if (msg != null)
+ {
+ theViewer.stopProgressBar(null, handle);
+ }
+ }
+ }
+ });
+ }
- public abstract void colourByChain();
+ protected abstract List<String> executeCommand(String command,
+ boolean getReply);
- public abstract void colourByCharge();
+ protected List<String> executeCommands(boolean getReply,
+ String... commands)
+ {
+ // todo: tidy this up
+ List<String> response = getReply ? new ArrayList<>() : null;
+ for (String cmd : commands)
+ {
+ List<String> replies = executeCommand(cmd, getReply);
+ if (getReply && replies != null)
+ {
+ response.addAll(replies);
+ }
+ }
+ return response;
+ }
/**
* colour any structures associated with sequences in the given alignment
String[] files = getStructureFiles();
SequenceRenderer sr = getSequenceRenderer(alignmentv);
+ Map<Object, AtomSpecModel> colourMap = buildColoursMap(ssm, files,
+ sequence, sr, alignmentv);
+
+ String[] colourBySequenceCommands = commandGenerator
+ .colourBySequence(colourMap);
+ executeCommands(false, colourBySequenceCommands);
+ }
+
+ /**
+ * Centre the display in the structure viewer
+ */
+ public void focusView()
+ {
+ executeCommand(commandGenerator.focusView(), false);
+ }
+
+ /**
+ * Generates and executes a command to show only specified chains in the
+ * structure viewer. The list of chains to show should contain entries
+ * formatted as "pdbid:chaincode".
+ *
+ * @param toShow
+ */
+ public void showChains(List<String> toShow)
+ {
+ // todo or reformat toShow list entries as modelNo:pdbId:chainCode ?
- StructureMappingcommandSet[] colourBySequenceCommands = getColourBySequenceCommands(
- files, sr, alignmentv);
- colourBySequence(colourBySequenceCommands);
+ /*
+ * Reformat the pdbid:chainCode values as modelNo:chainCode
+ * since this is what is needed to construct the viewer command
+ * todo: find a less messy way to do this
+ */
+ List<String> showThese = new ArrayList<>();
+ for (String chainId : toShow)
+ {
+ String[] tokens = chainId.split("\\:");
+ if (tokens.length == 2)
+ {
+ String pdbFile = getFileForChain(chainId);
+ int modelNo = getModelNoForFile(pdbFile);
+ String model = modelNo == -1 ? "" : String.valueOf(modelNo);
+ showThese.add(model + ":" + tokens[1]);
+ }
+ }
+ executeCommand(commandGenerator.showChains(showThese), false);
}
+ /**
+ * Answers the structure viewer's model number given a PDB file name. Returns
+ * -1 if model number is not found.
+ *
+ * @param chainId
+ * @return
+ */
+ protected abstract int getModelNoForFile(String chainId);
+
public boolean hasFileLoadingError()
{
return fileLoadingError != null && fileLoadingError.length() > 0;
}
- public abstract jalview.api.FeatureRenderer getFeatureRenderer(
- AlignmentViewPanel alignment);
+ /**
+ * Returns the FeatureRenderer for the given alignment view, or null if
+ * feature display is turned off in the view.
+ *
+ * @param avp
+ * @return
+ */
+ public FeatureRenderer getFeatureRenderer(AlignmentViewPanel avp)
+ {
+ AlignmentViewPanel ap = (avp == null) ? getViewer().getAlignmentPanel()
+ : avp;
+ return ap.getAlignViewport().isShowSequenceFeatures()
+ ? 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);
+ }
+
+ @Override
+ public void updateColours(Object source)
+ {
+ AlignmentViewPanel ap = (AlignmentViewPanel) source;
+ // ignore events from panels not used to colour this view
+ if (!getViewer().isUsedForColourBy(ap))
+ {
+ return;
+ }
+ if (!isLoadingFromArchive())
+ {
+ colourBySequence(ap);
+ }
+ }
+
+ public StructureCommandsI getCommandGenerator()
+ {
+ return commandGenerator;
+ }
+
+ protected abstract ViewerType getViewerType();
+
+ /**
+ * Send a structure viewer command asynchronously in a new thread. If the
+ * progress message is not null, display this message while the command is
+ * executing.
+ *
+ * @param command
+ * @param progressMsg
+ */
+ protected void sendAsynchronousCommand(String command, String progressMsg)
+ {
+ final JalviewStructureDisplayI theViewer = getViewer();
+ final long handle = progressMsg == null ? 0
+ : theViewer.startProgressBar(progressMsg);
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ try
+ {
+ executeCommand(command, false);
+ } finally
+ {
+ if (progressMsg != null)
+ {
+ theViewer.stopProgressBar(null, handle);
+ }
+ }
+ }
+ });
+
+ }
+
+ /**
+ * Builds a data structure which records mapped structure residues for each
+ * colour. From this we can easily generate the viewer commands for colour by
+ * sequence. Constructs and returns a map of {@code Color} to
+ * {@code AtomSpecModel}, where the atomspec model holds
+ *
+ * <pre>
+ * Model numbers
+ * Chains
+ * Residue positions
+ * </pre>
+ *
+ * Ordering is by order of addition (for colours), natural ordering (for
+ * models and chains)
+ *
+ * @param ssm
+ * @param files
+ * @param sequence
+ * @param sr
+ * @param viewPanel
+ * @return
+ */
+ protected Map<Object, AtomSpecModel> 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<Object, AtomSpecModel> colourMap = new LinkedHashMap<>();
+ Color lastColour = null;
+
+ for (int pdbfnum = 0; pdbfnum < files.length; pdbfnum++)
+ {
+ final int modelNumber = pdbfnum + commandGenerator.getModelStartNo();
+ 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, modelNumber,
+ startPos, lastPos, lastChain);
+ }
+ startPos = pos;
+ }
+ lastColour = colour;
+ lastPos = pos;
+ lastChain = chain;
+ }
+ // final colour range
+ if (lastColour != null)
+ {
+ addAtomSpecRange(colourMap, lastColour, modelNumber, 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
+ * <ul>
+ * <li>a colour, when building a 'colour structure by sequence' command</li>
+ * <li>a feature value, when building a 'set Chimera attributes from features'
+ * command</li>
+ * </ul>
+ *
+ * @param map
+ * @param value
+ * @param model
+ * @param startPos
+ * @param endPos
+ * @param chain
+ */
+ public static final void addAtomSpecRange(Map<Object, AtomSpecModel> 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);
+ }
}
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
return null;
}
}
+
+ /**
+ * do an HTTP GET with URL-Encoded parameters passed in the Query string
+ *
+ * @param url
+ * @param vals
+ * @return Reader containing content, if any, or null if no entity returned.
+ * @throws IOException
+ * @throws ClientProtocolException
+ * @throws Exception
+ */
+ public static BufferedReader doHttpGet(String url,
+ List<NameValuePair> vals, int connectionTimeoutMs,
+ int readTimeoutMs) throws ClientProtocolException, IOException
+ {
+ // todo use HttpClient 4.3 or later and class RequestConfig
+ HttpParams params = new BasicHttpParams();
+ params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
+ HttpVersion.HTTP_1_1);
+ if (connectionTimeoutMs > 0)
+ {
+ HttpConnectionParams.setConnectionTimeout(params,
+ connectionTimeoutMs);
+ }
+ if (readTimeoutMs > 0)
+ {
+ HttpConnectionParams.setSoTimeout(params, readTimeoutMs);
+ }
+ boolean first = true;
+ for (NameValuePair param : vals)
+ {
+ if (first)
+ {
+ url += "?";
+ }
+ else
+ {
+ url += "&";
+ }
+ url += param.getName();
+ url += "=";
+ url += param.getValue();
+ }
+ HttpClient httpclient = new DefaultHttpClient(params);
+ HttpGet httpGet = new HttpGet(url);
+ // UrlEncodedFormEntity ue = new UrlEncodedFormEntity(vals, "UTF-8");
+ // httpGet.setEntity(ue);
+ HttpResponse response = httpclient.execute(httpGet);
+ HttpEntity resEntity = response.getEntity();
+
+ if (resEntity != null)
+ {
+ BufferedReader r = new BufferedReader(
+ new InputStreamReader(resEntity.getContent()));
+ return r;
+ }
+ else
+ {
+ return null;
+ }
+ }
}
import jalview.gui.JvOptionPane;
import jalview.gui.SequenceRenderer;
import jalview.schemes.JalviewColourScheme;
+import jalview.structure.AtomSpecModel;
+import jalview.structure.StructureCommandsI;
import jalview.structure.StructureMapping;
-import jalview.structure.StructureMappingcommandSet;
import jalview.structure.StructureSelectionManager;
+import java.awt.Color;
import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
}
@Test(groups = { "Functional" })
- public void testGetColourBySequenceCommand_noFeatures()
- {
- SequenceI seq1 = new Sequence("seq1", "MHRSQTRALK");
- SequenceI seq2 = new Sequence("seq2", "MRLEITQSGD");
- AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
- AlignFrame af = new AlignFrame(al, 800, 500);
- SequenceRenderer sr = new SequenceRenderer(af.getViewport());
- SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } };
- String[] files = new String[] { "seq1.pdb", "seq2.pdb" };
- StructureSelectionManager ssm = new StructureSelectionManager();
-
- // need some mappings!
-
- StructureMappingcommandSet[] commands = JmolCommands
- .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
- }
-
- @Test(groups = { "Functional" })
public void testGetColourBySequenceCommands_hiddenColumns()
{
/*
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<Integer, int[]> map = new HashMap<Integer, int[]>();
+ HashMap<Integer, int[]> map = new HashMap<>();
for (int pos = 1; pos <= seq1.getLength(); pos++)
{
map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) });
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]"));
+ }
+
+ @Test(groups = "Functional")
+ public void testGetAtomSpec()
+ {
+ StructureCommandsI testee = new JmolCommands();
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(testee.getAtomSpec(model, false), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(testee.getAtomSpec(model, false), "2-4:A/1.1");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(testee.getAtomSpec(model, false), "2-4:A/1.1|8:A/1.1");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-4:A/1.1|8:A/1.1|5-7:B/1.1");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-5:A/1.1|8:A/1.1|5-7:B/1.1");
+ model.addRange(2, 1, 4, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-5:A/1.1|8:A/1.1|5-7:B/1.1|1-4:B/2.1");
+ model.addRange(2, 5, 9, "C");
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-5:A/1.1|8:A/1.1|5-7:B/1.1|1-4:B/2.1|5-9:C/2.1");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|5-9:C/2.1");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|5-9:C/2.1");
+ model.addRange(2, 3, 10, "C"); // subsumes 5-9
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|3-10:C/2.1");
+ model.addRange(5, 25, 35, " ");
+ assertEquals(testee.getAtomSpec(model, false),
+ "2-5:A/1.1|8:A/1.1|5-10:B/1.1|1-4:B/2.1|3-10:C/2.1|25-35:/5.1");
+
+ }
+
+ @Test(groups = { "Functional" })
+ public void testColourBySequence()
+ {
+ Map<Object, AtomSpecModel> map = new LinkedHashMap<>();
+ JmolCommands.addAtomSpecRange(map, Color.blue, 1, 2, 5, "A");
+ JmolCommands.addAtomSpecRange(map, Color.blue, 1, 7, 7, "B");
+ JmolCommands.addAtomSpecRange(map, Color.blue, 1, 9, 23, "A");
+ JmolCommands.addAtomSpecRange(map, Color.blue, 2, 1, 1, "A");
+ JmolCommands.addAtomSpecRange(map, Color.blue, 2, 4, 7, "B");
+ JmolCommands.addAtomSpecRange(map, Color.yellow, 2, 8, 8, "A");
+ JmolCommands.addAtomSpecRange(map, Color.yellow, 2, 3, 5, "A");
+ JmolCommands.addAtomSpecRange(map, Color.red, 1, 3, 5, "A");
+ JmolCommands.addAtomSpecRange(map, Color.red, 1, 6, 9, "A");
+
+ // Colours should appear in the Jmol command in the order in which
+ // they were added; within colour, by model, by chain, ranges in start order
+ String[] commands = new JmolCommands().colourBySequence(map);
+ assertEquals(commands.length, 1);
+ String expected = "select 2-5:A/1.1|9-23:A/1.1|7:B/1.1|1:A/2.1|4-7:B/2.1;color[0,0,255]; "
+ + "select 3-5:A/2.1|8:A/2.1;color[255,255,0]; "
+ + "select 3-9:A/1.1;color[255,0,0]";
+ assertEquals(commands[0], expected);
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSuperposeStructures()
+ {
+ StructureCommandsI testee = new JmolCommands();
+ AtomSpecModel ref = new AtomSpecModel();
+ ref.addRange(1, 12, 14, "A");
+ ref.addRange(1, 18, 18, "B");
+ ref.addRange(1, 22, 23, "B");
+ AtomSpecModel toAlign = new AtomSpecModel();
+ toAlign.addRange(2, 15, 17, "B");
+ toAlign.addRange(2, 20, 21, "B");
+ toAlign.addRange(2, 22, 22, "C");
+ String command = testee.superposeStructures(ref, toAlign);
+ String refSpec = "12-14:A/1.1|18:B/1.1|22-23:B/1.1";
+ String toAlignSpec = "15-17:B/2.1|20-21:B/2.1|22:C/2.1";
+ String expected = String.format(
+ "compare {2.1} {1.1} SUBSET {(*.CA | *.P) and conformation=1} ATOMS {%s}{%s} ROTATE TRANSLATE ;select %s|%s;cartoons",
+ toAlignSpec, refSpec, toAlignSpec, refSpec);
+ assertEquals(command, expected);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetModelStartNo()
+ {
+ StructureCommandsI testee = new JmolCommands();
+ assertEquals(testee.getModelStartNo(), 1);
}
}
+++ /dev/null
-package jalview.ext.rbvi.chimera;
-
-import static org.testng.Assert.assertEquals;
-
-import org.testng.annotations.Test;
-
-public class AtomSpecModelTest
-{
- @Test(groups = "Functional")
- public void testGetAtomSpec()
- {
- AtomSpecModel model = new AtomSpecModel();
- assertEquals(model.getAtomSpec(), "");
- model.addRange(1, 2, 4, "A");
- assertEquals(model.getAtomSpec(), "#1:2-4.A");
- model.addRange(1, 8, 8, "A");
- assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A");
- model.addRange(1, 5, 7, "B");
- assertEquals(model.getAtomSpec(), "#1:2-4.A,8.A,5-7.B");
- model.addRange(1, 3, 5, "A");
- assertEquals(model.getAtomSpec(), "#1:2-5.A,8.A,5-7.B");
- model.addRange(0, 1, 4, "B");
- assertEquals(model.getAtomSpec(), "#0:1-4.B|#1:2-5.A,8.A,5-7.B");
- model.addRange(0, 5, 9, "C");
- assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B");
- model.addRange(1, 8, 10, "B");
- assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
- model.addRange(1, 8, 9, "B");
- assertEquals(model.getAtomSpec(), "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
- model.addRange(0, 3, 10, "C"); // subsumes 5-9
- assertEquals(model.getAtomSpec(), "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
- model.addRange(5, 25, 35, " "); // empty chain code - e.g. from homology
- // modelling
- assertEquals(model.getAtomSpec(),
- "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35.");
-
- }
-
-}
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
-import jalview.datamodel.Alignment;
-import jalview.datamodel.AlignmentI;
-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 jalview.structure.AtomSpecModel;
+import jalview.structure.StructureCommandsI;
import java.awt.Color;
import java.util.HashMap;
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()
+ public void testColourBySequence()
{
- Map<Object, AtomSpecModel> map = new LinkedHashMap<Object, AtomSpecModel>();
+ Map<Object, AtomSpecModel> map = new LinkedHashMap<>();
ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 2, 5, "A");
ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 7, 7, "B");
ChimeraCommands.addAtomSpecRange(map, Color.blue, 0, 9, 23, "A");
// 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).get(0);
+ String[] commands = new ChimeraCommands().colourBySequence(map);
+ assertEquals(commands.length, 1);
assertEquals(
- command,
+ commands[0],
"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");
}
@Test(groups = { "Functional" })
- public void testBuildSetAttributeCommands()
+ public void testSetAttributes()
{
/*
* make a map of { featureType, {featureValue, {residue range specification } } }
*/
- Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<String, Map<Object, AtomSpecModel>>();
- Map<Object, AtomSpecModel> featureValues = new HashMap<Object, AtomSpecModel>();
+ Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<>();
+ Map<Object, AtomSpecModel> featureValues = new HashMap<>();
/*
* start with just one feature/value...
featuresMap.put("chain", featureValues);
ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 8, 20, "A");
- List<String> commands = ChimeraCommands
- .buildSetAttributeCommands(featuresMap);
- assertEquals(1, commands.size());
+ ChimeraCommands commandGenerator = new ChimeraCommands();
+ String[] commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(1, commands.length);
/*
* 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[0], "setattr res jv_chain 'X' #0:8-20.A");
// add same feature value, overlapping range
ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 3, 9, "A");
// same feature value, contiguous range
ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 21, 25, "A");
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
- assertEquals(1, commands.size());
- assertEquals(commands.get(0), "setattr r jv_chain 'X' #0:3-25.A");
+ commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(1, commands.length);
+ assertEquals(commands[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");
// same feature value and chain, different model
ChimeraCommands.addAtomSpecRange(featureValues, "X", 1, 26, 30, "A");
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
- assertEquals(1, commands.size());
- assertEquals(commands.get(0),
- "setattr r jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A");
+ commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(1, commands.length);
+ String expected1 = "setattr res jv_chain 'X' #0:3-25.A,21-25.B|#1:26-30.A";
+ assertEquals(commands[0],
+ expected1);
// same feature, different value
ChimeraCommands.addAtomSpecRange(featureValues, "Y", 0, 40, 50, "A");
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
- assertEquals(2, commands.size());
+ commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(2, commands.length);
// 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"));
+ // so test for the expected command in either order
+ assertTrue(
+ commands[0].equals(expected1) || commands[1].equals(expected1));
+ String expected2 = "setattr res jv_chain 'Y' #0:40-50.A";
+ assertTrue(
+ commands[0].equals(expected2) || commands[1].equals(expected2));
featuresMap.clear();
featureValues.clear();
"A");
// feature names are sanitised to change non-alphanumeric to underscore
// feature values are sanitised to encode single quote characters
- commands = ChimeraCommands.buildSetAttributeCommands(featuresMap);
- assertTrue(commands
- .contains("setattr r jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> 'ion!' #0:7-15.A"));
+ commands = commandGenerator.setAttributes(featuresMap);
+ String expected3 = "setattr res jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> 'ion!' #0:7-15.A";
+ assertTrue(
+ commands[0].equals(expected3) || commands[1].equals(expected3));
}
/**
"jv_helixColor_");
}
+ @Test(groups = "Functional")
+ public void testGetAtomSpec()
+ {
+ StructureCommandsI testee = new ChimeraCommands();
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(testee.getAtomSpec(model, false), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(testee.getAtomSpec(model, false), "#1:2-4.A");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(testee.getAtomSpec(model, false), "#1:2-4.A,8.A");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(testee.getAtomSpec(model, false), "#1:2-4.A,8.A,5-7.B");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(testee.getAtomSpec(model, false), "#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 1, 4, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0:1-4.B|#1:2-5.A,8.A,5-7.B");
+ model.addRange(0, 5, 9, "C");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-7.B");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0:1-4.B,5-9.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(0, 3, 10, "C"); // subsumes 5-9
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B");
+ model.addRange(5, 25, 35, " "); // empty chain code - e.g. from homology
+ // modelling
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0:1-4.B,3-10.C|#1:2-5.A,8.A,5-10.B|#5:25-35.");
+
+ }
+
@Test(groups = { "Functional" })
- public void testGetColourBySequenceCommands_hiddenColumns()
+ public void testSuperposeStructures()
{
- /*
- * load these sequences, coloured by Strand propensity,
- * with columns 2-4 hidden
- */
- SequenceI seq1 = new Sequence("seq1", "MHRSQSSSGG");
- SequenceI seq2 = new Sequence("seq2", "MVRSNGGSSS");
- AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
- AlignFrame af = new AlignFrame(al, 800, 500);
- af.changeColour_actionPerformed(JalviewColourScheme.Strand.toString());
- ColumnSelection cs = new ColumnSelection();
- cs.addElement(2);
- cs.addElement(3);
- cs.addElement(4);
- af.getViewport().setColumnSelection(cs);
- af.hideSelColumns_actionPerformed(null);
- SequenceRenderer sr = new SequenceRenderer(af.getViewport());
- SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } };
- String[] files = new String[] { "seq1.pdb", "seq2.pdb" };
- StructureSelectionManager ssm = new StructureSelectionManager();
+ StructureCommandsI testee = new ChimeraCommands();
+ AtomSpecModel ref = new AtomSpecModel();
+ ref.addRange(1, 12, 14, "A");
+ ref.addRange(1, 18, 18, "B");
+ ref.addRange(1, 22, 23, "B");
+ AtomSpecModel toAlign = new AtomSpecModel();
+ toAlign.addRange(2, 15, 17, "B");
+ toAlign.addRange(2, 20, 21, "B");
+ toAlign.addRange(2, 22, 22, "C");
+ String command = testee.superposeStructures(ref, toAlign);
+ String refSpec = "#1:12-14.A,18.B,22-23.B@CA|P&~@.B-Z&~@.2-9";
+ String toAlignSpec = "#2:15-17.B,20-21.B,22.C@CA|P&~@.B-Z&~@.2-9";
+ String expected = String.format(
+ "match %s %s;~display all; chain @CA|P; ribbon %s|%s; focus",
+ refSpec, toAlignSpec, refSpec, toAlignSpec);
+ assertEquals(command, expected);
+ }
- /*
- * map residues 1-10 to residues 21-30 (atoms 105-150) in structures
- */
- HashMap<Integer, int[]> map = new HashMap<Integer, int[]>();
- for (int pos = 1; pos <= seq1.getLength(); pos++)
- {
- map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) });
- }
- StructureMapping sm1 = new StructureMapping(seq1, "seq1.pdb", "pdb1",
- "A", map, null);
- ssm.addStructureMapping(sm1);
- StructureMapping sm2 = new StructureMapping(seq2, "seq2.pdb", "pdb2",
- "B", map, null);
- ssm.addStructureMapping(sm2);
-
- StructureMappingcommandSet[] commands = ChimeraCommands
- .getColourBySequenceCommand(ssm, files, seqs, sr, af.alignPanel);
- assertEquals(1, commands.length);
- assertEquals(1, commands[0].commands.length);
- String theCommand = commands[0].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
- assertTrue(theCommand.contains("color #60609f #0:22.A"));
- // V colour is #ffff00
- assertTrue(theCommand.contains("color #ffff00 #1:22.B"));
- // hidden columns are Gray (128, 128, 128)
- assertTrue(theCommand.contains("color #808080 #0:23-25.A|#1:23-25.B"));
- // S and G are both coloured #4949b6
- assertTrue(theCommand.contains("color #4949b6 #0:26-30.A|#1:26-30.B"));
+ @Test(groups = "Functional")
+ public void testGetAtomSpec_alphaOnly()
+ {
+ StructureCommandsI testee = new ChimeraCommands();
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(testee.getAtomSpec(model, true), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#1:2-4.A@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#1:2-4.A,8.A@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#1:2-4.A,8.A,5-7.B@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#1:2-5.A,8.A,5-7.B@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(0, 1, 4, "B");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0:1-4.B@CA|P&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-7.B@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(0, 5, 9, "C");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0:1-4.B,5-9.C@CA|P&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-7.B@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0:1-4.B,5-9.C@CA|P&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0:1-4.B,5-9.C@CA|P&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(0, 3, 10, "C"); // subsumes 5-9
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0:1-4.B,3-10.C@CA|P&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA|P&~@.B-Z&~@.2-9");
+ model.addRange(5, 25, 35, " "); // empty chain code
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0:1-4.B,3-10.C@CA|P&~@.B-Z&~@.2-9|#1:2-5.A,8.A,5-10.B@CA|P&~@.B-Z&~@.2-9|#5:25-35.@CA|P&~@.B-Z&~@.2-9");
+
+ }
+
+ @Test(groups = "Functional")
+ public void testGetModelStartNo()
+ {
+ StructureCommandsI testee = new ChimeraCommands();
+ assertEquals(testee.getModelStartNo(), 0);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetResidueSpec()
+ {
+ ChimeraCommands testee = new ChimeraCommands();
+ assertEquals(testee.getResidueSpec("ALA"), "::ALA");
+ }
+
+ @Test(groups = "Functional")
+ public void testShowBackbone()
+ {
+ ChimeraCommands testee = new ChimeraCommands();
+ assertEquals(testee.showBackbone(), "~display all;chain @CA|P");
+ }
+
+ @Test(groups = "Functional")
+ public void testOpenCommandFile()
+ {
+ ChimeraCommands testee = new ChimeraCommands();
+ assertEquals(testee.openCommandFile("nowhere"), "open cmd:nowhere");
+ }
+
+ @Test(groups = "Functional")
+ public void testSaveSession()
+ {
+ ChimeraCommands testee = new ChimeraCommands();
+ assertEquals(testee.saveSession("somewhere"), "save somewhere");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetColourCommand()
+ {
+ ChimeraCommands testee = new ChimeraCommands();
+ assertEquals(testee.getColourCommand("something", Color.MAGENTA),
+ "color #ff00ff something");
+ }
+
+ @Test(groups = "Functional")
+ public void testSetAttribute()
+ {
+ ChimeraCommands testee = new ChimeraCommands();
+ AtomSpecModel model = new AtomSpecModel();
+ model.addRange(1, 89, 92, "A");
+ model.addRange(2, 12, 20, "B");
+ model.addRange(2, 8, 9, "B");
+ assertEquals(testee.setAttribute("phi", "27.3", model),
+ "setattr res phi '27.3' #1:89-92.A|#2:8-9.B,12-20.B");
}
}
final StructureManager structureManager = new StructureManager(true);
ChimeraManager cm = new ChimeraManager(structureManager);
assertTrue("Couldn't launch chimera",
- cm.launchChimera(StructureManager.getChimeraPaths()));
+ cm.launchChimera(StructureManager.getChimeraPaths(false)));
assertTrue(cm.isChimeraLaunched()); // Chimera process is alive
// int n=0;
// not sure of the point of this is unless the tester is loading models
--- /dev/null
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ext.rbvi.chimera;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+import jalview.structure.AtomSpecModel;
+import jalview.structure.StructureCommandsI;
+
+import java.awt.Color;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.testng.annotations.Test;
+
+public class ChimeraXCommandsTest
+{
+ @Test(groups = { "Functional" })
+ public void testColourByCharge()
+ {
+ String cmd = new ChimeraXCommands().colourByCharge();
+ assertEquals(cmd,
+ "color white;color :ASP,GLU red;color :LYS,ARG blue;color :CYS yellow");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testColourByChain()
+ {
+ String cmd = new ChimeraXCommands().colourByChain();
+ assertEquals(cmd, "rainbow chain");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testFocusView()
+ {
+ String cmd = new ChimeraXCommands().focusView();
+ assertEquals(cmd, "view");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testColourBySequence()
+ {
+ Map<Object, AtomSpecModel> map = new LinkedHashMap<>();
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 1, 2, 5, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 1, 7, 7, "B");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 1, 9, 23, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 2, 1, 1, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.blue, 2, 4, 7, "B");
+ ChimeraCommands.addAtomSpecRange(map, Color.yellow, 2, 8, 8, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.yellow, 2, 3, 5, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.red, 1, 3, 5, "A");
+ ChimeraCommands.addAtomSpecRange(map, Color.red, 1, 6, 9, "A");
+
+ // 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[] commands = new ChimeraXCommands().colourBySequence(map);
+ assertEquals(commands.length, 1);
+ assertEquals(
+ commands[0],
+ "color #1/A:2-5,9-23/B:7|#2/A:1/B:4-7 #0000ff; color #2/A:3-5,8 #ffff00; color #1/A:3-9 #ff0000");
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSetAttributes()
+ {
+ /*
+ * make a map of { featureType, {featureValue, {residue range specification } } }
+ */
+ Map<String, Map<Object, AtomSpecModel>> featuresMap = new LinkedHashMap<>();
+ Map<Object, AtomSpecModel> featureValues = new HashMap<>();
+
+ /*
+ * start with just one feature/value...
+ */
+ featuresMap.put("chain", featureValues);
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 8, 20, "A");
+
+ ChimeraXCommands commandGenerator = new ChimeraXCommands();
+ String[] commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(commands.length, 1);
+
+ /*
+ * feature name gets a jv_ namespace prefix
+ * feature value is quoted in case it contains spaces
+ */
+ assertEquals(commands[0],
+ "setattr #0/A:8-20 res jv_chain 'X' create true");
+
+ // add same feature value, overlapping range
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 3, 9, "A");
+ // same feature value, contiguous range
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 21, 25, "A");
+ commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(commands.length, 1);
+ assertEquals(commands[0],
+ "setattr #0/A:3-25 res jv_chain 'X' create true");
+
+ // same feature value and model, different chain
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 0, 21, 25, "B");
+ // same feature value and chain, different model
+ ChimeraCommands.addAtomSpecRange(featureValues, "X", 1, 26, 30, "A");
+ commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(commands.length, 1);
+ String expected1 = "setattr #0/A:3-25/B:21-25|#1/A:26-30 res jv_chain 'X' create true";
+ assertEquals(commands[0], expected1);
+
+ // same feature, different value
+ ChimeraCommands.addAtomSpecRange(featureValues, "Y", 0, 40, 50, "A");
+ commands = commandGenerator.setAttributes(featuresMap);
+ assertEquals(2, commands.length);
+ // commands are ordered by feature type but not by value
+ // so test for the expected command in either order
+ assertTrue(
+ commands[0].equals(expected1) || commands[1].equals(expected1));
+ String expected2 = "setattr #0/A:40-50 res jv_chain 'Y' create true";
+ assertTrue(
+ commands[0].equals(expected2) || commands[1].equals(expected2));
+
+ featuresMap.clear();
+ featureValues.clear();
+ featuresMap.put("side-chain binding!", featureValues);
+ ChimeraCommands.addAtomSpecRange(featureValues,
+ "<html>metal <a href=\"http:a.b.c/x\"> 'ion!", 0, 7, 15,
+ "A");
+ // feature names are sanitised to change non-alphanumeric to underscore
+ // feature values are sanitised to encode single quote characters
+ commands = commandGenerator.setAttributes(featuresMap);
+ String expected3 = "setattr #0/A:7-15 res jv_side_chain_binding_ '<html>metal <a href=\"http:a.b.c/x\"> 'ion!' create true";
+ assertTrue(
+ commands[0].equals(expected3) || commands[1].equals(expected3));
+ }
+
+ @Test(groups = { "Functional" })
+ public void testSuperposeStructures()
+ {
+ StructureCommandsI testee = new ChimeraXCommands();
+ AtomSpecModel ref = new AtomSpecModel();
+ ref.addRange(1, 12, 14, "A");
+ ref.addRange(1, 18, 18, "B");
+ ref.addRange(1, 22, 23, "B");
+ AtomSpecModel toAlign = new AtomSpecModel();
+ toAlign.addRange(2, 15, 17, "B");
+ toAlign.addRange(2, 20, 21, "B");
+ toAlign.addRange(2, 22, 22, "C");
+ String command = testee.superposeStructures(ref, toAlign);
+ String refSpec = "#1/A:12-14/B:18,22-23";
+ String toAlignSpec = "#2/B:15-17,20-21/C:22";
+
+ /*
+ * superposition arguments include AlphaCarbon restriction,
+ * ribbon command does not
+ */
+ String expected = String.format(
+ "align %s@CA|P toAtoms %s@CA|P; ribbon %s|%s; view",
+ refSpec, toAlignSpec, refSpec, toAlignSpec);
+ assertEquals(command, expected);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetAtomSpec()
+ {
+ StructureCommandsI testee = new ChimeraXCommands();
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(testee.getAtomSpec(model, false), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(testee.getAtomSpec(model, false), "#1/A:2-4");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(testee.getAtomSpec(model, false), "#1/A:2-4,8");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(testee.getAtomSpec(model, false), "#1/A:2-4,8/B:5-7");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(testee.getAtomSpec(model, false), "#1/A:2-5,8/B:5-7");
+ model.addRange(0, 1, 4, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0/B:1-4|#1/A:2-5,8/B:5-7");
+ model.addRange(0, 5, 9, "C");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0/B:1-4/C:5-9|#1/A:2-5,8/B:5-7");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0/B:1-4/C:5-9|#1/A:2-5,8/B:5-10");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0/B:1-4/C:5-9|#1/A:2-5,8/B:5-10");
+ model.addRange(0, 3, 10, "C"); // subsumes 5-9
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0/B:1-4/C:3-10|#1/A:2-5,8/B:5-10");
+ model.addRange(5, 25, 35, " ");
+ assertEquals(testee.getAtomSpec(model, false),
+ "#0/B:1-4/C:3-10|#1/A:2-5,8/B:5-10|#5/:25-35");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetAtomSpec_alphaOnly()
+ {
+ StructureCommandsI testee = new ChimeraXCommands();
+ AtomSpecModel model = new AtomSpecModel();
+ assertEquals(testee.getAtomSpec(model, true), "");
+ model.addRange(1, 2, 4, "A");
+ assertEquals(testee.getAtomSpec(model, true), "#1/A:2-4@CA|P");
+ model.addRange(1, 8, 8, "A");
+ assertEquals(testee.getAtomSpec(model, true), "#1/A:2-4,8@CA|P");
+ model.addRange(1, 5, 7, "B");
+ assertEquals(testee.getAtomSpec(model, true), "#1/A:2-4,8/B:5-7@CA|P");
+ model.addRange(1, 3, 5, "A");
+ assertEquals(testee.getAtomSpec(model, true), "#1/A:2-5,8/B:5-7@CA|P");
+ model.addRange(0, 1, 4, "B");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0/B:1-4@CA|P|#1/A:2-5,8/B:5-7@CA|P");
+ model.addRange(0, 5, 9, "C");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0/B:1-4/C:5-9@CA|P|#1/A:2-5,8/B:5-7@CA|P");
+ model.addRange(1, 8, 10, "B");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0/B:1-4/C:5-9@CA|P|#1/A:2-5,8/B:5-10@CA|P");
+ model.addRange(1, 8, 9, "B");
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0/B:1-4/C:5-9@CA|P|#1/A:2-5,8/B:5-10@CA|P");
+ model.addRange(0, 3, 10, "C"); // subsumes 5-9
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0/B:1-4/C:3-10@CA|P|#1/A:2-5,8/B:5-10@CA|P");
+ model.addRange(5, 25, 35, " "); // empty chain code
+ assertEquals(testee.getAtomSpec(model, true),
+ "#0/B:1-4/C:3-10@CA|P|#1/A:2-5,8/B:5-10@CA|P|#5/:25-35@CA|P");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetModelStartNo()
+ {
+ StructureCommandsI testee = new ChimeraXCommands();
+ assertEquals(testee.getModelStartNo(), 1);
+ }
+
+ @Test(groups = "Functional")
+ public void testGetResidueSpec()
+ {
+ ChimeraCommands testee = new ChimeraXCommands();
+ assertEquals(testee.getResidueSpec("ALA"), ":ALA");
+ }
+
+ @Test(groups = "Functional")
+ public void testShowBackbone()
+ {
+ ChimeraCommands testee = new ChimeraXCommands();
+ assertEquals(testee.showBackbone(), "~display all;show @CA|P pbonds");
+ }
+
+ @Test(groups = "Functional")
+ public void testOpenCommandFile()
+ {
+ ChimeraCommands testee = new ChimeraXCommands();
+ assertEquals(testee.openCommandFile("nowhere"), "open nowhere");
+ }
+
+ @Test(groups = "Functional")
+ public void testSaveSession()
+ {
+ ChimeraCommands testee = new ChimeraXCommands();
+ assertEquals(testee.saveSession("somewhere"), "save session somewhere");
+ }
+
+ @Test(groups = "Functional")
+ public void testGetColourCommand()
+ {
+ ChimeraCommands testee = new ChimeraXCommands();
+ assertEquals(testee.getColourCommand("something", Color.MAGENTA),
+ "color something #ff00ff");
+ }
+
+ @Test(groups = "Functional")
+ public void testSetAttribute()
+ {
+ ChimeraCommands testee = new ChimeraXCommands();
+ AtomSpecModel model = new AtomSpecModel();
+ model.addRange(1, 89, 92, "A");
+ model.addRange(2, 12, 20, "B");
+ model.addRange(2, 8, 9, "B");
+ assertEquals(testee.setAttribute("phi", "27.3", model),
+ "setattr #1/A:89-92|#2/B:8-9,12-20 res phi '27.3' create true");
+ }
+}
/*
* ask Chimera for its residue attribute names
*/
- List<String> reply = binding.sendChimeraCommand("list resattr", true);
+ List<String> 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"));
* 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
* 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"));
/*
* 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"));
assertEquals(binding.getPdbCount(), 1);
/*
- * 'perform' menu action to copy visible features to
- * attributes in Chimera
+ * 'perform' menu action to copy Chimera attributes
+ * to features in Jalview
*/
// TODO rename and pull up method to binding interface
// once functionality is added for Jmol as well
binding.copyStructureAttributesToFeatures("phi", af.getViewport()
.getAlignPanel());
fr.setVisible("phi");
- List<SequenceFeature> fs = fer2Arath.getFeatures().findFeatures(54, 54);
- assertEquals(fs.size(), 3);
- /*
- * order of returned features is not guaranteed
- */
- assertTrue("RESNUM".equals(fs.get(0).getType())
- || "RESNUM".equals(fs.get(1).getType())
- || "RESNUM".equals(fs.get(2).getType()));
+ List<SequenceFeature> fs = fer2Arath.getFeatures().findFeatures(54, 54,
+ "phi");
+ assertEquals(fs.size(), 2);
assertTrue(fs.contains(new SequenceFeature("phi", "A", 54, 54,
-131.0713f, "Chimera")));
assertTrue(fs.contains(new SequenceFeature("phi", "B", 54, 54,
int res, String featureType)
{
String where = "at position " + res;
- List<SequenceFeature> fs = seq.getFeatures().findFeatures(res, res);
+ List<SequenceFeature> fs = seq.getFeatures().findFeatures(res, res,
+ featureType);
- assertEquals(fs.size(), 2, where);
- assertEquals(fs.get(0).getType(), "RESNUM", where);
- SequenceFeature sf = fs.get(1);
+ assertEquals(fs.size(), 1, where);
+ SequenceFeature sf = fs.get(0);
assertEquals(sf.getType(), featureType, where);
assertEquals(sf.getFeatureGroup(), "Chimera", where);
assertEquals(sf.getDescription(), "True", where);
--- /dev/null
+package jalview.structure;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+
+import java.util.List;
+
+import org.testng.annotations.Test;
+
+public class AtomSpecModelTest
+{
+ @Test(groups="Functional")
+ public void testGetRanges()
+ {
+ AtomSpecModel model = new AtomSpecModel();
+ assertFalse(model.getModels().iterator().hasNext());
+ List<int[]> ranges = model.getRanges(1, "A");
+ assertTrue(ranges.isEmpty());
+
+ model.addRange(1, 12, 14, "A");
+ assertTrue(model.getRanges(1, "B").isEmpty());
+ assertTrue(model.getRanges(2, "A").isEmpty());
+ ranges = model.getRanges(1, "A");
+ assertEquals(ranges.size(), 1);
+ int[] range = ranges.get(0);
+ assertEquals(range[0], 12);
+ assertEquals(range[1], 14);
+
+ /*
+ * add some ranges; they should be coalesced and
+ * ordered when retrieved
+ */
+ model.addRange(1, 25, 25, "A");
+ model.addRange(1, 20, 24, "A");
+ model.addRange(1, 6, 8, "A");
+ model.addRange(1, 13, 18, "A");
+ model.addRange(1, 5, 6, "A");
+ ranges = model.getRanges(1, "A");
+ assertEquals(ranges.size(), 3);
+ range = ranges.get(0);
+ assertEquals(range[0], 5);
+ assertEquals(range[1], 8);
+ range = ranges.get(1);
+ assertEquals(range[0], 12);
+ assertEquals(range[1], 18);
+ range = ranges.get(2);
+ assertEquals(range[0], 20);
+ assertEquals(range[1], 25);
+ }
+}
public class AtomSpecTest
{
@Test
- public void testFromChimeraAtomSpec()
+ public void testFromChimeraAtomSpec_chimera()
{
- AtomSpec as = AtomSpec.fromChimeraAtomspec("#1:12.B");
+ AtomSpec as = AtomSpec.fromChimeraAtomspec("#1:12.B", false);
assertEquals(as.getModelNumber(), 1);
assertEquals(as.getPdbResNum(), 12);
assertEquals(as.getChain(), "B");
assertNull(as.getPdbFile());
// no model - default to zero
- as = AtomSpec.fromChimeraAtomspec(":13.C");
+ as = AtomSpec.fromChimeraAtomspec(":13.C", false);
assertEquals(as.getModelNumber(), 0);
assertEquals(as.getPdbResNum(), 13);
assertEquals(as.getChain(), "C");
assertNull(as.getPdbFile());
// model.submodel
- as = AtomSpec.fromChimeraAtomspec("#3.2:15");
+ as = AtomSpec.fromChimeraAtomspec("#3.2:15", false);
assertEquals(as.getModelNumber(), 3);
assertEquals(as.getPdbResNum(), 15);
assertEquals(as.getChain(), "");
String spec = "3:12.B";
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
fail("Expected exception for " + spec);
} catch (IllegalArgumentException e)
{
spec = "#3:12-14.B";
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
fail("Expected exception for " + spec);
} catch (IllegalArgumentException e)
{
spec = "";
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
fail("Expected exception for " + spec);
} catch (IllegalArgumentException e)
{
spec = null;
try
{
- as = AtomSpec.fromChimeraAtomspec(spec);
+ as = AtomSpec.fromChimeraAtomspec(spec, false);
+ fail("Expected exception for " + spec);
+ } catch (NullPointerException e)
+ {
+ // ok
+ }
+ }
+
+ @Test
+ public void testFromChimeraAtomSpec_chimeraX()
+ {
+ AtomSpec as = AtomSpec.fromChimeraAtomspec("#1/B:12", true);
+ assertEquals(as.getModelNumber(), 1);
+ assertEquals(as.getPdbResNum(), 12);
+ assertEquals(as.getChain(), "B");
+ assertNull(as.getPdbFile());
+
+ // no model - default to zero
+ as = AtomSpec.fromChimeraAtomspec("/C:13", true);
+ assertEquals(as.getModelNumber(), 0);
+ assertEquals(as.getPdbResNum(), 13);
+ assertEquals(as.getChain(), "C");
+ assertNull(as.getPdbFile());
+
+ // model.submodel
+ as = AtomSpec.fromChimeraAtomspec("#3.2/:15", true);
+ assertEquals(as.getModelNumber(), 3);
+ assertEquals(as.getPdbResNum(), 15);
+ assertEquals(as.getChain(), "");
+ assertNull(as.getPdbFile());
+
+ String spec = "3:12.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "#3:12-14.B";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = "";
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
+ fail("Expected exception for " + spec);
+ } catch (IllegalArgumentException e)
+ {
+ // ok
+ }
+
+ spec = null;
+ try
+ {
+ as = AtomSpec.fromChimeraAtomspec(spec, true);
fail("Expected exception for " + spec);
} catch (NullPointerException e)
{
acf3.addMap(new Sequence("s3", "ttt"), new Sequence("p3", "p"),
new MapList(new int[] { 1, 3 }, new int[] { 1, 1 }, 1, 1));
- List<AlignedCodonFrame> set1 = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> set1 = new ArrayList<>();
set1.add(acf1);
set1.add(acf2);
- List<AlignedCodonFrame> set2 = new ArrayList<AlignedCodonFrame>();
+ List<AlignedCodonFrame> set2 = new ArrayList<>();
set2.add(acf2);
set2.add(acf3);
assertEquals(1, pmap.getSeqs().size());
assertEquals("4IM2|A", pmap.getSeqs().get(0).getName());
- List<int[]> structuremap1 = new ArrayList(
+ List<int[]> structuremap1 = new ArrayList<>(
sm.getMapping(P4IM2_MISSING)[0]
.getPDBResNumRanges(seq.getStart(), seq.getEnd()));
// 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[][]
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);
}
}
*/
package jalview.structures.models;
+import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertFalse;
-import static org.testng.AssertJUnit.assertEquals;
-import static org.testng.AssertJUnit.assertTrue;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
import jalview.api.AlignmentViewPanel;
-import jalview.api.FeatureRenderer;
import jalview.api.SequenceRenderer;
import jalview.datamodel.Alignment;
import jalview.datamodel.AlignmentI;
-import jalview.datamodel.HiddenColumns;
+import jalview.datamodel.ColumnSelection;
import jalview.datamodel.PDBEntry;
import jalview.datamodel.PDBEntry.Type;
import jalview.datamodel.Sequence;
import jalview.datamodel.SequenceI;
+import jalview.ext.rbvi.chimera.ChimeraCommands;
+import jalview.gui.AlignFrame;
import jalview.gui.JvOptionPane;
+import jalview.gui.StructureViewer.ViewerType;
import jalview.io.DataSourceType;
import jalview.io.FileFormats;
-import jalview.schemes.ColourSchemeI;
+import jalview.schemes.JalviewColourScheme;
import jalview.structure.AtomSpec;
-import jalview.structure.StructureMappingcommandSet;
+import jalview.structure.AtomSpecModel;
+import jalview.structure.StructureCommandsI.SuperposeData;
+import jalview.structure.StructureMapping;
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;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import junit.extensions.PA;
+
/**
* Unit tests for non-abstract methods of abstract base class
*
@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;
- }
-
- @Override
- 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<AtomSpec> atoms)
{
- // TODO Auto-generated method stub
-
}
@Override
public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
{
- // TODO Auto-generated method stub
return null;
}
-
+
@Override
- public FeatureRenderer getFeatureRenderer(AlignmentViewPanel alignment)
+ protected List<String> executeCommand(String command,
+ boolean getReply)
{
- // TODO Auto-generated method stub
return null;
}
-
+
@Override
- protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, AlignmentViewPanel avp)
+ protected int getModelNoForFile(String chainId)
{
- // TODO Auto-generated method stub
- return null;
+ return 0;
}
-
+
@Override
- public List<String> getChainNames()
+ protected ViewerType getViewerType()
{
- // 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()
- {
- // TODO Auto-generated method stub
-
- }
};
String[][] chains = binder.getChains();
assertFalse(chains == null || chains[0] == null,
"No chains discovered by binding");
- assertEquals(2, chains[0].length);
- assertEquals("A", chains[0][0]);
- assertEquals("B", chains[0][1]);
+ assertEquals(chains[0].length, 2);
+ assertEquals(chains[0][0], "A");
+ assertEquals(chains[0][1], "B");
}
AAStructureBindingModel testee;
ssm.setMapping(new SequenceI[] { seq3 }, null, PDB_3,
DataSourceType.PASTE, null);
- testee = new AAStructureBindingModel(ssm, pdbFiles, seqs, null)
+ testee = newBindingModel(pdbFiles, seqs, ssm);
+ }
+
+ /**
+ * A helper method to construct the test target object
+ *
+ * @param pdbFiles
+ * @param seqs
+ * @param ssm
+ */
+ protected AAStructureBindingModel newBindingModel(PDBEntry[] pdbFiles,
+ SequenceI[][] seqs,
+ StructureSelectionManager ssm)
+ {
+ AAStructureBindingModel model = new AAStructureBindingModel(ssm,
+ pdbFiles, seqs, null)
{
@Override
public String[] getStructureFiles()
}
@Override
- public List<String> getChainNames()
- {
- return null;
- }
-
- @Override
- public void setJalviewColourScheme(ColourSchemeI cs)
- {
- }
-
- @Override
- public String superposeStructures(AlignmentI[] als, int[] alm,
- HiddenColumns[] alc)
- {
- return null;
- }
-
- @Override
- public void setBackgroundColour(Color col)
- {
- }
-
- @Override
- protected StructureMappingcommandSet[] getColourBySequenceCommands(
- String[] files, SequenceRenderer sr, AlignmentViewPanel avp)
- {
- return null;
- }
-
- @Override
public SequenceRenderer getSequenceRenderer(
AlignmentViewPanel alignment)
{
}
@Override
- protected void colourBySequence(
- StructureMappingcommandSet[] colourBySequenceCommands)
- {
- }
-
- @Override
- public void colourByChain()
+ protected List<String> executeCommand(String command,
+ boolean getReply)
{
+ return null;
}
@Override
- public void colourByCharge()
+ protected int getModelNoForFile(String chainId)
{
+ return 0;
}
@Override
- public FeatureRenderer getFeatureRenderer(
- AlignmentViewPanel alignment)
+ protected ViewerType getViewerType()
{
return null;
}
};
+ PA.setValue(model, "commandGenerator", new ChimeraCommands());
+ return model;
}
/**
SuperposeData[] structs = new SuperposeData[testee.getStructureFiles().length];
for (int i = 0; i < structs.length; i++)
{
- structs[i] = testee.new SuperposeData(al.getWidth());
+ structs[i] = new SuperposeData(al.getWidth(), 0);
}
/*
* initialise BitSet of 'superposable columns' to true (would be false for
int refStructure = testee
.findSuperposableResidues(al, matched, structs);
- assertEquals(0, refStructure);
+ assertEquals(refStructure, 0);
/*
* only ungapped, structure-mapped columns are superposable
assertTrue(matched.get(4));
assertTrue(matched.get(5)); // gap in second sequence
- assertEquals("1YCS", structs[0].pdbId);
- assertEquals("3A6S", structs[1].pdbId);
- assertEquals("1OOT", structs[2].pdbId);
- assertEquals("A", structs[0].chain); // ? struct has chains A _and_ B
- assertEquals("B", structs[1].chain);
- assertEquals("A", structs[2].chain);
+ assertEquals(structs[0].pdbId, "1YCS");
+ assertEquals(structs[1].pdbId, "3A6S");
+ assertEquals(structs[2].pdbId, "1OOT");
+ assertEquals(structs[0].chain, "A"); // ? struct has chains A _and_ B
+ assertEquals(structs[1].chain, "B");
+ assertEquals(structs[2].chain, "A");
// the 0's for unsuperposable positions propagate down the columns:
- assertEquals("[0, 97, 98, 99, 100, 102]",
- Arrays.toString(structs[0].pdbResNo));
- assertEquals("[0, 2, 0, 3, 4, 5]", Arrays.toString(structs[1].pdbResNo));
- assertEquals("[0, 8, 0, 0, 10, 12]",
- Arrays.toString(structs[2].pdbResNo));
+ assertEquals(Arrays.toString(structs[0].pdbResNo),
+ "[0, 97, 98, 99, 100, 102]");
+ assertEquals(Arrays.toString(structs[1].pdbResNo),
+ "[0, 2, 0, 3, 4, 5]");
+ assertEquals(Arrays.toString(structs[2].pdbResNo),
+ "[0, 8, 0, 0, 10, 12]");
}
@Test(groups = { "Functional" })
SuperposeData[] structs = new SuperposeData[al.getHeight()];
for (int i = 0; i < structs.length; i++)
{
- structs[i] = testee.new SuperposeData(al.getWidth());
+ structs[i] = new SuperposeData(al.getWidth(), 0);
}
/*
* initialise BitSet of 'superposable columns' to true (would be false for
int refStructure = testee
.findSuperposableResidues(al, matched, structs);
- assertEquals(0, refStructure);
+ assertEquals(refStructure, 0);
// only ungapped, structure-mapped columns are not superposable
assertFalse(matched.get(0));
assertFalse(matched.get(4)); // superposable, but hidden, column
assertTrue(matched.get(5));
}
-}
+
+ @Test(groups = { "Functional" })
+ public void testBuildColoursMap()
+ {
+ /*
+ * load these sequences, coloured by Strand propensity,
+ * with columns 2-4 hidden
+ */
+ SequenceI seq1 = new Sequence("seq1", "MHRSQSSSGG");
+ SequenceI seq2 = new Sequence("seq2", "MVRSNGGSSS");
+ AlignmentI al = new Alignment(new SequenceI[] { seq1, seq2 });
+ AlignFrame af = new AlignFrame(al, 800, 500);
+ af.changeColour_actionPerformed(JalviewColourScheme.Strand.toString());
+ ColumnSelection cs = new ColumnSelection();
+ cs.addElement(2);
+ cs.addElement(3);
+ cs.addElement(4);
+ af.getViewport().setColumnSelection(cs);
+ af.hideSelColumns_actionPerformed(null);
+ SequenceRenderer sr = new jalview.gui.SequenceRenderer(
+ af.getViewport());
+ SequenceI[][] seqs = new SequenceI[][] { { seq1 }, { seq2 } };
+ String[] files = new String[] { "seq1.pdb", "seq2.pdb" };
+ PDBEntry[] pdbFiles = new PDBEntry[2];
+ pdbFiles[0] = new PDBEntry("PDB1", "A", Type.PDB, "INLINEPDB1");
+ pdbFiles[1] = new PDBEntry("PDB2", "B", Type.PDB, "INLINEPDB2");
+ StructureSelectionManager ssm = new StructureSelectionManager();
+
+ /*
+ * map residues 1-10 to residues 21-30 (atoms 105-150) in structures
+ */
+ HashMap<Integer, int[]> map = new HashMap<>();
+ for (int pos = 1; pos <= seq1.getLength(); pos++)
+ {
+ map.put(pos, new int[] { 20 + pos, 5 * (20 + pos) });
+ }
+ StructureMapping sm1 = new StructureMapping(seq1, "seq1.pdb", "pdb1",
+ "A", map, null);
+ ssm.addStructureMapping(sm1);
+ StructureMapping sm2 = new StructureMapping(seq2, "seq2.pdb", "pdb2",
+ "B", map, null);
+ ssm.addStructureMapping(sm2);
+
+ AAStructureBindingModel binding = newBindingModel(pdbFiles, seqs, ssm);
+
+ /*
+ * method under test builds a map of structures residues by colour
+ * verify the map holds what it should
+ */
+ Map<Object, AtomSpecModel> colours = binding.buildColoursMap(ssm, files,
+ seqs, sr, af.alignPanel);
+ ChimeraCommands helper = new ChimeraCommands();
+
+ /*
+ * M colour is #82827d (see strand.html help page)
+ * sequence residue 1 mapped to structure residue 21
+ */
+ Color mColor = new Color(0x82827d);
+ AtomSpecModel atomSpec = colours.get(mColor);
+ assertNotNull(atomSpec);
+ assertEquals(helper.getAtomSpec(atomSpec, false), "#0:21.A|#1:21.B");
+
+ /*
+ * H colour is #60609f, seq1.2 mapped to structure 0 residue 22
+ */
+ Color hColor = new Color(0x60609f);
+ atomSpec = colours.get(hColor);
+ assertNotNull(atomSpec);
+ assertEquals(helper.getAtomSpec(atomSpec, false), "#0:22.A");
+
+ /*
+ * V colour is #ffff00, seq2.2 mapped to structure 1 residue 22
+ */
+ Color vColor = new Color(0xffff00);
+ atomSpec = colours.get(vColor);
+ assertNotNull(atomSpec);
+ assertEquals(helper.getAtomSpec(atomSpec, false), "#1:22.B");
+
+ /*
+ * hidden columns are Gray (128, 128, 128)
+ * sequence positions 3-5 mapped to structure residues 23-25
+ */
+ Color gray = new Color(128, 128, 128);
+ atomSpec = colours.get(gray);
+ assertNotNull(atomSpec);
+ assertEquals(helper.getAtomSpec(atomSpec, false), "#0:23-25.A|#1:23-25.B");
+
+ /*
+ * S and G are both coloured #4949b6, structure residues 26-30
+ */
+ Color sgColour = new Color(0x4949b6);
+ atomSpec = colours.get(sgColour);
+ assertNotNull(atomSpec);
+ assertEquals(helper.getAtomSpec(atomSpec, false),
+ "#0:26-30.A|#1:26-30.B");
+ }
+}
\ No newline at end of file