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.SearchResultMatchI;
import jalview.datamodel.SearchResults;
-import jalview.datamodel.SearchResults.Match;
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;
*/
private long loadNotifiesHandled = 0;
+ private Thread chimeraMonitor;
+
/**
* Open a PDB structure file in Chimera and set up mappings from Jalview.
*
* @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();
}
/**
}
viewer = null;
+ if (chimeraMonitor != null)
+ {
+ chimeraMonitor.interrupt();
+ }
releaseUIResources();
}
/**
* 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;
}
/**
String cmd = "list residues attr '" + attName + "'";
List<String> residues = sendChimeraCommand(cmd, true);
- /*
- * Expect 0, 1 or more reply lines of the format (chi2 is attName):
- * residue id #0:5.A chi2 -155.000836316 index 5
- * or
- * residue id #0:6.A chi3 None
- *
- * We assume here that attributes on structure do not naturally convert
- * to ranges on sequence, i.e. we just set one feature per mapped position.
- *
- * To conflate positions, would need to first build a map
- * Map<String value, Map<Sequence seq, List<Integer position>>>
- * and then traverse it to find feature ranges.
- */
+
+ boolean featureAdded = createFeaturesForAttributes(attName, residues);
+ if (featureAdded)
+ {
+ alignmentPanel.getFeatureRenderer().featuresAdded();
+ }
+ }
+
+ /**
+ * Create features in Jalview for the given attribute name and structure
+ * residues.
+ *
+ * <pre>
+ * The residue list should be 0, 1 or more reply lines of the format:
+ * residue id #0:5.A isHelix -155.000836316 index 5
+ * or
+ * residue id #0:6.A isHelix None
+ * </pre>
+ *
+ * @param attName
+ * @param residues
+ * @return
+ */
+ protected boolean createFeaturesForAttributes(String attName,
+ List<String> residues)
+ {
boolean featureAdded = false;
String featureGroup = getViewerFeatureGroup();
spec.setPdbFile(pdbFile);
List<AtomSpec> atoms = Collections.singletonList(spec);
+
+ /*
+ * locate the mapped position in the alignment (if any)
+ */
SearchResults 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();
featureAdded |= seq.addSequenceFeature(sf);
}
}
- if (featureAdded)
- {
- alignmentPanel.getFeatureRenderer().featuresAdded();
- }
+ return featureAdded;
}
/**