+ /**
+ * 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();
+
+ for (String residue : residues)
+ {
+ AtomSpec spec = null;
+ String[] tokens = residue.split(" ");
+ if (tokens.length < 5)
+ {
+ continue;
+ }
+ String atomSpec = tokens[2];
+ String attValue = tokens[4];
+
+ /*
+ * ignore 'None' (e.g. for phi) or 'False' (e.g. for isHelix)
+ */
+ if ("None".equalsIgnoreCase(attValue)
+ || "False".equalsIgnoreCase(attValue))
+ {
+ continue;
+ }
+
+ try
+ {
+ spec = AtomSpec.fromChimeraAtomspec(atomSpec);
+ } catch (IllegalArgumentException e)
+ {
+ System.err.println("Problem parsing atomspec " + atomSpec);
+ continue;
+ }
+
+ String chainId = spec.getChain();
+ String description = attValue;
+ float score = Float.NaN;
+ try
+ {
+ score = Float.valueOf(attValue);
+ description = chainId;
+ } catch (NumberFormatException e)
+ {
+ // was not a float value
+ }
+
+ String pdbFile = getPdbFileForModel(spec.getModelNumber());
+ spec.setPdbFile(pdbFile);
+
+ List<AtomSpec> atoms = Collections.singletonList(spec);
+
+ /*
+ * locate the mapped position in the alignment (if any)
+ */
+ SearchResultsI sr = getSsm()
+ .findAlignmentPositionsForStructurePositions(atoms);
+
+ /*
+ * expect one matched alignment position, or none
+ * (if the structure position is not mapped)
+ */
+ for (SearchResultMatchI m : sr.getResults())
+ {
+ SequenceI seq = m.getSequence();
+ int start = m.getStart();
+ int end = m.getEnd();
+ SequenceFeature sf = new SequenceFeature(attName, description,
+ start, end, score, featureGroup);
+ // todo: should SequenceFeature have an explicit property for chain?
+ // note: repeating the action shouldn't duplicate features
+ featureAdded |= seq.addSequenceFeature(sf);
+ }
+ }
+ return featureAdded;
+ }
+
+ /**
+ * Answers the feature group name to apply to features created in Jalview from
+ * Chimera attributes
+ *
+ * @return
+ */
+ protected String getViewerFeatureGroup()
+ {
+ // todo pull up to interface
+ return CHIMERA_FEATURE_GROUP;
+ }
+
+ public Hashtable<String, String> getChainFile()
+ {
+ return chainFile;
+ }
+
+ public List<ChimeraModel> getChimeraModelByChain(String chain)
+ {
+ return chimeraMaps.get(chainFile.get(chain));
+ }
+
+ public int getModelNoForChain(String chain)
+ {
+ List<ChimeraModel> foundModels = getChimeraModelByChain(chain);
+ if (foundModels != null && !foundModels.isEmpty())
+ {
+ return foundModels.get(0).getModelNumber();
+ }
+ return -1;
+ }
+
+ @Override
+ public void showStructures(AlignViewportI av, boolean refocus)
+ {
+ StringBuilder cmd = new StringBuilder(128);
+ cmd.append("~display; ~ribbon;");
+
+ AtomSpecModel model = getShownResidues(av);
+ String atomSpec = ChimeraCommands.getAtomSpec(model, this);
+
+ cmd.append("ribbon ").append(atomSpec);
+ if (!isShowAlignmentOnly())
+ {
+ cmd.append("; chain @CA|P");
+ }
+ if (refocus)
+ {
+ cmd.append("; focus");
+ }
+ sendChimeraCommand(cmd.toString(), false);
+ }
+
+ @Override
+ public int getModelForPdbFile(String fileName, int fileIndex)
+ {
+ if (chimeraMaps.containsKey(fileName))
+ {
+ List<ChimeraModel> models = chimeraMaps.get(fileName);
+ if (!models.isEmpty())
+ {
+ return models.get(0).getModelNumber();
+ }
+ }
+ return -1;
+ }