Merge branch 'features/JAL-1333' into Release_2_8_2_Branch
[jalview.git] / src / ext / edu / ucsf / rbvi / strucviz2 / StructureManager.java
1 package ext.edu.ucsf.rbvi.strucviz2;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.Collection;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Properties;
13 import java.util.Set;
14
15 import org.slf4j.Logger;
16 import org.slf4j.LoggerFactory;
17
18 /**
19  * This object maintains the relationship between Chimera objects and Cytoscape
20  * objects.
21  */
22
23 public class StructureManager
24 {
25   static final String[] defaultStructureKeys =
26   { "Structure", "pdb", "pdbFileName", "PDB ID", "structure",
27       "biopax.xref.PDB", "pdb_ids", "ModelName", "ModelNumber" };
28
29   static final String[] defaultChemStructKeys =
30   { "Smiles", "smiles", "SMILES" };
31
32   static final String[] defaultResidueKeys =
33   { "FunctionalResidues", "ResidueList", "Residues" };
34
35   private final String chimeraPropertyName = "chimera";
36
37   private final String chimeraPathPropertyKey = "LastChimeraPath";
38
39   public enum ModelType
40   {
41     PDB_MODEL, MODBASE_MODEL, SMILES
42   };
43
44   public static Properties pathProps;
45
46   private String chimeraCommandAttr = "ChimeraCommand";
47
48   private String chimeraOutputTable = "ChimeraTable";
49
50   private String chimeraOutputAttr = "ChimeraOutput";
51
52   private boolean haveGUI = true;
53
54   private ChimeraManager chimeraManager = null;
55
56   static private List<ChimeraStructuralObject> chimSelectionList;
57
58   private boolean ignoreCySelection = false;
59
60   private File configurationDirectory = null;
61
62   private static Logger logger = LoggerFactory
63           .getLogger(ext.edu.ucsf.rbvi.strucviz2.StructureManager.class);
64
65   public StructureManager(boolean haveGUI)
66   {
67     this.haveGUI = haveGUI;
68     // Create the Chimera interface
69     chimeraManager = new ChimeraManager(this);
70     chimSelectionList = new ArrayList<ChimeraStructuralObject>();
71     pathProps = new Properties();
72   }
73
74   public ChimeraManager getChimeraManager()
75   {
76     return chimeraManager;
77   }
78
79   public boolean openStructures(Collection<List<String>> chimObjNames,
80           ModelType type)
81   {
82     // new models
83     Map<String, List<ChimeraModel>> newModels = new HashMap<String, List<ChimeraModel>>();
84     if (chimObjNames.size() > 0)
85     {
86       List<String> names = chimObjNames.iterator().next();
87       if (names == null)
88       {
89         return false;
90       }
91       for (String chimObjName : names)
92       {
93         // get or open the corresponding models if they already exist
94         List<ChimeraModel> currentModels = chimeraManager.getChimeraModels(
95                 chimObjName, type);
96         if (currentModels.size() == 0)
97         {
98           // open and return models
99           currentModels = chimeraManager.openModel(chimObjName, type);
100           if (currentModels == null)
101           {
102             // failed to open model, continue with next
103             continue;
104           }
105           // if (type == ModelType.SMILES) {
106           // newModels.put("smiles:" + chimObjName, currentModels);
107           // } else {
108           newModels.put(chimObjName, currentModels);
109           // }
110           // for each model
111           for (ChimeraModel currentModel : currentModels)
112           {
113             // if not RIN then associate new model with the Cytoscape
114             // node
115             // if (!currentChimMap.containsKey(currentModel)) {
116             // currentChimMap.put(currentModel, new HashSet<CyIdentifiable>());
117             // }
118           }
119         }
120       }
121     }
122     else
123     {
124       return false;
125     }
126     // update dialog
127     // if (mnDialog != null) {
128     // mnDialog.modelChanged();
129     // }
130     // aTask.associate();
131     return true;
132
133   }
134
135   // TODO: [Release] Handle case where one network is associated with two models
136   // that are opened
137   // at the same time
138   /*
139    * public boolean openStructures(CyNetwork network, Map<CyIdentifiable,
140    * List<String>> chimObjNames, ModelType type) { if
141    * (!chimeraManager.isChimeraLaunched() &&
142    * !chimeraManager.launchChimera(getChimeraPaths(network))) {
143    * logger.error("Chimera could not be launched."); return false; } else if
144    * (chimObjNames.size() == 0) { return false; } else if (network == null) {
145    * return openStructures(chimObjNames.values(), type); }
146    * 
147    * // potential rins Set<CyNetwork> potentialRINs = new HashSet<CyNetwork>();
148    * // attributes List<String> attrsFound = new ArrayList<String>();
149    * attrsFound.
150    * addAll(CytoUtils.getMatchingAttributes(network.getDefaultNodeTable(),
151    * getCurrentStructureKeys(network)));
152    * attrsFound.addAll(CytoUtils.getMatchingAttributes
153    * (network.getDefaultNodeTable(), getCurrentChemStructKeys(network))); // new
154    * models Map<String, List<ChimeraModel>> newModels = new HashMap<String,
155    * List<ChimeraModel>>(); // for each node that has an associated structure
156    * for (CyIdentifiable cyObj : chimObjNames.keySet()) { // get possible res
157    * specs List<String> specsFound = null; if (cyObj instanceof CyNode) {
158    * specsFound = ChimUtils.getResidueKeys(network.getDefaultNodeTable(), cyObj,
159    * attrsFound); } // save node to track its selection and mapping to chimera
160    * objects if (!currentCyMap.containsKey(cyObj)) { currentCyMap.put(cyObj, new
161    * HashSet<ChimeraStructuralObject>()); } // save node to network mapping to
162    * keep track of selection events if (!networkMap.containsKey(cyObj)) {
163    * networkMap.put(cyObj, new HashSet<CyNetwork>()); }
164    * networkMap.get(cyObj).add(network); // for each structure that has to be
165    * opened for (String chimObjName : chimObjNames.get(cyObj)) { // get or open
166    * the corresponding models if they already exist List<ChimeraModel>
167    * currentModels = chimeraManager.getChimeraModels(chimObjName, type); if
168    * (currentModels.size() == 0) { // open and return models currentModels =
169    * chimeraManager.openModel(chimObjName, type); if (currentModels == null) {
170    * // failed to open model, continue with next continue; } // if (type ==
171    * ModelType.SMILES) { // newModels.put("smiles:" + chimObjName,
172    * currentModels); // } else { newModels.put(chimObjName, currentModels); // }
173    * // for each model for (ChimeraModel currentModel : currentModels) { //
174    * check if it is a RIN boolean foundRIN = false; if
175    * (currentModel.getModelType().equals(ModelType.PDB_MODEL)) { // go through
176    * all node annotations and check if any of them is a residue // or a chain if
177    * (cyObj instanceof CyNode && network.containsNode((CyNode) cyObj) &&
178    * specsFound != null && specsFound.size() > 0) { for (String resSpec :
179    * specsFound) { ChimeraStructuralObject res =
180    * ChimUtils.fromAttribute(resSpec, chimeraManager); if (res != null && (res
181    * instanceof ChimeraResidue || res instanceof ChimeraChain)) { // if so,
182    * assume it might be a RIN potentialRINs.add(network); foundRIN = true;
183    * break; } } } else if (cyObj instanceof CyNetwork) { // if cyObj is a
184    * network, check for residue/chain annotations in an // arbitrary node
185    * CyNetwork rinNet = (CyNetwork) cyObj; if (rinNet.getNodeList().size() > 0)
186    * { specsFound = ChimUtils.getResidueKeys( rinNet.getDefaultNodeTable(),
187    * rinNet.getNodeList().get(0), attrsFound); for (String resSpec : specsFound)
188    * { ChimeraStructuralObject res = ChimUtils.fromAttribute( resSpec,
189    * chimeraManager); if (res != null && (res instanceof ChimeraResidue || res
190    * instanceof ChimeraChain)) { potentialRINs.add(network); foundRIN = true;
191    * break; } } } } } if (foundRIN) { continue; } // if not RIN then associate
192    * new model with the Cytoscape // node if
193    * (!currentChimMap.containsKey(currentModel)) {
194    * currentChimMap.put(currentModel, new HashSet<CyIdentifiable>()); } String
195    * cyObjName = network.getRow(cyObj).get(CyNetwork.NAME, String.class); if
196    * (cyObjName != null && cyObjName.endsWith(currentModel.getModelName())) { //
197    * it is a modbase model, associate directly
198    * currentCyMap.get(cyObj).add(currentModel);
199    * currentChimMap.get(currentModel).add(cyObj);
200    * currentModel.addCyObject(cyObj, network); } else if (specsFound != null &&
201    * specsFound.size() > 0) { for (String resSpec : specsFound) {
202    * ChimeraStructuralObject specModel = ChimUtils.fromAttribute( resSpec,
203    * chimeraManager); if (specModel == null &&
204    * resSpec.equals(currentModel.getModelName())) { specModel =
205    * chimeraManager.getChimeraModel( currentModel.getModelNumber(),
206    * currentModel.getSubModelNumber()); } if (specModel != null &&
207    * currentModel.toSpec().equals(specModel.toSpec()) ||
208    * currentModel.getModelName().equals("smiles:" + resSpec)) {
209    * currentCyMap.get(cyObj).add(currentModel);
210    * currentChimMap.get(currentModel).add(cyObj);
211    * currentModel.addCyObject(cyObj, network);
212    * currentModel.setFuncResidues(ChimUtils.parseFuncRes(
213    * getResidueList(network, cyObj), chimObjName)); } } } } } } } // networks
214    * that contain nodes associated to newly opened models // this will usually
215    * be of length 1 for (CyNetwork net : potentialRINs) {
216    * addStructureNetwork(net); } // update dialog if (mnDialog != null) {
217    * mnDialog.modelChanged(); } aTask.associate(); return true; }
218    */
219   public void closeStructures(Set<String> chimObjNames)
220   {
221     // for each cytoscape object and chimera model pair
222     for (String modelName : chimObjNames)
223     {
224       List<ChimeraModel> models = chimeraManager
225               .getChimeraModels(modelName);
226       for (ChimeraModel model : models)
227       {
228         closeModel(model);
229       }
230     }
231     // if (mnDialog != null) {
232     // mnDialog.modelChanged();
233     // }
234   }
235
236   // TODO: [Optional] Can we make a screenshot of a single molecule?
237   public File saveChimeraImage()
238   {
239     File tmpFile = null;
240     try
241     {
242       // Create the temp file name
243       tmpFile = File.createTempFile("structureViz", ".png");
244       chimeraManager.sendChimeraCommand("set bgTransparency", false);
245       chimeraManager.sendChimeraCommand(
246               "copy file " + tmpFile.getAbsolutePath() + " png", true);
247       chimeraManager.sendChimeraCommand("unset bgTransparency", false);
248     } catch (IOException ioe)
249     {
250       // Log error
251       logger.error("Error writing image", ioe);
252     }
253     return tmpFile;
254   }
255
256   public void closeModel(ChimeraModel model)
257   {
258     // close model in Chimera
259     chimeraManager.closeModel(model);
260     // remove all associations
261     // if (currentChimMap.containsKey(model)) {
262     // for (CyIdentifiable cyObj : model.getCyObjects().keySet()) {
263     // if (cyObj == null) {
264     // continue;
265     // } else if (currentCyMap.containsKey(cyObj)) {
266     // currentCyMap.get(cyObj).remove(model);
267     // } else if (cyObj instanceof CyNetwork) {
268     // for (ChimeraResidue residue : model.getResidues()) {
269     // if (currentChimMap.containsKey(residue)) {
270     // for (CyIdentifiable cyObjRes : currentChimMap.get(residue)) {
271     // if (currentCyMap.containsKey(cyObjRes)) {
272     // currentCyMap.get(cyObjRes).remove(residue);
273     // }
274     // }
275     // currentChimMap.remove(residue);
276     // }
277     // }
278     // }
279     // }
280     // currentChimMap.remove(model);
281     // }
282   }
283
284   // public void addStructureNetwork(CyNetwork rin) {
285   // if (rin == null) {
286   // return;
287   // }
288   // ChimeraModel model = null;
289   // // the network is not added to the model in the currentChimMap
290   // List<String> attrsFound =
291   // CytoUtils.getMatchingAttributes(rin.getDefaultNodeTable(),
292   // getCurrentStructureKeys(rin));
293   // for (CyNode node : rin.getNodeList()) {
294   // if (!networkMap.containsKey(node)) {
295   // networkMap.put(node, new HashSet<CyNetwork>());
296   // }
297   // networkMap.get(node).add(rin);
298   // List<String> specsFound =
299   // ChimUtils.getResidueKeys(rin.getDefaultNodeTable(), node,
300   // attrsFound);
301   // for (String residueSpec : specsFound) {
302   // // if (!rin.getRow(node).isSet(ChimUtils.RESIDUE_ATTR)) {
303   // // continue;
304   // // }
305   // // String residueSpec = rin.getRow(node).get(ChimUtils.RESIDUE_ATTR,
306   // String.class);
307   // ChimeraStructuralObject chimObj = ChimUtils.fromAttribute(residueSpec,
308   // chimeraManager);
309   // // chimObj.getChimeraModel().addCyObject(node, rin);
310   // if (chimObj == null || chimObj instanceof ChimeraModel) {
311   // continue;
312   // }
313   // model = chimObj.getChimeraModel();
314   // if (!currentCyMap.containsKey(node)) {
315   // currentCyMap.put(node, new HashSet<ChimeraStructuralObject>());
316   // }
317   // currentCyMap.get(node).add(chimObj);
318   // if (!currentChimMap.containsKey(chimObj)) {
319   // currentChimMap.put(chimObj, new HashSet<CyIdentifiable>());
320   // }
321   // currentChimMap.get(chimObj).add(node);
322   // }
323   // }
324   // if (model != null) {
325   // model.addCyObject(rin, rin);
326   // if (!currentCyMap.containsKey(rin)) {
327   // currentCyMap.put(rin, new HashSet<ChimeraStructuralObject>());
328   // }
329   // currentCyMap.get(rin).add(model);
330   // }
331   // }
332
333   public void exitChimera()
334   {
335     // // exit chimera, invokes clearOnExitChimera
336     // if (mnDialog != null) {
337     // mnDialog.setVisible(false);
338     // mnDialog = null;
339     // }
340     // if (alDialog != null) {
341     // alDialog.setVisible(false);
342     // }
343     chimeraManager.exitChimera();
344   }
345
346   // invoked by ChimeraManager whenever Chimera exits
347   public void clearOnChimeraExit()
348   {
349     // // clear structures
350     // currentCyMap.clear();
351     // currentChimMap.clear();
352     // networkMap.clear();
353     chimSelectionList.clear();
354     // if (chimTable != null) {
355     // ((CyTableManager)
356     // getService(CyTableManager.class)).deleteTable(chimTable.getSUID());
357     // }
358     // if (mnDialog != null) {
359     // if (mnDialog.isVisible()) {
360     // mnDialog.lostChimera();
361     // mnDialog.setVisible(false);
362     // }
363     // mnDialog = null;
364     // if (alDialog != null) {
365     // alDialog.setVisible(false);
366     // }
367     // }
368   }
369
370   // We need to do this in two passes since some parts of a structure might be
371   // selected and some might not. Our selection model (unfortunately) only
372   // tells
373   // us that something has changed, not what...
374   public void updateCytoscapeSelection()
375   {
376     // List<ChimeraStructuralObject> selectedChimObj
377     ignoreCySelection = true;
378     // System.out.println("update Cytoscape selection");
379     // find all possibly selected Cytoscape objects and unselect them
380     // Set<CyNetwork> networks = new HashSet<CyNetwork>();
381     // for (CyIdentifiable currentCyObj : currentCyMap.keySet()) {
382     // if (!networkMap.containsKey(currentCyObj)) {
383     // continue;
384     // }
385     // Set<CyNetwork> currentCyNetworks = networkMap.get(currentCyObj);
386     // if (currentCyNetworks == null || currentCyNetworks.size() == 0) {
387     //
388     // continue;
389     // }
390     // for (CyNetwork network : currentCyNetworks) {
391     // if ((currentCyObj instanceof CyNode && network.containsNode((CyNode)
392     // currentCyObj))
393     // || (currentCyObj instanceof CyEdge && network
394     // .containsEdge((CyEdge) currentCyObj))) {
395     // network.getRow(currentCyObj).set(CyNetwork.SELECTED, false);
396     // networks.add(network);
397     // }
398     // }
399     // }
400     //
401     // // select only those associated with selected Chimera objects
402     // Set<CyIdentifiable> currentCyObjs = new HashSet<CyIdentifiable>();
403     // for (ChimeraStructuralObject chimObj : chimSelectionList) {
404     // ChimeraModel currentSelModel = chimObj.getChimeraModel();
405     // if (currentChimMap.containsKey(currentSelModel)) {
406     // currentCyObjs.addAll(currentChimMap.get(currentSelModel));
407     // }
408     // if (currentChimMap.containsKey(chimObj)) {
409     // currentCyObjs.addAll(currentChimMap.get(chimObj));
410     // }
411     // // System.out.println(chimObj.toSpec() + ": " +
412     // // currentCyObjs.size());
413     // }
414     // for (CyIdentifiable cyObj : currentCyObjs) {
415     // // System.out.println(cyObj.toString());
416     // if (cyObj == null || !networkMap.containsKey(cyObj)) {
417     // continue;
418     // }
419     // Set<CyNetwork> currentCyNetworks = networkMap.get(cyObj);
420     // if (currentCyNetworks == null || currentCyNetworks.size() == 0) {
421     // continue;
422     // }
423     // for (CyNetwork network : currentCyNetworks) {
424     // if ((cyObj instanceof CyNode && network.containsNode((CyNode) cyObj))
425     // || (cyObj instanceof CyEdge && network.containsEdge((CyEdge) cyObj))) {
426     // network.getRow(cyObj).set(CyNetwork.SELECTED, true);
427     // networks.add(network);
428     // }
429     // }
430     // }
431     //
432     // CyNetworkViewManager cyNetViewManager = (CyNetworkViewManager)
433     // getService(CyNetworkViewManager.class);
434     // // Update network views
435     // for (CyNetwork network : networks) {
436     // Collection<CyNetworkView> views =
437     // cyNetViewManager.getNetworkViews(network);
438     // for (CyNetworkView view : views) {
439     // view.updateView();
440     // }
441     // }
442     ignoreCySelection = false;
443   }
444
445   public void cytoscapeSelectionChanged(Map<Long, Boolean> selectedRows)
446   {
447     // if (ignoreCySelection || currentCyMap.size() == 0) {
448     // return;
449     // }
450     // // clearSelectionList();
451     // // System.out.println("cytoscape selection changed");
452     // // iterate over all cy objects with associated models
453     // for (CyIdentifiable cyObj : currentCyMap.keySet()) {
454     // if (cyObj instanceof CyNetwork ||
455     // !selectedRows.containsKey(cyObj.getSUID())) {
456     // continue;
457     // }
458     // for (ChimeraStructuralObject chimObj : currentCyMap.get(cyObj)) {
459     // if (selectedRows.get(cyObj.getSUID())) {
460     // addChimSelection(chimObj);
461     // if (chimObj instanceof ChimeraResidue) {
462     // if (chimObj.getChimeraModel().isSelected()) {
463     // removeChimSelection(chimObj.getChimeraModel());
464     // } else if (chimObj.getChimeraModel()
465     // .getChain(((ChimeraResidue) chimObj).getChainId()).isSelected()) {
466     // removeChimSelection(chimObj.getChimeraModel().getChain(
467     // ((ChimeraResidue) chimObj).getChainId()));
468     // }
469     // }
470     // } else {
471     // removeChimSelection(chimObj);
472     // if (chimObj.hasSelectedChildren() && chimObj instanceof ChimeraModel) {
473     // for (ChimeraResidue residue : ((ChimeraModel) chimObj)
474     // .getSelectedResidues()) {
475     // removeChimSelection(residue);
476     // }
477     // }
478     // }
479     // }
480     // }
481     // System.out.println("selection list: " + getChimSelectionCount());
482     updateChimeraSelection();
483     selectionChanged();
484   }
485
486   // Save models in a HashMap/Set for better performance?
487   public void updateChimeraSelection()
488   {
489     // System.out.println("update Chimera selection");
490     String selSpec = "";
491     for (int i = 0; i < chimSelectionList.size(); i++)
492     {
493       ChimeraStructuralObject nodeInfo = chimSelectionList.get(i);
494       // we do not care about the model anymore
495       selSpec = selSpec.concat(nodeInfo.toSpec());
496       if (i < chimSelectionList.size() - 1)
497         selSpec.concat("|");
498     }
499     if (selSpec.length() > 0)
500     {
501       chimeraManager.select("sel " + selSpec);
502     }
503     else
504     {
505       chimeraManager.select("~sel");
506     }
507   }
508
509   /**
510    * This is called by the selectionListener to let us know that the user has
511    * changed their selection in Chimera. We need to go back to Chimera to find
512    * out what is currently selected and update our list.
513    */
514   public void chimeraSelectionChanged()
515   {
516     // System.out.println("Chimera selection changed");
517     clearSelectionList();
518     // Execute the command to get the list of models with selections
519     Map<Integer, ChimeraModel> selectedModelsMap = chimeraManager
520             .getSelectedModels();
521     // Now get the residue-level data
522     chimeraManager.getSelectedResidues(selectedModelsMap);
523     // Get the selected objects
524     try
525     {
526       for (ChimeraModel selectedModel : selectedModelsMap.values())
527       {
528         int modelNumber = selectedModel.getModelNumber();
529         int subModelNumber = selectedModel.getSubModelNumber();
530         // Get the corresponding "real" model
531         if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber))
532         {
533           ChimeraModel dataModel = chimeraManager.getChimeraModel(
534                   modelNumber, subModelNumber);
535           if (dataModel.getResidueCount() == selectedModel
536                   .getResidueCount()
537                   || dataModel.getModelType() == StructureManager.ModelType.SMILES)
538           {
539             // Select the entire model
540             addChimSelection(dataModel);
541             // dataModel.setSelected(true);
542           }
543           else
544           {
545             for (ChimeraChain selectedChain : selectedModel.getChains())
546             {
547               ChimeraChain dataChain = dataModel.getChain(selectedChain
548                       .getChainId());
549               if (selectedChain.getResidueCount() == dataChain
550                       .getResidueCount())
551               {
552                 addChimSelection(dataChain);
553                 // dataChain.setSelected(true);
554               }
555               // else {
556               // Need to select individual residues
557               for (ChimeraResidue res : selectedChain.getResidues())
558               {
559                 String residueIndex = res.getIndex();
560                 ChimeraResidue residue = dataChain.getResidue(residueIndex);
561                 if (residue == null)
562                 {
563                   continue;
564                 }
565                 addChimSelection(residue);
566                 // residue.setSelected(true);
567               } // resIter.hasNext
568                 // }
569             } // chainIter.hasNext()
570           }
571         }
572       } // modelIter.hasNext()
573     } catch (Exception ex)
574     {
575       logger.warn("Could not update selection", ex);
576     }
577     // System.out.println("selection list: " + getChimSelectionCount());
578     // Finally, update the navigator panel
579     selectionChanged();
580     updateCytoscapeSelection();
581   }
582
583   public void selectFunctResidues(Collection<ChimeraModel> models)
584   {
585     clearSelectionList();
586     for (ChimeraModel model : models)
587     {
588       for (ChimeraResidue residue : model.getFuncResidues())
589       {
590         addChimSelection(residue);
591       }
592     }
593     updateChimeraSelection();
594     updateCytoscapeSelection();
595     selectionChanged();
596   }
597
598   // public void selectFunctResidues(CyNode node, CyNetwork network) {
599   // clearSelectionList();
600   // if (currentCyMap.containsKey(node)) {
601   // Set<ChimeraStructuralObject> chimObjects = currentCyMap.get(node);
602   // for (ChimeraStructuralObject obj : chimObjects) {
603   // if (obj instanceof ChimeraModel) {
604   // ChimeraModel model = (ChimeraModel) obj;
605   // for (ChimeraResidue residue : model.getFuncResidues()) {
606   // addChimSelection(residue);
607   // }
608   // }
609   // }
610   // }
611   // updateChimeraSelection();
612   // updateCytoscapeSelection();
613   // selectionChanged();
614   // }
615
616   public List<ChimeraStructuralObject> getChimSelectionList()
617   {
618     return chimSelectionList;
619   }
620
621   public int getChimSelectionCount()
622   {
623     return chimSelectionList.size();
624   }
625
626   /**
627    * Add a selection to the selection list. This is called primarily by the
628    * Model Navigator Dialog to keep the selections in sync
629    * 
630    * @param selectionToAdd
631    *          the selection to add to our list
632    */
633   public void addChimSelection(ChimeraStructuralObject selectionToAdd)
634   {
635     if (selectionToAdd != null
636             && !chimSelectionList.contains(selectionToAdd))
637     {
638       chimSelectionList.add(selectionToAdd);
639       selectionToAdd.setSelected(true);
640     }
641   }
642
643   /**
644    * Remove a selection from the selection list. This is called primarily by the
645    * Model Navigator Dialog to keep the selections in sync
646    * 
647    * @param selectionToRemove
648    *          the selection to remove from our list
649    */
650   public void removeChimSelection(ChimeraStructuralObject selectionToRemove)
651   {
652     if (selectionToRemove != null
653             && chimSelectionList.contains(selectionToRemove))
654     {
655       chimSelectionList.remove(selectionToRemove);
656       selectionToRemove.setSelected(false);
657     }
658   }
659
660   /**
661    * Clear the list of selected objects
662    */
663   public void clearSelectionList()
664   {
665     for (ChimeraStructuralObject cso : chimSelectionList)
666     {
667       if (cso != null)
668         cso.setSelected(false);
669     }
670     chimSelectionList.clear();
671   }
672
673   /**
674    * Associate a new network with the corresponding Chimera objects.
675    * 
676    * @param network
677    */
678
679   /**
680    * Dump and refresh all of our model/chain/residue info
681    */
682   public void updateModels()
683   {
684     // Stop all of our listeners while we try to handle this
685     chimeraManager.stopListening();
686
687     // Get all of the open models
688     List<ChimeraModel> newModelList = chimeraManager.getModelList();
689
690     // Match them up -- assume that the model #'s haven't changed
691     for (ChimeraModel newModel : newModelList)
692     {
693       // Get the color (for our navigator)
694       newModel.setModelColor(chimeraManager.getModelColor(newModel));
695
696       // Get our model info
697       int modelNumber = newModel.getModelNumber();
698       int subModelNumber = newModel.getSubModelNumber();
699
700       // If we already know about this model number, get the Structure,
701       // which tells us about the associated CyNode
702       if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber))
703       {
704         ChimeraModel oldModel = chimeraManager.getChimeraModel(modelNumber,
705                 subModelNumber);
706         chimeraManager.removeChimeraModel(modelNumber, subModelNumber);
707         newModel.setModelType(oldModel.getModelType());
708         if (oldModel.getModelType() == ModelType.SMILES)
709         {
710           newModel.setModelName(oldModel.getModelName());
711         }
712         // re-assign associations to cytoscape objects
713         // Map<CyIdentifiable, CyNetwork> oldModelCyObjs =
714         // oldModel.getCyObjects();
715         // for (CyIdentifiable cyObj : oldModelCyObjs.keySet()) {
716         // // add cy objects to the new model
717         // newModel.addCyObject(cyObj, oldModelCyObjs.get(cyObj));
718         // if (currentCyMap.containsKey(cyObj)) {
719         // currentCyMap.get(cyObj).add(newModel);
720         // if (currentCyMap.get(cyObj).contains(oldModel)) {
721         // currentCyMap.get(cyObj).remove(oldModel);
722         // }
723         // }
724         // }
725         // // add new model to the chimera objects map and remove old model
726         // if (currentChimMap.containsKey(oldModel)) {
727         // currentChimMap.put(newModel, currentChimMap.get(oldModel));
728         // currentChimMap.remove(oldModel);
729         // }
730       }
731       // add new model to ChimeraManager
732       chimeraManager.addChimeraModel(modelNumber, subModelNumber, newModel);
733
734       // Get the residue information
735       if (newModel.getModelType() != ModelType.SMILES)
736       {
737         chimeraManager.addResidues(newModel);
738       }
739       // for (CyIdentifiable cyObj : newModel.getCyObjects().keySet()) {
740       // if (cyObj != null && cyObj instanceof CyNetwork) {
741       // addStructureNetwork((CyNetwork) cyObj);
742       // } else if (cyObj != null && cyObj instanceof CyNode) {
743       // newModel.setFuncResidues(ChimUtils.parseFuncRes(
744       // getResidueList(newModel.getCyObjects().get(cyObj), cyObj),
745       // newModel.getModelName()));
746       // }
747       // }
748     }
749
750     // associate all models with any node or network
751     // aTask.associate();
752
753     // Restart all of our listeners
754     chimeraManager.startListening();
755     // Done
756   }
757
758   public void launchModelNavigatorDialog()
759   {
760     // TODO: [Optional] Use haveGUI flag
761     // if (!haveGUI) {
762     // return;
763     // }
764     // if (mnDialog == null) {
765     // CySwingApplication cyApplication = (CySwingApplication)
766     // getService(CySwingApplication.class);
767     // mnDialog = new ModelNavigatorDialog(cyApplication.getJFrame(), this);
768     // mnDialog.pack();
769     // }
770     // mnDialog.setVisible(true);
771   }
772
773   public boolean isMNDialogOpen()
774   {
775     // if (mnDialog != null && mnDialog.isVisible()) {
776     // return true;
777     // }
778     return false;
779   }
780
781   /**
782    * Invoked by the listener thread.
783    */
784   public void modelChanged()
785   {
786     // if (mnDialog != null) {
787     // mnDialog.modelChanged();
788     // }
789   }
790
791   /**
792    * Inform our interface that the selection has changed
793    */
794   public void selectionChanged()
795   {
796     // if (mnDialog != null) {
797     // // System.out.println("update dialog selection");
798     // mnDialog.updateSelection(new
799     // ArrayList<ChimeraStructuralObject>(chimSelectionList));
800     // }
801   }
802
803   public void launchAlignDialog(boolean useChains)
804   {
805     // TODO: [Optional] Use haveGUI flag
806     // Sometimes it does not appear in Windows
807     // if (!haveGUI) {
808     // return;
809     // }
810     // if (alDialog != null) {
811     // alDialog.setVisible(false);
812     // alDialog.dispose();
813     // }
814     // System.out.println("launch align dialog");
815     List<ChimeraStructuralObject> chimObjectList = new ArrayList<ChimeraStructuralObject>();
816     for (ChimeraModel model : chimeraManager.getChimeraModels())
817     {
818       if (useChains)
819       {
820         for (ChimeraChain chain : model.getChains())
821         {
822           chimObjectList.add(chain);
823         }
824       }
825       else
826       {
827         chimObjectList.add(model);
828       }
829     }
830     // Bring up the dialog
831     // CySwingApplication cyApplication = (CySwingApplication)
832     // getService(CySwingApplication.class);
833     // alDialog = new AlignStructuresDialog(cyApplication.getJFrame(), this,
834     // chimObjectList);
835     // alDialog.pack();
836     // alDialog.setVisible(true);
837   }
838
839   public List<String> getAllStructureKeys()
840   {
841     return Arrays.asList(defaultStructureKeys);
842   }
843
844   public List<String> getAllChemStructKeys()
845   {
846     return Arrays.asList(defaultChemStructKeys);
847   }
848
849   public List<String> getAllResidueKeys()
850   {
851     return Arrays.asList(defaultResidueKeys);
852   }
853
854   public List<String> getAllChimeraResidueAttributes()
855   {
856     List<String> attributes = new ArrayList<String>();
857     // attributes.addAll(rinManager.getResAttrs());
858     attributes.addAll(chimeraManager.getAttrList());
859     return attributes;
860   }
861
862   StructureSettings defaultSettings = null;
863
864   // TODO: [Optional] Change priority of Chimera paths
865   public List<String> getChimeraPaths()
866   {
867     List<String> pathList = new ArrayList<String>();
868
869     // if no network is available and the settings have been modified by the
870     // user, check for a
871     // path to chimera
872     if (defaultSettings != null)
873     {
874       String defaultPath = defaultSettings.getChimeraPath();
875       if (defaultPath != null && !defaultPath.equals(""))
876       {
877         pathList.add(defaultPath);
878         return pathList;
879       }
880     }
881
882     // if no network settings, check if the last chimera path is saved in the
883     // session
884     // String lastPath = CytoUtils.getDefaultChimeraPath(registrar,
885     // chimeraPropertyName,
886     // chimeraPathPropertyKey);
887     // if (lastPath != null && !lastPath.equals("")) {
888     // pathList.add(lastPath);
889     // return pathList;
890     // }
891
892     // if no user settings and no last path, get default system's settings
893     String os = System.getProperty("os.name");
894     if (os.startsWith("Linux"))
895     {
896       pathList.add("/usr/local/chimera/bin/chimera");
897       pathList.add("/usr/local/bin/chimera");
898       pathList.add("/usr/bin/chimera");
899     }
900     else if (os.startsWith("Windows"))
901     {
902       pathList.add("\\Program Files\\Chimera\\bin\\chimera");
903       pathList.add("C:\\Program Files\\Chimera\\bin\\chimera.exe");
904     }
905     else if (os.startsWith("Mac"))
906     {
907       pathList.add("/Applications/Chimera.app/Contents/MacOS/chimera");
908     }
909     return pathList;
910   }
911
912   public void setChimeraPathProperty(String path)
913   {
914     // CytoUtils.setDefaultChimeraPath(registrar, chimeraPropertyName,
915     // chimeraPathPropertyKey,
916     // path);
917   }
918
919   public void setStructureSettings(StructureSettings structureSettings)
920   {
921     this.defaultSettings = structureSettings;
922   }
923
924   public String getCurrentChimeraPath(Object object)
925   {
926     if (defaultSettings != null)
927     {
928       return defaultSettings.getChimeraPath();
929     }
930     else
931     {
932       return "";
933     }
934   }
935
936   // public void initChimTable() {
937   // CyTableManager manager = (CyTableManager) getService(CyTableManager.class);
938   // CyTableFactory factory = (CyTableFactory) getService(CyTableFactory.class);
939   // for (CyTable table : manager.getGlobalTables()) {
940   // if (table.getTitle().equals(chimeraOutputTable)) {
941   // manager.deleteTable(table.getSUID());
942   // }
943   // }
944   // chimTable = factory.createTable(chimeraOutputTable, chimeraCommandAttr,
945   // String.class,
946   // false, true);
947   // manager.addTable(chimTable);
948   // if (chimTable.getColumn(chimeraOutputAttr) == null) {
949   // chimTable.createListColumn(chimeraOutputAttr, String.class, false);
950   // }
951   // }
952
953   // public void addChimReply(String command, List<String> reply) {
954   // chimTable.getRow(command).set(chimeraOutputAttr, reply);
955   // }
956
957 }