JAL-1333 Chimera specific code extracted from the StructureViz library for opening...
[jalview.git] / src / ext / edu / ucsf / rbvi / strucviz2 / ChimeraModel.java
1 package ext.edu.ucsf.rbvi.strucviz2;
2
3 import java.awt.Color;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.TreeMap;
12
13 import ext.edu.ucsf.rbvi.strucviz2.StructureManager.ModelType;
14
15 /**
16  * This class provides the implementation for the ChimeraModel, ChimeraChain, and ChimeraResidue
17  * objects
18  * 
19  * @author scooter
20  * 
21  */
22 public class ChimeraModel implements ChimeraStructuralObject {
23
24         private String name; // The name of this model
25         private ModelType type; // The type of the model
26         private int modelNumber; // The model number
27         private int subModelNumber; // The sub-model number
28
29         private Color modelColor = null; // The color of this model (from Chimera)
30         private Object userData = null; // User data associated with this model
31         private boolean selected = false; // The selected state of this model
32
33         private TreeMap<String, ChimeraChain> chainMap; // The list of chains
34         // private TreeMap<String, ChimeraResidue> residueMap; // The list of residues
35         private HashSet<ChimeraResidue> funcResidues; // List of functional residues
36
37         /**
38          * Constructor to create a model
39          * 
40          * @param name
41          *            the name of this model
42          * @param color
43          *            the model Color
44          * @param modelNumber
45          *            the model number
46          * @param subModelNumber
47          *            the sub-model number
48          */
49         public ChimeraModel(String name, ModelType type, int modelNumber, int subModelNumber) {
50                 this.name = name;
51                 this.type = type;
52                 this.modelNumber = modelNumber;
53                 this.subModelNumber = subModelNumber;
54
55                 this.chainMap = new TreeMap<String, ChimeraChain>();
56                 this.funcResidues = new HashSet<ChimeraResidue>();
57         }
58
59         /**
60          * Constructor to create a model from the Chimera input line
61          * 
62          * @param inputLine
63          *            Chimera input line from which to construct this model
64          */
65         // TODO: [Optional] How to distinguish between PDB and MODBASE?
66         // invoked when listing models: listm type molecule; lists level molecule
67         // line = model id #0 type Molecule name 1ert
68         public ChimeraModel(String inputLine) {
69                 this.name = ChimUtils.parseModelName(inputLine);
70                 // TODO: [Optional] Write a separate method to get model type
71                 if (name.startsWith("smiles")) {
72                         this.type = ModelType.SMILES;
73                 } else {
74                         this.type = ModelType.PDB_MODEL;
75                 }
76                 this.modelNumber = ChimUtils.parseModelNumber(inputLine)[0];
77                 this.subModelNumber = ChimUtils.parseModelNumber(inputLine)[1];
78
79                 this.chainMap = new TreeMap<String, ChimeraChain>();
80                 this.funcResidues = new HashSet<ChimeraResidue>();
81         }
82
83         /**
84          * Add a residue to this model
85          * 
86          * @param residue
87          *            to add to the model
88          */
89         public void addResidue(ChimeraResidue residue) {
90                 residue.setChimeraModel(this);
91                 // residueMap.put(residue.getIndex(), residue);
92                 String chainId = residue.getChainId();
93                 if (chainId != null) {
94                         addResidue(chainId, residue);
95                 } else {
96                         addResidue("_", residue);
97                 }
98                 // Put it in our map so that we can return it in order
99                 // residueMap.put(residue.getIndex(), residue);
100         }
101
102         /**
103          * Add a residue to a chain in this model. If the chain associated with chainId doesn't exist,
104          * it will be created.
105          * 
106          * @param chainId
107          *            to add the residue to
108          * @param residue
109          *            to add to the chain
110          */
111         public void addResidue(String chainId, ChimeraResidue residue) {
112                 ChimeraChain chain = null;
113                 if (!chainMap.containsKey(chainId)) {
114                         chain = new ChimeraChain(this.modelNumber, this.subModelNumber, chainId);
115                         chain.setChimeraModel(this);
116                         chainMap.put(chainId, chain);
117                 } else {
118                         chain = chainMap.get(chainId);
119                 }
120                 chain.addResidue(residue);
121         }
122
123         /**
124          * Get the ChimeraModel (required for ChimeraStructuralObject interface)
125          * 
126          * @return ChimeraModel
127          */
128         public ChimeraModel getChimeraModel() {
129                 return this;
130         }
131
132         /**
133          * Get the model color of this model
134          * 
135          * @return model color of this model
136          */
137         public Color getModelColor() {
138                 return this.modelColor;
139         }
140
141         /**
142          * Set the color of this model
143          * 
144          * @param color
145          *            Color of this model
146          */
147         public void setModelColor(Color color) {
148                 this.modelColor = color;
149         }
150
151         /**
152          * Return the name of this model
153          * 
154          * @return model name
155          */
156         public String getModelName() {
157                 return name;
158         }
159
160         /**
161          * Set the name of this model
162          * 
163          * @param name
164          *            model name
165          */
166         public void setModelName(String name) {
167                 this.name = name;
168         }
169
170         /**
171          * Get the model number of this model
172          * 
173          * @return integer model number
174          */
175         public int getModelNumber() {
176                 return modelNumber;
177         }
178
179         /**
180          * Set the model number of this model
181          * 
182          * @param modelNumber
183          *            integer model number
184          */
185         public void setModelNumber(int modelNumber) {
186                 this.modelNumber = modelNumber;
187         }
188
189         /**
190          * Get the sub-model number of this model
191          * 
192          * @return integer sub-model number
193          */
194         public int getSubModelNumber() {
195                 return subModelNumber;
196         }
197
198         /**
199          * Set the sub-model number of this model
200          * 
201          * @param subModelNumber
202          *            integer model number
203          */
204         public void setSubModelNumber(int subModelNumber) {
205                 this.subModelNumber = subModelNumber;
206         }
207
208         public ModelType getModelType() {
209                 return type;
210         }
211
212         public void setModelType(ModelType type) {
213                 this.type = type;
214         }
215
216         public HashSet<ChimeraResidue> getFuncResidues() {
217                 return funcResidues;
218         }
219
220         public void setFuncResidues(List<String> residues) {
221                 for (String residue : residues) {
222                         for (ChimeraChain chain : getChains()) {
223                                 if (residue.indexOf("-") > 0) {
224                                         funcResidues.addAll(chain.getResidueRange(residue));
225                                 } else {
226                                         funcResidues.add(chain.getResidue(residue));
227                                 }
228                         }
229                 }
230         }
231
232         /**
233          * Get the user data for this model
234          * 
235          * @return user data
236          */
237         public Object getUserData() {
238                 return userData;
239         }
240
241         /**
242          * Set the user data for this model
243          * 
244          * @param data
245          *            user data to associate with this model
246          */
247         public void setUserData(Object data) {
248                 this.userData = data;
249         }
250
251         /**
252          * Return the selected state of this model
253          * 
254          * @return the selected state
255          */
256         public boolean isSelected() {
257                 return selected;
258         }
259
260         /**
261          * Set the selected state of this model
262          * 
263          * @param selected
264          *            a boolean to set the selected state to
265          */
266         public void setSelected(boolean selected) {
267                 this.selected = selected;
268         }
269
270         /**
271          * Return the chains in this model as a List
272          * 
273          * @return the chains in this model as a list
274          */
275         public List<ChimeraStructuralObject> getChildren() {
276                 return new ArrayList<ChimeraStructuralObject>(chainMap.values());
277         }
278
279         /**
280          * Return the chains in this model as a colleciton
281          * 
282          * @return the chains in this model
283          */
284         public Collection<ChimeraChain> getChains() {
285                 return chainMap.values();
286         }
287
288         /**
289          * Get the number of chains in this model
290          * 
291          * @return integer chain count
292          */
293         public int getChainCount() {
294                 return chainMap.size();
295         }
296
297         /**
298          * Get the list of chain names associated with this model
299          * 
300          * @return return the list of chain names for this model
301          */
302         public Collection<String> getChainNames() {
303                 return chainMap.keySet();
304         }
305
306         /**
307          * Get the residues associated with this model
308          * 
309          * @return the list of residues in this model
310          */
311         public Collection<ChimeraResidue> getResidues() {
312                 Collection<ChimeraResidue> residues = new ArrayList<ChimeraResidue>();
313                 for (ChimeraChain chain : getChains()) {
314                         residues.addAll(chain.getResidues());
315                 }
316                 return residues;
317         }
318
319         /**
320          * Get the number of residues in this model
321          * 
322          * @return integer residues count
323          */
324         public int getResidueCount() {
325                 int count = 0;
326                 for (ChimeraChain chain : getChains()) {
327                         count += chain.getResidueCount();
328                 }
329                 return count;
330         }
331
332         /**
333          * Get a specific chain from the model
334          * 
335          * @param chain
336          *            the ID of the chain to return
337          * @return ChimeraChain associated with the chain
338          */
339         public ChimeraChain getChain(String chain) {
340                 if (chainMap.containsKey(chain)) {
341                         return chainMap.get(chain);
342                 }
343                 return null;
344         }
345
346         /**
347          * Return a specific residue based on its index
348          * 
349          * @param index
350          *            of the residue to return
351          * @return the residue associated with that index
352          */
353         public ChimeraResidue getResidue(String chainId, String index) {
354                 if (chainMap.containsKey(chainId)) {
355                         return chainMap.get(chainId).getResidue(index);
356                 }
357                 return null;
358         }
359
360         /**
361          * Checks if this model has selected children.
362          */
363         public boolean hasSelectedChildren() {
364                 if (selected) {
365                         return true;
366                 } else {
367                         for (ChimeraChain chain : getChains()) {
368                                 if (chain.hasSelectedChildren()) {
369                                         return true;
370                                 }
371                         }
372                 }
373                 return false;
374         }
375
376         /**
377          * Return the list of selected residues
378          * 
379          * @return all selected residues
380          */
381         public List<ChimeraResidue> getSelectedResidues() {
382                 List<ChimeraResidue> residueList = new ArrayList<ChimeraResidue>();
383                 for (ChimeraChain chain : getChains()) {
384                         if (selected) {
385                                 residueList.addAll(chain.getSelectedResidues());
386                         } else {
387                                 residueList.addAll(getResidues());
388                         }
389                 }
390                 return residueList;
391         }
392
393
394         /**
395          * Return the Chimera specification for this model.
396          */
397         public String toSpec() {
398                 if (subModelNumber == 0)
399                         return ("#" + modelNumber);
400                 return ("#" + modelNumber + "." + subModelNumber);
401         }
402
403         /**
404          * Return a string representation for the model. Shorten if longer than 100 characters.
405          */
406         public String toString() {
407                 String modelName = "";
408                 // TODO: [Optional] Change cutoff for shortening model names in the structure naviagator dialog
409                 if (getChainCount() > 0) {
410                         modelName = "Model " + toSpec() + " " + name + " (" + getChainCount() + " chains, "
411                                         + getResidueCount() + " residues)";
412                 } else if (getResidueCount() > 0) {
413                         modelName = "Model " + toSpec() + " " + name + " (" + getResidueCount() + " residues)";
414                 } else {
415                         modelName = "Model " + toSpec() + " " + name + "";
416                 }
417
418                 Set<String> networkNames = new HashSet<String>();
419                 Set<String> nodeNames = new HashSet<String>();
420                 Set<String> edgeNames = new HashSet<String>();
421
422                 String cytoName = " [";
423                 if (networkNames.size() > 0) {
424                         if (networkNames.size() == 1) {
425                                 cytoName += "Network {";
426                         } else if (networkNames.size() > 1) {
427                                 cytoName += "Networks {";
428                         }
429                         for (String cName : networkNames) {
430                                 cytoName += cName + ",";
431                         }
432                         cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, ";
433                 }
434                 if (nodeNames.size() > 0) {
435                         if (nodeNames.size() == 1) {
436                                 cytoName += "Node {";
437                         } else if (nodeNames.size() > 1) {
438                                 cytoName += "Nodes {";
439                         }
440                         for (String cName : nodeNames) {
441                                 cytoName += cName + ",";
442                         }
443                         cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, ";
444                 }
445                 if (edgeNames.size() > 0) {
446                         if (edgeNames.size() == 1) {
447                                 cytoName += "Edge {";
448                         } else if (edgeNames.size() > 1) {
449                                 cytoName += "Edges {";
450                         }
451                         for (String cName : edgeNames) {
452                                 cytoName += cName + ",";
453                         }
454                         cytoName = cytoName.substring(0, cytoName.length() - 1) + "}, ";
455                 }
456                 if (cytoName.endsWith(", ")) {
457                         cytoName = cytoName.substring(0, cytoName.length() - 2);
458                 }
459                 cytoName += "]";
460                 String nodeName = modelName + cytoName;
461                 if (nodeName.length() > 100) {
462                         nodeName = nodeName.substring(0, 100) + "...";
463                 }
464                 return nodeName;
465         }
466 }