+ List<String> colourCommands = buildColourCommands(colourMap);
+
+ StructureMappingcommandSet cs = new StructureMappingcommandSet(
+ ChimeraCommands.class, null,
+ colourCommands.toArray(new String[0]));
+
+ 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
+ *
+ * <blockquote> color colorname #modelnumber:range.chain e.g. color #00ff00
+ * #0:2.B,4.B,9-12.B|#1:1.A,2-6.A,...
+ *
+ * @see http
+ * ://www.cgl.ucsf.edu/chimera/current/docs/UsersGuide/midas/frameatom_spec
+ * .html </pre>
+ *
+ * @param colourMap
+ * @return
+ */
+ protected static List<String> buildColourCommands(
+ Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> 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<String>();
+ StringBuilder sb = new StringBuilder(256);
+ boolean firstColour = true;
+ for (Color colour : colourMap.keySet())
+ {
+ String colourCode = ColorUtils.toTkCode(colour);
+ if (!firstColour)
+ {
+ sb.append("; ");
+ }
+ sb.append("color ").append(colourCode).append(" ");
+ firstColour = false;
+ boolean firstModelForColour = true;
+ final Map<Integer, Map<String, List<int[]>>> colourData = colourMap
+ .get(colour);
+ for (Integer model : colourData.keySet())
+ {
+ boolean firstPositionForModel = true;
+ if (!firstModelForColour)
+ {
+ sb.append("|");
+ }
+ firstModelForColour = false;
+ sb.append("#").append(model).append(":");
+
+ final Map<String, List<int[]>> modelData = colourData.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;
+ }
+ }
+ }
+ }
+ commands.add(sb.toString());
+ return commands;
+ }
+
+ /**
+ * <pre>
+ * Build a data structure which maps contiguous subsequences for each colour.
+ * This generates a data structure from which 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<Color, SortedMap<Integer, Map<String, List<int[]>>>> buildColoursMap(
+ StructureSelectionManager ssm, String[] files,
+ SequenceI[][] sequence, SequenceRenderer sr, FeatureRenderer fr,
+ AlignmentI alignment)
+ {
+ Map<Color, SortedMap<Integer, Map<String, List<int[]>>>> colourMap = new LinkedHashMap<Color, SortedMap<Integer, Map<String, List<int[]>>>>();
+ Color lastColour = null;