package ext.edu.ucsf.rbvi.strucviz2; import java.awt.Color; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeMap; import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType; /** * This class provides the implementation for the ChimeraModel, ChimeraChain, * and ChimeraResidue objects * * @author scooter * */ public class ChimeraModel implements ChimeraStructuralObject { private String name; // The name of this model private ModelType type; // The type of the model private int modelNumber; // The model number private int subModelNumber; // The sub-model number private Color modelColor = null; // The color of this model (from Chimera) private Object userData = null; // User data associated with this model private boolean selected = false; // The selected state of this model private TreeMap chainMap; // The list of chains // private TreeMap residueMap; // The list of residues private HashSet funcResidues; // List of functional residues /** * Constructor to create a model * * @param name * the name of this model * @param color * the model Color * @param modelNumber * the model number * @param subModelNumber * the sub-model number */ public ChimeraModel(String name, ModelType type, int modelNumber, int subModelNumber) { this.name = name; this.type = type; this.modelNumber = modelNumber; this.subModelNumber = subModelNumber; this.chainMap = new TreeMap(); this.funcResidues = new HashSet(); } /** * Constructor to create a model from the Chimera input line * * @param inputLine * Chimera input line from which to construct this model */ // TODO: [Optional] How to distinguish between PDB and MODBASE? // invoked when listing models: listm type molecule; lists level molecule // line = model id #0 type Molecule name 1ert public ChimeraModel(String inputLine) { this.name = ChimUtils.parseModelName(inputLine); // TODO: [Optional] Write a separate method to get model type if (name.startsWith("smiles")) { this.type = ModelType.SMILES; } else { this.type = ModelType.PDB_MODEL; } this.modelNumber = ChimUtils.parseModelNumber(inputLine)[0]; this.subModelNumber = ChimUtils.parseModelNumber(inputLine)[1]; this.chainMap = new TreeMap(); this.funcResidues = new HashSet(); } /** * Add a residue to this model * * @param residue * to add to the model */ public void addResidue(ChimeraResidue residue) { residue.setChimeraModel(this); // residueMap.put(residue.getIndex(), residue); String chainId = residue.getChainId(); if (chainId != null) { addResidue(chainId, residue); } else { addResidue("_", residue); } // Put it in our map so that we can return it in order // residueMap.put(residue.getIndex(), residue); } /** * Add a residue to a chain in this model. If the chain associated with * chainId doesn't exist, it will be created. * * @param chainId * to add the residue to * @param residue * to add to the chain */ public void addResidue(String chainId, ChimeraResidue residue) { ChimeraChain chain = null; if (!chainMap.containsKey(chainId)) { chain = new ChimeraChain(this.modelNumber, this.subModelNumber, chainId); chain.setChimeraModel(this); chainMap.put(chainId, chain); } else { chain = chainMap.get(chainId); } chain.addResidue(residue); } /** * Get the ChimeraModel (required for ChimeraStructuralObject interface) * * @return ChimeraModel */ public ChimeraModel getChimeraModel() { return this; } /** * Get the model color of this model * * @return model color of this model */ public Color getModelColor() { return this.modelColor; } /** * Set the color of this model * * @param color * Color of this model */ public void setModelColor(Color color) { this.modelColor = color; } /** * Return the name of this model * * @return model name */ public String getModelName() { return name; } /** * Set the name of this model * * @param name * model name */ public void setModelName(String name) { this.name = name; } /** * Get the model number of this model * * @return integer model number */ public int getModelNumber() { return modelNumber; } /** * Set the model number of this model * * @param modelNumber * integer model number */ public void setModelNumber(int modelNumber) { this.modelNumber = modelNumber; } /** * Get the sub-model number of this model * * @return integer sub-model number */ public int getSubModelNumber() { return subModelNumber; } /** * Set the sub-model number of this model * * @param subModelNumber * integer model number */ public void setSubModelNumber(int subModelNumber) { this.subModelNumber = subModelNumber; } public ModelType getModelType() { return type; } public void setModelType(ModelType type) { this.type = type; } public HashSet getFuncResidues() { return funcResidues; } public void setFuncResidues(List residues) { for (String residue : residues) { for (ChimeraChain chain : getChains()) { if (residue.indexOf("-") > 0) { funcResidues.addAll(chain.getResidueRange(residue)); } else { funcResidues.add(chain.getResidue(residue)); } } } } /** * Get the user data for this model * * @return user data */ public Object getUserData() { return userData; } /** * Set the user data for this model * * @param data * user data to associate with this model */ public void setUserData(Object data) { this.userData = data; } /** * Return the selected state of this model * * @return the selected state */ public boolean isSelected() { return selected; } /** * Set the selected state of this model * * @param selected * a boolean to set the selected state to */ public void setSelected(boolean selected) { this.selected = selected; } /** * Return the chains in this model as a List * * @return the chains in this model as a list */ public List getChildren() { return new ArrayList(chainMap.values()); } /** * Return the chains in this model as a colleciton * * @return the chains in this model */ public Collection getChains() { return chainMap.values(); } /** * Get the number of chains in this model * * @return integer chain count */ public int getChainCount() { return chainMap.size(); } /** * Get the list of chain names associated with this model * * @return return the list of chain names for this model */ public Collection getChainNames() { return chainMap.keySet(); } /** * Get the residues associated with this model * * @return the list of residues in this model */ public Collection getResidues() { Collection residues = new ArrayList(); for (ChimeraChain chain : getChains()) { residues.addAll(chain.getResidues()); } return residues; } /** * Get the number of residues in this model * * @return integer residues count */ public int getResidueCount() { int count = 0; for (ChimeraChain chain : getChains()) { count += chain.getResidueCount(); } return count; } /** * Get a specific chain from the model * * @param chain * the ID of the chain to return * @return ChimeraChain associated with the chain */ public ChimeraChain getChain(String chain) { if (chainMap.containsKey(chain)) { return chainMap.get(chain); } return null; } /** * Return a specific residue based on its index * * @param index * of the residue to return * @return the residue associated with that index */ public ChimeraResidue getResidue(String chainId, String index) { if (chainMap.containsKey(chainId)) { return chainMap.get(chainId).getResidue(index); } return null; } /** * Checks if this model has selected children. */ public boolean hasSelectedChildren() { if (selected) { return true; } else { for (ChimeraChain chain : getChains()) { if (chain.hasSelectedChildren()) { return true; } } } return false; } /** * Return the list of selected residues * * @return all selected residues */ public List getSelectedResidues() { List residueList = new ArrayList(); for (ChimeraChain chain : getChains()) { if (selected) { residueList.addAll(chain.getSelectedResidues()); } else { residueList.addAll(getResidues()); } } return residueList; } /** * Return the Chimera specification for this model. */ public String toSpec() { if (subModelNumber == 0) return ("#" + modelNumber); return ("#" + modelNumber + "." + subModelNumber); } /** * Return a string representation for the model. Shorten if longer than 100 * characters. */ public String toString() { String modelName = ""; // TODO: [Optional] Change cutoff for shortening model names in the // structure naviagator dialog if (getChainCount() > 0) { modelName = "Model " + toSpec() + " " + name + " (" + getChainCount() + " chains, " + getResidueCount() + " residues)"; } else if (getResidueCount() > 0) { modelName = "Model " + toSpec() + " " + name + " (" + getResidueCount() + " residues)"; } else { modelName = "Model " + toSpec() + " " + name + ""; } Set networkNames = new HashSet(); Set nodeNames = new HashSet(); Set edgeNames = new HashSet(); String cytoName = " ["; if (networkNames.size() > 0) { if (networkNames.size() == 1) { cytoName += "Network {"; } else if (networkNames.size() > 1) { cytoName += "Networks {"; } for (String cName : networkNames) { cytoName += cName + ","; } cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, "; } if (nodeNames.size() > 0) { if (nodeNames.size() == 1) { cytoName += "Node {"; } else if (nodeNames.size() > 1) { cytoName += "Nodes {"; } for (String cName : nodeNames) { cytoName += cName + ","; } cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, "; } if (edgeNames.size() > 0) { if (edgeNames.size() == 1) { cytoName += "Edge {"; } else if (edgeNames.size() > 1) { cytoName += "Edges {"; } for (String cName : edgeNames) { cytoName += cName + ","; } cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, "; } if (cytoName.endsWith(", ")) { cytoName = cytoName.substring(0, cytoName.length() - 2); } cytoName += "]"; String nodeName = modelName + cytoName; if (nodeName.length() > 100) { nodeName = nodeName.substring(0, 100) + "..."; } return nodeName; } }