3 * Copyright (c) 2006 The Regents of the University of California.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions, and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
15 * 3. Redistributions must acknowledge that this software was
16 * originally developed by the UCSF Computer Graphics Laboratory
17 * under support by the NIH National Center for Research Resources,
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 package ext.edu.ucsf.rbvi.strucviz2;
36 import java.io.IOException;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.Collection;
40 import java.util.HashMap;
41 import java.util.List;
43 import java.util.Properties;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
49 import jalview.bin.Cache;
50 import jalview.gui.Preferences;
53 * This object maintains the relationship between Chimera objects and Cytoscape
57 public class StructureManager
60 * Version numbers to build Windows installation paths for
61 * Chimera https://www.cgl.ucsf.edu/chimera/download.html
62 * ChimeraX http://www.rbvi.ucsf.edu/chimerax/download.html#release
63 * https://www.rbvi.ucsf.edu/trac/ChimeraX/wiki/ChangeLog
64 * These are a fallback for Jalview users who don't save path in Preferences;
65 * these will need to be updated as new versions are released;
66 * deliberately not 'final' (so modifiable using Groovy).
68 * May 2020: 1.14 is Chimera latest, anticipating a few more...
69 * 0.93 is ChimeraX latest, 1.0 expected soon
71 private static String[] CHIMERA_VERSIONS = new String[] { "1.16.2",
73 "1.15.2", "1.15.1", "1.15", "1.14.2", "1.14.1", "1.14",
74 "1.13.1", "1.13", "1.12.2", "1.12.1", "1.12", "1.11.2",
75 "1.11.2", "1.11.1", "1.11" };
77 private static String[] CHIMERAX_VERSIONS = new String[] { "1.0", "0.93",
78 "0.92", "0.91", "0.9" };
80 static final String[] defaultStructureKeys = { "Structure", "pdb",
81 "pdbFileName", "PDB ID", "structure", "biopax.xref.PDB", "pdb_ids",
82 "ModelName", "ModelNumber" };
84 static final String[] defaultChemStructKeys = { "Smiles", "smiles",
87 static final String[] defaultResidueKeys = { "FunctionalResidues",
88 "ResidueList", "Residues" };
92 PDB_MODEL, MODBASE_MODEL, SMILES
95 public static Properties pathProps;
97 private String chimeraCommandAttr = "ChimeraCommand";
99 private String chimeraOutputTable = "ChimeraTable";
101 private String chimeraOutputAttr = "ChimeraOutput";
103 private boolean haveGUI = true;
105 private ChimeraManager chimeraManager = null;
107 static private List<ChimeraStructuralObject> chimSelectionList;
109 private boolean ignoreCySelection = false;
111 private File configurationDirectory = null;
113 private static Logger logger = LoggerFactory
114 .getLogger(ext.edu.ucsf.rbvi.strucviz2.StructureManager.class);
116 public StructureManager(boolean haveGUI)
118 this.haveGUI = haveGUI;
119 // Create the Chimera interface
120 chimeraManager = new ChimeraManager(this);
121 chimSelectionList = new ArrayList<>();
122 pathProps = new Properties();
125 public ChimeraManager getChimeraManager()
127 return chimeraManager;
130 public boolean openStructures(Collection<List<String>> chimObjNames,
134 Map<String, List<ChimeraModel>> newModels = new HashMap<>();
135 if (chimObjNames.size() > 0)
137 List<String> names = chimObjNames.iterator().next();
142 for (String chimObjName : names)
144 // get or open the corresponding models if they already exist
145 List<ChimeraModel> currentModels = chimeraManager
146 .getChimeraModels(chimObjName, type);
147 if (currentModels.size() == 0)
149 // open and return models
150 currentModels = chimeraManager.openModel(chimObjName, type);
151 if (currentModels == null)
153 // failed to open model, continue with next
156 // if (type == ModelType.SMILES) {
157 // newModels.put("smiles:" + chimObjName, currentModels);
159 newModels.put(chimObjName, currentModels);
162 for (ChimeraModel currentModel : currentModels)
164 // if not RIN then associate new model with the Cytoscape
166 // if (!currentChimMap.containsKey(currentModel)) {
167 // currentChimMap.put(currentModel, new HashSet<CyIdentifiable>());
178 // if (mnDialog != null) {
179 // mnDialog.modelChanged();
181 // aTask.associate();
186 // TODO: [Release] Handle case where one network is associated with two models
190 * public boolean openStructures(CyNetwork network, Map<CyIdentifiable,
191 * List<String>> chimObjNames, ModelType type) { if
192 * (!chimeraManager.isChimeraLaunched() &&
193 * !chimeraManager.launchChimera(getChimeraPaths(network))) {
194 * logger.error("Chimera could not be launched."); return false; } else if
195 * (chimObjNames.size() == 0) { return false; } else if (network == null) {
196 * return openStructures(chimObjNames.values(), type); }
198 * // potential rins Set<CyNetwork> potentialRINs = new HashSet<CyNetwork>();
199 * // attributes List<String> attrsFound = new ArrayList<String>();
201 * addAll(CytoUtils.getMatchingAttributes(network.getDefaultNodeTable(),
202 * getCurrentStructureKeys(network)));
203 * attrsFound.addAll(CytoUtils.getMatchingAttributes
204 * (network.getDefaultNodeTable(), getCurrentChemStructKeys(network))); // new
205 * models Map<String, List<ChimeraModel>> newModels = new HashMap<String,
206 * List<ChimeraModel>>(); // for each node that has an associated structure
207 * for (CyIdentifiable cyObj : chimObjNames.keySet()) { // get possible res
208 * specs List<String> specsFound = null; if (cyObj instanceof CyNode) {
209 * specsFound = ChimUtils.getResidueKeys(network.getDefaultNodeTable(), cyObj,
210 * attrsFound); } // save node to track its selection and mapping to chimera
211 * objects if (!currentCyMap.containsKey(cyObj)) { currentCyMap.put(cyObj, new
212 * HashSet<ChimeraStructuralObject>()); } // save node to network mapping to
213 * keep track of selection events if (!networkMap.containsKey(cyObj)) {
214 * networkMap.put(cyObj, new HashSet<CyNetwork>()); }
215 * networkMap.get(cyObj).add(network); // for each structure that has to be
216 * opened for (String chimObjName : chimObjNames.get(cyObj)) { // get or open
217 * the corresponding models if they already exist List<ChimeraModel>
218 * currentModels = chimeraManager.getChimeraModels(chimObjName, type); if
219 * (currentModels.size() == 0) { // open and return models currentModels =
220 * chimeraManager.openModel(chimObjName, type); if (currentModels == null) {
221 * // failed to open model, continue with next continue; } // if (type ==
222 * ModelType.SMILES) { // newModels.put("smiles:" + chimObjName,
223 * currentModels); // } else { newModels.put(chimObjName, currentModels); // }
224 * // for each model for (ChimeraModel currentModel : currentModels) { //
225 * check if it is a RIN boolean foundRIN = false; if
226 * (currentModel.getModelType().equals(ModelType.PDB_MODEL)) { // go through
227 * all node annotations and check if any of them is a residue // or a chain if
228 * (cyObj instanceof CyNode && network.containsNode((CyNode) cyObj) &&
229 * specsFound != null && specsFound.size() > 0) { for (String resSpec :
230 * specsFound) { ChimeraStructuralObject res =
231 * ChimUtils.fromAttribute(resSpec, chimeraManager); if (res != null && (res
232 * instanceof ChimeraResidue || res instanceof ChimeraChain)) { // if so,
233 * assume it might be a RIN potentialRINs.add(network); foundRIN = true;
234 * break; } } } else if (cyObj instanceof CyNetwork) { // if cyObj is a
235 * network, check for residue/chain annotations in an // arbitrary node
236 * CyNetwork rinNet = (CyNetwork) cyObj; if (rinNet.getNodeList().size() > 0)
237 * { specsFound = ChimUtils.getResidueKeys( rinNet.getDefaultNodeTable(),
238 * rinNet.getNodeList().get(0), attrsFound); for (String resSpec : specsFound)
239 * { ChimeraStructuralObject res = ChimUtils.fromAttribute( resSpec,
240 * chimeraManager); if (res != null && (res instanceof ChimeraResidue || res
241 * instanceof ChimeraChain)) { potentialRINs.add(network); foundRIN = true;
242 * break; } } } } } if (foundRIN) { continue; } // if not RIN then associate
243 * new model with the Cytoscape // node if
244 * (!currentChimMap.containsKey(currentModel)) {
245 * currentChimMap.put(currentModel, new HashSet<CyIdentifiable>()); } String
246 * cyObjName = network.getRow(cyObj).get(CyNetwork.NAME, String.class); if
247 * (cyObjName != null && cyObjName.endsWith(currentModel.getModelName())) { //
248 * it is a modbase model, associate directly
249 * currentCyMap.get(cyObj).add(currentModel);
250 * currentChimMap.get(currentModel).add(cyObj);
251 * currentModel.addCyObject(cyObj, network); } else if (specsFound != null &&
252 * specsFound.size() > 0) { for (String resSpec : specsFound) {
253 * ChimeraStructuralObject specModel = ChimUtils.fromAttribute( resSpec,
254 * chimeraManager); if (specModel == null &&
255 * resSpec.equals(currentModel.getModelName())) { specModel =
256 * chimeraManager.getChimeraModel( currentModel.getModelNumber(),
257 * currentModel.getSubModelNumber()); } if (specModel != null &&
258 * currentModel.toSpec().equals(specModel.toSpec()) ||
259 * currentModel.getModelName().equals("smiles:" + resSpec)) {
260 * currentCyMap.get(cyObj).add(currentModel);
261 * currentChimMap.get(currentModel).add(cyObj);
262 * currentModel.addCyObject(cyObj, network);
263 * currentModel.setFuncResidues(ChimUtils.parseFuncRes(
264 * getResidueList(network, cyObj), chimObjName)); } } } } } } } // networks
265 * that contain nodes associated to newly opened models // this will usually
266 * be of length 1 for (CyNetwork net : potentialRINs) {
267 * addStructureNetwork(net); } // update dialog if (mnDialog != null) {
268 * mnDialog.modelChanged(); } aTask.associate(); return true; }
270 public void closeStructures(Set<String> chimObjNames)
272 // for each cytoscape object and chimera model pair
273 for (String modelName : chimObjNames)
275 List<ChimeraModel> models = chimeraManager
276 .getChimeraModels(modelName);
277 for (ChimeraModel model : models)
282 // if (mnDialog != null) {
283 // mnDialog.modelChanged();
287 // TODO: [Optional] Can we make a screenshot of a single molecule?
288 public File saveChimeraImage()
293 // Create the temp file name
294 tmpFile = File.createTempFile("structureViz", ".png");
295 chimeraManager.sendChimeraCommand("set bgTransparency", false);
296 chimeraManager.sendChimeraCommand(
297 "copy file " + tmpFile.getAbsolutePath() + " png", true);
298 chimeraManager.sendChimeraCommand("unset bgTransparency", false);
299 } catch (IOException ioe)
302 logger.error("Error writing image", ioe);
307 public void closeModel(ChimeraModel model)
309 // close model in Chimera
310 chimeraManager.closeModel(model);
311 // remove all associations
312 // if (currentChimMap.containsKey(model)) {
313 // for (CyIdentifiable cyObj : model.getCyObjects().keySet()) {
314 // if (cyObj == null) {
316 // } else if (currentCyMap.containsKey(cyObj)) {
317 // currentCyMap.get(cyObj).remove(model);
318 // } else if (cyObj instanceof CyNetwork) {
319 // for (ChimeraResidue residue : model.getResidues()) {
320 // if (currentChimMap.containsKey(residue)) {
321 // for (CyIdentifiable cyObjRes : currentChimMap.get(residue)) {
322 // if (currentCyMap.containsKey(cyObjRes)) {
323 // currentCyMap.get(cyObjRes).remove(residue);
326 // currentChimMap.remove(residue);
331 // currentChimMap.remove(model);
335 // public void addStructureNetwork(CyNetwork rin) {
336 // if (rin == null) {
339 // ChimeraModel model = null;
340 // // the network is not added to the model in the currentChimMap
341 // List<String> attrsFound =
342 // CytoUtils.getMatchingAttributes(rin.getDefaultNodeTable(),
343 // getCurrentStructureKeys(rin));
344 // for (CyNode node : rin.getNodeList()) {
345 // if (!networkMap.containsKey(node)) {
346 // networkMap.put(node, new HashSet<CyNetwork>());
348 // networkMap.get(node).add(rin);
349 // List<String> specsFound =
350 // ChimUtils.getResidueKeys(rin.getDefaultNodeTable(), node,
352 // for (String residueSpec : specsFound) {
353 // // if (!rin.getRow(node).isSet(ChimUtils.RESIDUE_ATTR)) {
356 // // String residueSpec = rin.getRow(node).get(ChimUtils.RESIDUE_ATTR,
358 // ChimeraStructuralObject chimObj = ChimUtils.fromAttribute(residueSpec,
360 // // chimObj.getChimeraModel().addCyObject(node, rin);
361 // if (chimObj == null || chimObj instanceof ChimeraModel) {
364 // model = chimObj.getChimeraModel();
365 // if (!currentCyMap.containsKey(node)) {
366 // currentCyMap.put(node, new HashSet<ChimeraStructuralObject>());
368 // currentCyMap.get(node).add(chimObj);
369 // if (!currentChimMap.containsKey(chimObj)) {
370 // currentChimMap.put(chimObj, new HashSet<CyIdentifiable>());
372 // currentChimMap.get(chimObj).add(node);
375 // if (model != null) {
376 // model.addCyObject(rin, rin);
377 // if (!currentCyMap.containsKey(rin)) {
378 // currentCyMap.put(rin, new HashSet<ChimeraStructuralObject>());
380 // currentCyMap.get(rin).add(model);
384 public void exitChimera()
386 // // exit chimera, invokes clearOnExitChimera
387 // if (mnDialog != null) {
388 // mnDialog.setVisible(false);
391 // if (alDialog != null) {
392 // alDialog.setVisible(false);
394 chimeraManager.exitChimera();
397 // invoked by ChimeraManager whenever Chimera exits
398 public void clearOnChimeraExit()
400 // // clear structures
401 // currentCyMap.clear();
402 // currentChimMap.clear();
403 // networkMap.clear();
404 chimSelectionList.clear();
405 // if (chimTable != null) {
407 // getService(CyTableManager.class)).deleteTable(chimTable.getSUID());
409 // if (mnDialog != null) {
410 // if (mnDialog.isVisible()) {
411 // mnDialog.lostChimera();
412 // mnDialog.setVisible(false);
415 // if (alDialog != null) {
416 // alDialog.setVisible(false);
421 // We need to do this in two passes since some parts of a structure might be
422 // selected and some might not. Our selection model (unfortunately) only
424 // us that something has changed, not what...
425 public void updateCytoscapeSelection()
427 // List<ChimeraStructuralObject> selectedChimObj
428 ignoreCySelection = true;
429 // System.out.println("update Cytoscape selection");
430 // find all possibly selected Cytoscape objects and unselect them
431 // Set<CyNetwork> networks = new HashSet<CyNetwork>();
432 // for (CyIdentifiable currentCyObj : currentCyMap.keySet()) {
433 // if (!networkMap.containsKey(currentCyObj)) {
436 // Set<CyNetwork> currentCyNetworks = networkMap.get(currentCyObj);
437 // if (currentCyNetworks == null || currentCyNetworks.size() == 0) {
441 // for (CyNetwork network : currentCyNetworks) {
442 // if ((currentCyObj instanceof CyNode && network.containsNode((CyNode)
444 // || (currentCyObj instanceof CyEdge && network
445 // .containsEdge((CyEdge) currentCyObj))) {
446 // network.getRow(currentCyObj).set(CyNetwork.SELECTED, false);
447 // networks.add(network);
452 // // select only those associated with selected Chimera objects
453 // Set<CyIdentifiable> currentCyObjs = new HashSet<CyIdentifiable>();
454 // for (ChimeraStructuralObject chimObj : chimSelectionList) {
455 // ChimeraModel currentSelModel = chimObj.getChimeraModel();
456 // if (currentChimMap.containsKey(currentSelModel)) {
457 // currentCyObjs.addAll(currentChimMap.get(currentSelModel));
459 // if (currentChimMap.containsKey(chimObj)) {
460 // currentCyObjs.addAll(currentChimMap.get(chimObj));
462 // // System.out.println(chimObj.toSpec() + ": " +
463 // // currentCyObjs.size());
465 // for (CyIdentifiable cyObj : currentCyObjs) {
466 // // System.out.println(cyObj.toString());
467 // if (cyObj == null || !networkMap.containsKey(cyObj)) {
470 // Set<CyNetwork> currentCyNetworks = networkMap.get(cyObj);
471 // if (currentCyNetworks == null || currentCyNetworks.size() == 0) {
474 // for (CyNetwork network : currentCyNetworks) {
475 // if ((cyObj instanceof CyNode && network.containsNode((CyNode) cyObj))
476 // || (cyObj instanceof CyEdge && network.containsEdge((CyEdge) cyObj))) {
477 // network.getRow(cyObj).set(CyNetwork.SELECTED, true);
478 // networks.add(network);
483 // CyNetworkViewManager cyNetViewManager = (CyNetworkViewManager)
484 // getService(CyNetworkViewManager.class);
485 // // Update network views
486 // for (CyNetwork network : networks) {
487 // Collection<CyNetworkView> views =
488 // cyNetViewManager.getNetworkViews(network);
489 // for (CyNetworkView view : views) {
490 // view.updateView();
493 ignoreCySelection = false;
496 public void cytoscapeSelectionChanged(Map<Long, Boolean> selectedRows)
498 // if (ignoreCySelection || currentCyMap.size() == 0) {
501 // // clearSelectionList();
502 // // System.out.println("cytoscape selection changed");
503 // // iterate over all cy objects with associated models
504 // for (CyIdentifiable cyObj : currentCyMap.keySet()) {
505 // if (cyObj instanceof CyNetwork ||
506 // !selectedRows.containsKey(cyObj.getSUID())) {
509 // for (ChimeraStructuralObject chimObj : currentCyMap.get(cyObj)) {
510 // if (selectedRows.get(cyObj.getSUID())) {
511 // addChimSelection(chimObj);
512 // if (chimObj instanceof ChimeraResidue) {
513 // if (chimObj.getChimeraModel().isSelected()) {
514 // removeChimSelection(chimObj.getChimeraModel());
515 // } else if (chimObj.getChimeraModel()
516 // .getChain(((ChimeraResidue) chimObj).getChainId()).isSelected()) {
517 // removeChimSelection(chimObj.getChimeraModel().getChain(
518 // ((ChimeraResidue) chimObj).getChainId()));
522 // removeChimSelection(chimObj);
523 // if (chimObj.hasSelectedChildren() && chimObj instanceof ChimeraModel) {
524 // for (ChimeraResidue residue : ((ChimeraModel) chimObj)
525 // .getSelectedResidues()) {
526 // removeChimSelection(residue);
532 // System.out.println("selection list: " + getChimSelectionCount());
533 updateChimeraSelection();
537 // Save models in a HashMap/Set for better performance?
538 public void updateChimeraSelection()
540 // System.out.println("update Chimera selection");
542 for (int i = 0; i < chimSelectionList.size(); i++)
544 ChimeraStructuralObject nodeInfo = chimSelectionList.get(i);
545 // we do not care about the model anymore
546 selSpec = selSpec.concat(nodeInfo.toSpec());
547 if (i < chimSelectionList.size() - 1)
552 if (selSpec.length() > 0)
554 chimeraManager.select("sel " + selSpec);
558 chimeraManager.select("~sel");
563 * This is called by the selectionListener to let us know that the user has
564 * changed their selection in Chimera. We need to go back to Chimera to find
565 * out what is currently selected and update our list.
567 public void chimeraSelectionChanged()
569 // System.out.println("Chimera selection changed");
570 clearSelectionList();
571 // Execute the command to get the list of models with selections
572 Map<Integer, ChimeraModel> selectedModelsMap = chimeraManager
573 .getSelectedModels();
574 // Now get the residue-level data
575 chimeraManager.getSelectedResidues(selectedModelsMap);
576 // Get the selected objects
579 for (ChimeraModel selectedModel : selectedModelsMap.values())
581 int modelNumber = selectedModel.getModelNumber();
582 int subModelNumber = selectedModel.getSubModelNumber();
583 // Get the corresponding "real" model
584 if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber))
586 ChimeraModel dataModel = chimeraManager
587 .getChimeraModel(modelNumber, subModelNumber);
588 if (dataModel.getResidueCount() == selectedModel.getResidueCount()
590 .getModelType() == StructureManager.ModelType.SMILES)
592 // Select the entire model
593 addChimSelection(dataModel);
594 // dataModel.setSelected(true);
598 for (ChimeraChain selectedChain : selectedModel.getChains())
600 ChimeraChain dataChain = dataModel
601 .getChain(selectedChain.getChainId());
602 if (selectedChain.getResidueCount() == dataChain
605 addChimSelection(dataChain);
606 // dataChain.setSelected(true);
609 // Need to select individual residues
610 for (ChimeraResidue res : selectedChain.getResidues())
612 String residueIndex = res.getIndex();
613 ChimeraResidue residue = dataChain.getResidue(residueIndex);
618 addChimSelection(residue);
619 // residue.setSelected(true);
622 } // chainIter.hasNext()
625 } // modelIter.hasNext()
626 } catch (Exception ex)
628 logger.warn("Could not update selection", ex);
630 // System.out.println("selection list: " + getChimSelectionCount());
631 // Finally, update the navigator panel
633 updateCytoscapeSelection();
636 public void selectFunctResidues(Collection<ChimeraModel> models)
638 clearSelectionList();
639 for (ChimeraModel model : models)
641 for (ChimeraResidue residue : model.getFuncResidues())
643 addChimSelection(residue);
646 updateChimeraSelection();
647 updateCytoscapeSelection();
651 // public void selectFunctResidues(CyNode node, CyNetwork network) {
652 // clearSelectionList();
653 // if (currentCyMap.containsKey(node)) {
654 // Set<ChimeraStructuralObject> chimObjects = currentCyMap.get(node);
655 // for (ChimeraStructuralObject obj : chimObjects) {
656 // if (obj instanceof ChimeraModel) {
657 // ChimeraModel model = (ChimeraModel) obj;
658 // for (ChimeraResidue residue : model.getFuncResidues()) {
659 // addChimSelection(residue);
664 // updateChimeraSelection();
665 // updateCytoscapeSelection();
666 // selectionChanged();
669 public List<ChimeraStructuralObject> getChimSelectionList()
671 return chimSelectionList;
674 public int getChimSelectionCount()
676 return chimSelectionList.size();
680 * Add a selection to the selection list. This is called primarily by the
681 * Model Navigator Dialog to keep the selections in sync
683 * @param selectionToAdd
684 * the selection to add to our list
686 public void addChimSelection(ChimeraStructuralObject selectionToAdd)
688 if (selectionToAdd != null
689 && !chimSelectionList.contains(selectionToAdd))
691 chimSelectionList.add(selectionToAdd);
692 selectionToAdd.setSelected(true);
697 * Remove a selection from the selection list. This is called primarily by the
698 * Model Navigator Dialog to keep the selections in sync
700 * @param selectionToRemove
701 * the selection to remove from our list
703 public void removeChimSelection(ChimeraStructuralObject selectionToRemove)
705 if (selectionToRemove != null
706 && chimSelectionList.contains(selectionToRemove))
708 chimSelectionList.remove(selectionToRemove);
709 selectionToRemove.setSelected(false);
714 * Clear the list of selected objects
716 public void clearSelectionList()
718 for (ChimeraStructuralObject cso : chimSelectionList)
722 cso.setSelected(false);
725 chimSelectionList.clear();
729 * Associate a new network with the corresponding Chimera objects.
735 * Dump and refresh all of our model/chain/residue info
737 public void updateModels()
739 // Stop all of our listeners while we try to handle this
740 chimeraManager.stopListening();
742 // Get all of the open models
743 List<ChimeraModel> newModelList = chimeraManager.getModelList();
745 // Match them up -- assume that the model #'s haven't changed
746 for (ChimeraModel newModel : newModelList)
748 // Get the color (for our navigator)
749 newModel.setModelColor(chimeraManager.getModelColor(newModel));
751 // Get our model info
752 int modelNumber = newModel.getModelNumber();
753 int subModelNumber = newModel.getSubModelNumber();
755 // If we already know about this model number, get the Structure,
756 // which tells us about the associated CyNode
757 if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber))
759 ChimeraModel oldModel = chimeraManager.getChimeraModel(modelNumber,
761 chimeraManager.removeChimeraModel(modelNumber, subModelNumber);
762 newModel.setModelType(oldModel.getModelType());
763 if (oldModel.getModelType() == ModelType.SMILES)
765 newModel.setModelName(oldModel.getModelName());
767 // re-assign associations to cytoscape objects
768 // Map<CyIdentifiable, CyNetwork> oldModelCyObjs =
769 // oldModel.getCyObjects();
770 // for (CyIdentifiable cyObj : oldModelCyObjs.keySet()) {
771 // // add cy objects to the new model
772 // newModel.addCyObject(cyObj, oldModelCyObjs.get(cyObj));
773 // if (currentCyMap.containsKey(cyObj)) {
774 // currentCyMap.get(cyObj).add(newModel);
775 // if (currentCyMap.get(cyObj).contains(oldModel)) {
776 // currentCyMap.get(cyObj).remove(oldModel);
780 // // add new model to the chimera objects map and remove old model
781 // if (currentChimMap.containsKey(oldModel)) {
782 // currentChimMap.put(newModel, currentChimMap.get(oldModel));
783 // currentChimMap.remove(oldModel);
786 // add new model to ChimeraManager
787 chimeraManager.addChimeraModel(modelNumber, subModelNumber, newModel);
789 // Get the residue information
790 if (newModel.getModelType() != ModelType.SMILES)
792 chimeraManager.addResidues(newModel);
794 // for (CyIdentifiable cyObj : newModel.getCyObjects().keySet()) {
795 // if (cyObj != null && cyObj instanceof CyNetwork) {
796 // addStructureNetwork((CyNetwork) cyObj);
797 // } else if (cyObj != null && cyObj instanceof CyNode) {
798 // newModel.setFuncResidues(ChimUtils.parseFuncRes(
799 // getResidueList(newModel.getCyObjects().get(cyObj), cyObj),
800 // newModel.getModelName()));
805 // associate all models with any node or network
806 // aTask.associate();
808 // Restart all of our listeners
809 chimeraManager.startListening();
813 public void launchModelNavigatorDialog()
815 // TODO: [Optional] Use haveGUI flag
819 // if (mnDialog == null) {
820 // CySwingApplication cyApplication = (CySwingApplication)
821 // getService(CySwingApplication.class);
822 // mnDialog = new ModelNavigatorDialog(cyApplication.getJFrame(), this);
825 // mnDialog.setVisible(true);
828 public boolean isMNDialogOpen()
830 // if (mnDialog != null && mnDialog.isVisible()) {
837 * Invoked by the listener thread.
839 public void modelChanged()
841 // if (mnDialog != null) {
842 // mnDialog.modelChanged();
847 * Inform our interface that the selection has changed
849 public void selectionChanged()
851 // if (mnDialog != null) {
852 // // System.out.println("update dialog selection");
853 // mnDialog.updateSelection(new
854 // ArrayList<ChimeraStructuralObject>(chimSelectionList));
858 public void launchAlignDialog(boolean useChains)
860 // TODO: [Optional] Use haveGUI flag
861 // Sometimes it does not appear in Windows
865 // if (alDialog != null) {
866 // alDialog.setVisible(false);
867 // alDialog.dispose();
869 // System.out.println("launch align dialog");
870 List<ChimeraStructuralObject> chimObjectList = new ArrayList<>();
871 for (ChimeraModel model : chimeraManager.getChimeraModels())
875 for (ChimeraChain chain : model.getChains())
877 chimObjectList.add(chain);
882 chimObjectList.add(model);
885 // Bring up the dialog
886 // CySwingApplication cyApplication = (CySwingApplication)
887 // getService(CySwingApplication.class);
888 // alDialog = new AlignStructuresDialog(cyApplication.getJFrame(), this,
891 // alDialog.setVisible(true);
894 public List<String> getAllStructureKeys()
896 return Arrays.asList(defaultStructureKeys);
899 public List<String> getAllChemStructKeys()
901 return Arrays.asList(defaultChemStructKeys);
904 public List<String> getAllResidueKeys()
906 return Arrays.asList(defaultResidueKeys);
909 public List<String> getAllChimeraResidueAttributes()
911 List<String> attributes = new ArrayList<>();
912 // attributes.addAll(rinManager.getResAttrs());
913 attributes.addAll(chimeraManager.getAttrList());
917 StructureSettings defaultSettings = null;
919 // TODO: [Optional] Change priority of Chimera paths
920 public static List<String> getChimeraPaths(boolean isChimeraX)
922 List<String> pathList = new ArrayList<>();
924 // if no network is available and the settings have been modified by the
928 // For Jalview, Preferences/Cache plays this role instead
929 // if (defaultSettings != null)
931 // String defaultPath = defaultSettings.getChimeraPath();
932 // if (defaultPath != null && !defaultPath.equals(""))
934 // pathList.add(defaultPath);
940 * Jalview addition: check if path set in user preferences
942 String userPath = Cache
943 .getDefault(isChimeraX ? Preferences.CHIMERAX_PATH
944 : Preferences.CHIMERA_PATH, null);
945 if (userPath != null)
947 pathList.add(userPath);
951 * paths are based on getChimeraPaths() in
953 * https://github.com/RBVI/structureViz2/blob/master/src/main/java/edu/ucsf/rbvi/structureViz2/internal/model/StructureManager.java
955 * https://github.com/RBVI/structureVizX/blob/master/src/main/java/edu/ucsf/rbvi/structureVizX/internal/model/StructureManager.java
957 String chimera = isChimeraX ? "ChimeraX" : "Chimera";
958 String chimeraExe = isChimeraX ? "ChimeraX" : "chimera";
960 // Add default installation paths
961 String os = System.getProperty("os.name");
962 if (os.startsWith("Linux"))
964 // todo should this be /chimeraX/ for ChimeraX? not in structureVizX code
965 pathList.add("/usr/local/chimera/bin/" + chimeraExe);
966 pathList.add("/usr/local/bin/" + chimeraExe);
967 pathList.add("/usr/bin/" + chimeraExe);
968 pathList.add(System.getProperty("user.home") + "/opt/bin/" + chimeraExe);
970 else if (os.startsWith("Windows"))
972 for (String root : new String[] { "\\Program Files",
973 "C:\\Program Files", "\\Program Files (x86)",
974 "C:\\Program Files (x86)" })
976 String[] candidates = isChimeraX ? CHIMERAX_VERSIONS
978 for (String version : candidates)
980 // TODO original code doesn't include version in path; which is right?
981 String path = String.format("%s\\%s %s\\bin\\%s", root, chimera,
982 version, chimeraExe);
984 pathList.add(path + ".exe");
988 else if (os.startsWith("Mac"))
990 pathList.add(String.format("/Applications/%s.app/Contents/MacOS/%s",
991 chimera, chimeraExe));
996 public void setChimeraPathProperty(String path)
998 // CytoUtils.setDefaultChimeraPath(registrar, chimeraPropertyName,
999 // chimeraPathPropertyKey,
1003 public void setStructureSettings(StructureSettings structureSettings)
1005 this.defaultSettings = structureSettings;
1008 public String getCurrentChimeraPath(Object object)
1010 if (defaultSettings != null)
1012 return defaultSettings.getChimeraPath();
1020 // public void initChimTable() {
1021 // CyTableManager manager = (CyTableManager) getService(CyTableManager.class);
1022 // CyTableFactory factory = (CyTableFactory) getService(CyTableFactory.class);
1023 // for (CyTable table : manager.getGlobalTables()) {
1024 // if (table.getTitle().equals(chimeraOutputTable)) {
1025 // manager.deleteTable(table.getSUID());
1028 // chimTable = factory.createTable(chimeraOutputTable, chimeraCommandAttr,
1031 // manager.addTable(chimTable);
1032 // if (chimTable.getColumn(chimeraOutputAttr) == null) {
1033 // chimTable.createListColumn(chimeraOutputAttr, String.class, false);
1037 // public void addChimReply(String command, List<String> reply) {
1038 // chimTable.getRow(command).set(chimeraOutputAttr, reply);