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