X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fext%2Frbvi%2Fchimera%2FJalviewChimeraBinding.java;h=9a570fc46ed1d195904c8a73b831768c07c521bc;hb=799c26111d6936a2e70cb5f1fd7d7312311e6db9;hp=7e70fef79dd175cd10d66efd86f54d058be6c1c4;hpb=8e5fa38447bcb8541c71bd7491c16a96f80fabc2;p=jalview.git diff --git a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java index 7e70fef..9a570fc 100644 --- a/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java +++ b/src/jalview/ext/rbvi/chimera/JalviewChimeraBinding.java @@ -20,18 +20,21 @@ */ package jalview.ext.rbvi.chimera; +import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeatureRenderer; import jalview.api.SequenceRenderer; +import jalview.api.structures.JalviewStructureDisplayI; import jalview.bin.Cache; import jalview.datamodel.AlignmentI; import jalview.datamodel.ColumnSelection; import jalview.datamodel.PDBEntry; -import jalview.datamodel.SearchResults; -import jalview.datamodel.SearchResults.Match; +import jalview.datamodel.SearchResultMatchI; +import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceI; import jalview.httpserver.AbstractRequestHandler; +import jalview.io.DataSourceType; import jalview.schemes.ColourSchemeI; import jalview.schemes.ResidueProperties; import jalview.structure.AtomSpec; @@ -47,6 +50,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.net.BindException; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collections; import java.util.Hashtable; import java.util.LinkedHashMap; @@ -101,8 +105,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ private boolean loadingFinished = true; - public String fileLoadingError; - /* * Map of ChimeraModel objects keyed by PDB full local file name */ @@ -117,6 +119,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ private long loadNotifiesHandled = 0; + private Thread chimeraMonitor; + /** * Open a PDB structure file in Chimera and set up mappings from Jalview. * @@ -197,11 +201,41 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * @param protocol */ public JalviewChimeraBinding(StructureSelectionManager ssm, - PDBEntry[] pdbentry, SequenceI[][] sequenceIs, String protocol) + PDBEntry[] pdbentry, SequenceI[][] sequenceIs, DataSourceType protocol) { super(ssm, pdbentry, sequenceIs, protocol); - viewer = new ChimeraManager( - new ext.edu.ucsf.rbvi.strucviz2.StructureManager(true)); + viewer = new ChimeraManager(new StructureManager(true)); + } + + /** + * 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(); + chimeraMonitor = new Thread(new Runnable() + { + + @Override + public void run() + { + try + { + p.waitFor(); + JalviewStructureDisplayI display = getViewer(); + if (display != null) + { + display.closeViewer(false); + } + } catch (InterruptedException e) + { + // exit thread if Chimera Viewer is closed in Jalview + } + } + }); + chimeraMonitor.start(); } /** @@ -222,18 +256,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Construct a title string for the viewer window based on the data Jalview - * knows about - * - * @param verbose - * @return - */ - public String getViewerTitle(boolean verbose) - { - return getViewerTitle("Chimera", verbose); - } - - /** * Tells Chimera to display only the specified chains * * @param toshow @@ -288,9 +310,14 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } viewer = null; + if (chimeraMonitor != null) + { + chimeraMonitor.interrupt(); + } releaseUIResources(); } + @Override public void colourByChain() { colourBySequence = false; @@ -306,6 +333,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel *
  • all others - white
  • * */ + @Override public void colourByCharge() { colourBySequence = false; @@ -314,20 +342,10 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * Construct and send a command to align structures against a reference - * structure, based on one or more sequence alignments - * - * @param _alignment - * an array of alignments to process - * @param _refStructure - * 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 + * {@inheritDoc} */ - public void superposeStructures(AlignmentI[] _alignment, + @Override + public String superposeStructures(AlignmentI[] _alignment, int[] _refStructure, ColumnSelection[] _hiddenCols) { StringBuilder allComs = new StringBuilder(128); @@ -335,7 +353,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel if (!waitForFileLoad(files)) { - return; + return null; } refreshPdbEntries(); @@ -354,13 +372,16 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /* - * 'matched' array will hold 'true' for visible alignment columns where + * 'matched' bit i will be set for visible alignment columns i where * all sequences have a residue with a mapping to the PDB structure */ - boolean matched[] = new boolean[alignment.getWidth()]; - for (int m = 0; m < matched.length; m++) + BitSet matched = new BitSet(); + for (int m = 0; m < alignment.getWidth(); m++) { - matched[m] = (hiddenCols != null) ? hiddenCols.isVisible(m) : true; + if (hiddenCols == null || hiddenCols.isVisible(m)) + { + matched.set(m); + } } SuperposeData[] structures = new SuperposeData[files.length]; @@ -384,17 +405,11 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel refStructure = candidateRefStructure; } - int nmatched = 0; - for (boolean b : matched) - { - if (b) - { - nmatched++; - } - } + int nmatched = matched.cardinality(); if (nmatched < 4) { - // TODO: bail out here because superposition illdefined? + return MessageManager.formatMessage("label.insufficient_residues", + nmatched); } /* @@ -407,41 +422,41 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel int lpos = -1; boolean run = false; StringBuilder molsel = new StringBuilder(); - for (int r = 0; r < matched.length; r++) + + int nextColumnMatch = matched.nextSetBit(0); + while (nextColumnMatch != -1) { - if (matched[r]) + int pdbResNum = structures[pdbfnum].pdbResNo[nextColumnMatch]; + if (lpos != pdbResNum - 1) { - int pdbResNum = structures[pdbfnum].pdbResNo[r]; - if (lpos != pdbResNum - 1) + /* + * discontiguous - append last residue now + */ + if (lpos != -1) { - /* - * discontiguous - append last residue now - */ - if (lpos != -1) - { - molsel.append(String.valueOf(lpos)); - molsel.append(chainCd); - molsel.append(","); - } - run = false; + molsel.append(String.valueOf(lpos)); + molsel.append(chainCd); + molsel.append(","); } - else + run = false; + } + else + { + /* + * extending a contiguous run + */ + if (!run) { /* - * extending a contiguous run + * start the range selection */ - if (!run) - { - /* - * start the range selection - */ - molsel.append(String.valueOf(lpos)); - molsel.append("-"); - } - run = true; + molsel.append(String.valueOf(lpos)); + molsel.append("-"); } - lpos = pdbResNum; + run = true; } + lpos = pdbResNum; + nextColumnMatch = matched.nextSetBit(nextColumnMatch + 1); } /* @@ -517,6 +532,8 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel .append(";" + command.toString()); } } + + String error = null; if (selectioncom.length() > 0) { // TODO: visually distinguish regions that were superposed @@ -530,9 +547,17 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } allComs.append("; ~display all; chain @CA|P; ribbon ") .append(selectioncom.toString()).append("; focus"); - sendChimeraCommand(allComs.toString(), false); + List chimeraReplies = sendChimeraCommand(allComs.toString(), + true); + for (String reply : chimeraReplies) + { + if (reply.toLowerCase().contains("unequal numbers of atoms")) + { + error = reply; + } + } } - + return error; } /** @@ -568,23 +593,29 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel /** * Launch Chimera, unless an instance linked to this object is already - * running. Returns true if chimera is successfully launched, or already + * running. Returns true if Chimera is successfully launched, or already * running, else false. * * @return */ public boolean launchChimera() { - if (!viewer.isChimeraLaunched()) - { - return viewer.launchChimera(StructureManager.getChimeraPaths()); - } if (viewer.isChimeraLaunched()) { return true; } - log("Failed to launch Chimera!"); - return false; + + boolean launched = viewer.launchChimera(StructureManager + .getChimeraPaths()); + if (launched) + { + startChimeraProcessMonitor(); + } + else + { + log("Failed to launch Chimera!"); + } + return launched; } /** @@ -648,39 +679,37 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel String progressMsg); /** - * colour any structures associated with sequences in the given alignment - * using the getFeatureRenderer() and getSequenceRenderer() renderers but only - * if colourBySequence is enabled. + * Sends a set of colour commands to the structure viewer + * + * @param colourBySequenceCommands */ - public void colourBySequence(boolean showFeatures, - jalview.api.AlignmentViewPanel alignmentv) + @Override + protected void colourBySequence( + StructureMappingcommandSet[] colourBySequenceCommands) { - if (!colourBySequence || !loadingFinished) - { - return; - } - if (getSsm() == null) + for (StructureMappingcommandSet cpdbbyseq : colourBySequenceCommands) { - return; - } - String[] files = getPdbFile(); - - SequenceRenderer sr = getSequenceRenderer(alignmentv); - - FeatureRenderer fr = null; - if (showFeatures) - { - fr = getFeatureRenderer(alignmentv); + for (String command : cpdbbyseq.commands) + { + sendAsynchronousCommand(command, COLOURING_CHIMERA); + } } - AlignmentI alignment = alignmentv.getAlignment(); + } - StructureMappingcommandSet colourBySequenceCommands = ChimeraCommands - .getColourBySequenceCommand(getSsm(), files, getSequence(), sr, - fr, alignment); - for (String command : colourBySequenceCommands.commands) - { - sendAsynchronousCommand(command, COLOURING_CHIMERA); - } + /** + * @param files + * @param sr + * @param fr + * @param viewport + * @return + */ + @Override + protected StructureMappingcommandSet[] getColourBySequenceCommands( + String[] files, SequenceRenderer sr, FeatureRenderer fr, + AlignViewportI viewport) + { + return ChimeraCommands.getColourBySequenceCommand(getSsm(), files, + getSequence(), sr, fr, viewport); } /** @@ -710,23 +739,20 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel // ////////////////////////// /** - * returns the current featureRenderer that should be used to colour the - * structures - * - * @param alignment - * - * @return - */ - public abstract FeatureRenderer getFeatureRenderer( - AlignmentViewPanel alignment); - - /** * 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 @@ -742,17 +768,6 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel } /** - * returns the current sequenceRenderer that should be used to colour the - * structures - * - * @param alignment - * - * @return - */ - public abstract SequenceRenderer getSequenceRenderer( - AlignmentViewPanel alignment); - - /** * 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. @@ -909,6 +924,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel return loadNotifiesHandled; } + @Override public void setJalviewColourScheme(ColourSchemeI cs) { colourBySequence = false; @@ -925,12 +941,14 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel List residueSet = ResidueProperties.getResidues(isNucleotide(), false); - for (String res : residueSet) + for (String resName : residueSet) { - Color col = cs.findColour(res.charAt(0)); + 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 + " ::" + res + ";"); + / normalise + " ::" + resName + ";"); } sendAsynchronousCommand(command.toString(), COLOURING_CHIMERA); @@ -981,6 +999,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * .html * @param col */ + @Override public void setBackgroundColour(Color col) { viewerCommandHistory(false); @@ -1085,8 +1104,9 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel * features visible in Jalview * * @param avp + * @return */ - public void sendFeaturesToViewer(AlignmentViewPanel avp) + public int sendFeaturesToViewer(AlignmentViewPanel avp) { // TODO refactor as required to pull up to an interface AlignmentI alignment = avp.getAlignment(); @@ -1097,13 +1117,13 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel */ if (fr == null) { - return; + return 0; } String[] files = getPdbFile(); if (files == null) { - return; + return 0; } StructureMappingcommandSet commandSet = ChimeraCommands @@ -1121,6 +1141,7 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel sendAsynchronousCommand(command, null); } } + return commands.length; } /** @@ -1253,14 +1274,14 @@ public abstract class JalviewChimeraBinding extends AAStructureBindingModel /* * locate the mapped position in the alignment (if any) */ - SearchResults sr = getSsm() + SearchResultsI sr = getSsm() .findAlignmentPositionsForStructurePositions(atoms); /* * expect one matched alignment position, or none * (if the structure position is not mapped) */ - for (Match m : sr.getResults()) + for (SearchResultMatchI m : sr.getResults()) { SequenceI seq = m.getSequence(); int start = m.getStart();