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;
42 import java.util.Locale;
44 import java.util.Properties;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 import jalview.bin.Cache;
51 import jalview.gui.Preferences;
54 * This object maintains the relationship between Chimera objects and Cytoscape
58 public class StructureManager
61 * Version numbers to build Windows installation paths for
62 * Chimera https://www.cgl.ucsf.edu/chimera/download.html
63 * ChimeraX http://www.rbvi.ucsf.edu/chimerax/download.html#release
64 * https://www.rbvi.ucsf.edu/trac/ChimeraX/wiki/ChangeLog
65 * These are a fallback for Jalview users who don't save path in Preferences;
66 * these will need to be updated as new versions are released;
67 * deliberately not 'final' (so modifiable using Groovy).
69 * May 2020: 1.14 is Chimera latest, anticipating a few more...
70 * 0.93 is ChimeraX latest, 1.0 expected soon
72 private static String[] CHIMERA_VERSIONS = new String[] { "1.16.2",
73 "1.16.1", "1.16", "1.15.2", "1.15.1", "1.15", "1.14.2", "1.14.1",
74 "1.14", "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 // Missing 1.1 as this has known bug see JAL-2422
78 private static String[] CHIMERAX_VERSIONS = new String[] { "1.3", "1.2.5",
79 "1.0", "0.93", "0.92", "0.91", "0.9" };
81 static final String[] defaultStructureKeys = { "Structure", "pdb",
82 "pdbFileName", "PDB ID", "structure", "biopax.xref.PDB", "pdb_ids",
83 "ModelName", "ModelNumber" };
85 static final String[] defaultChemStructKeys = { "Smiles", "smiles",
88 static final String[] defaultResidueKeys = { "FunctionalResidues",
89 "ResidueList", "Residues" };
93 PDB_MODEL, MODBASE_MODEL, SMILES
96 public static Properties pathProps;
98 private String chimeraCommandAttr = "ChimeraCommand";
100 private String chimeraOutputTable = "ChimeraTable";
102 private String chimeraOutputAttr = "ChimeraOutput";
104 private boolean haveGUI = true;
106 private ChimeraManager chimeraManager = null;
108 static private List<ChimeraStructuralObject> chimSelectionList;
110 private boolean ignoreCySelection = false;
112 private File configurationDirectory = null;
114 private static Logger logger = LoggerFactory
115 .getLogger(ext.edu.ucsf.rbvi.strucviz2.StructureManager.class);
117 public StructureManager(boolean haveGUI)
119 this.haveGUI = haveGUI;
120 // Create the Chimera interface
121 chimeraManager = new ChimeraManager(this);
122 chimSelectionList = new ArrayList<>();
123 pathProps = new Properties();
126 public ChimeraManager getChimeraManager()
128 return chimeraManager;
131 public boolean openStructures(Collection<List<String>> chimObjNames,
135 Map<String, List<ChimeraModel>> newModels = new HashMap<>();
136 if (chimObjNames.size() > 0)
138 List<String> names = chimObjNames.iterator().next();
143 for (String chimObjName : names)
145 // get or open the corresponding models if they already exist
146 List<ChimeraModel> currentModels = chimeraManager
147 .getChimeraModels(chimObjName, type);
148 if (currentModels.size() == 0)
150 // open and return models
151 currentModels = chimeraManager.openModel(chimObjName, type);
152 if (currentModels == null)
154 // failed to open model, continue with next
157 // if (type == ModelType.SMILES) {
158 // newModels.put("smiles:" + chimObjName, currentModels);
160 newModels.put(chimObjName, currentModels);
163 for (ChimeraModel currentModel : currentModels)
165 // if not RIN then associate new model with the Cytoscape
167 // if (!currentChimMap.containsKey(currentModel)) {
168 // currentChimMap.put(currentModel, new HashSet<CyIdentifiable>());
179 // if (mnDialog != null) {
180 // mnDialog.modelChanged();
182 // aTask.associate();
187 // TODO: [Release] Handle case where one network is associated with two models
191 * public boolean openStructures(CyNetwork network, Map<CyIdentifiable,
192 * List<String>> chimObjNames, ModelType type) { if
193 * (!chimeraManager.isChimeraLaunched() &&
194 * !chimeraManager.launchChimera(getChimeraPaths(network))) {
195 * logger.error("Chimera could not be launched."); return false; } else if
196 * (chimObjNames.size() == 0) { return false; } else if (network == null) {
197 * return openStructures(chimObjNames.values(), type); }
199 * // potential rins Set<CyNetwork> potentialRINs = new HashSet<CyNetwork>();
200 * // attributes List<String> attrsFound = new ArrayList<String>();
202 * addAll(CytoUtils.getMatchingAttributes(network.getDefaultNodeTable(),
203 * getCurrentStructureKeys(network)));
204 * attrsFound.addAll(CytoUtils.getMatchingAttributes
205 * (network.getDefaultNodeTable(), getCurrentChemStructKeys(network))); // new
206 * models Map<String, List<ChimeraModel>> newModels = new HashMap<String,
207 * List<ChimeraModel>>(); // for each node that has an associated structure
208 * for (CyIdentifiable cyObj : chimObjNames.keySet()) { // get possible res
209 * specs List<String> specsFound = null; if (cyObj instanceof CyNode) {
210 * specsFound = ChimUtils.getResidueKeys(network.getDefaultNodeTable(), cyObj,
211 * attrsFound); } // save node to track its selection and mapping to chimera
212 * objects if (!currentCyMap.containsKey(cyObj)) { currentCyMap.put(cyObj, new
213 * HashSet<ChimeraStructuralObject>()); } // save node to network mapping to
214 * keep track of selection events if (!networkMap.containsKey(cyObj)) {
215 * networkMap.put(cyObj, new HashSet<CyNetwork>()); }
216 * networkMap.get(cyObj).add(network); // for each structure that has to be
217 * opened for (String chimObjName : chimObjNames.get(cyObj)) { // get or open
218 * the corresponding models if they already exist List<ChimeraModel>
219 * currentModels = chimeraManager.getChimeraModels(chimObjName, type); if
220 * (currentModels.size() == 0) { // open and return models currentModels =
221 * chimeraManager.openModel(chimObjName, type); if (currentModels == null) {
222 * // failed to open model, continue with next continue; } // if (type ==
223 * ModelType.SMILES) { // newModels.put("smiles:" + chimObjName,
224 * currentModels); // } else { newModels.put(chimObjName, currentModels); // }
225 * // for each model for (ChimeraModel currentModel : currentModels) { //
226 * check if it is a RIN boolean foundRIN = false; if
227 * (currentModel.getModelType().equals(ModelType.PDB_MODEL)) { // go through
228 * all node annotations and check if any of them is a residue // or a chain if
229 * (cyObj instanceof CyNode && network.containsNode((CyNode) cyObj) &&
230 * specsFound != null && specsFound.size() > 0) { for (String resSpec :
231 * specsFound) { ChimeraStructuralObject res =
232 * ChimUtils.fromAttribute(resSpec, chimeraManager); if (res != null && (res
233 * instanceof ChimeraResidue || res instanceof ChimeraChain)) { // if so,
234 * assume it might be a RIN potentialRINs.add(network); foundRIN = true;
235 * break; } } } else if (cyObj instanceof CyNetwork) { // if cyObj is a
236 * network, check for residue/chain annotations in an // arbitrary node
237 * CyNetwork rinNet = (CyNetwork) cyObj; if (rinNet.getNodeList().size() > 0)
238 * { specsFound = ChimUtils.getResidueKeys( rinNet.getDefaultNodeTable(),
239 * rinNet.getNodeList().get(0), attrsFound); for (String resSpec : specsFound)
240 * { ChimeraStructuralObject res = ChimUtils.fromAttribute( resSpec,
241 * chimeraManager); if (res != null && (res instanceof ChimeraResidue || res
242 * instanceof ChimeraChain)) { potentialRINs.add(network); foundRIN = true;
243 * break; } } } } } if (foundRIN) { continue; } // if not RIN then associate
244 * new model with the Cytoscape // node if
245 * (!currentChimMap.containsKey(currentModel)) {
246 * currentChimMap.put(currentModel, new HashSet<CyIdentifiable>()); } String
247 * cyObjName = network.getRow(cyObj).get(CyNetwork.NAME, String.class); if
248 * (cyObjName != null && cyObjName.endsWith(currentModel.getModelName())) { //
249 * it is a modbase model, associate directly
250 * currentCyMap.get(cyObj).add(currentModel);
251 * currentChimMap.get(currentModel).add(cyObj);
252 * currentModel.addCyObject(cyObj, network); } else if (specsFound != null &&
253 * specsFound.size() > 0) { for (String resSpec : specsFound) {
254 * ChimeraStructuralObject specModel = ChimUtils.fromAttribute( resSpec,
255 * chimeraManager); if (specModel == null &&
256 * resSpec.equals(currentModel.getModelName())) { specModel =
257 * chimeraManager.getChimeraModel( currentModel.getModelNumber(),
258 * currentModel.getSubModelNumber()); } if (specModel != null &&
259 * currentModel.toSpec().equals(specModel.toSpec()) ||
260 * currentModel.getModelName().equals("smiles:" + resSpec)) {
261 * currentCyMap.get(cyObj).add(currentModel);
262 * currentChimMap.get(currentModel).add(cyObj);
263 * currentModel.addCyObject(cyObj, network);
264 * currentModel.setFuncResidues(ChimUtils.parseFuncRes(
265 * getResidueList(network, cyObj), chimObjName)); } } } } } } } // networks
266 * that contain nodes associated to newly opened models // this will usually
267 * be of length 1 for (CyNetwork net : potentialRINs) {
268 * addStructureNetwork(net); } // update dialog if (mnDialog != null) {
269 * mnDialog.modelChanged(); } aTask.associate(); return true; }
271 public void closeStructures(Set<String> chimObjNames)
273 // for each cytoscape object and chimera model pair
274 for (String modelName : chimObjNames)
276 List<ChimeraModel> models = chimeraManager
277 .getChimeraModels(modelName);
278 for (ChimeraModel model : models)
283 // if (mnDialog != null) {
284 // mnDialog.modelChanged();
288 // TODO: [Optional] Can we make a screenshot of a single molecule?
289 public File saveChimeraImage()
294 // Create the temp file name
295 tmpFile = File.createTempFile("structureViz", ".png");
296 chimeraManager.sendChimeraCommand("set bgTransparency", false);
297 chimeraManager.sendChimeraCommand(
298 "copy file " + tmpFile.getAbsolutePath() + " png", true);
299 chimeraManager.sendChimeraCommand("unset bgTransparency", false);
300 } catch (IOException ioe)
303 logger.error("Error writing image", ioe);
308 public void closeModel(ChimeraModel model)
310 // close model in Chimera
311 chimeraManager.closeModel(model);
312 // remove all associations
313 // if (currentChimMap.containsKey(model)) {
314 // for (CyIdentifiable cyObj : model.getCyObjects().keySet()) {
315 // if (cyObj == null) {
317 // } else if (currentCyMap.containsKey(cyObj)) {
318 // currentCyMap.get(cyObj).remove(model);
319 // } else if (cyObj instanceof CyNetwork) {
320 // for (ChimeraResidue residue : model.getResidues()) {
321 // if (currentChimMap.containsKey(residue)) {
322 // for (CyIdentifiable cyObjRes : currentChimMap.get(residue)) {
323 // if (currentCyMap.containsKey(cyObjRes)) {
324 // currentCyMap.get(cyObjRes).remove(residue);
327 // currentChimMap.remove(residue);
332 // currentChimMap.remove(model);
336 // public void addStructureNetwork(CyNetwork rin) {
337 // if (rin == null) {
340 // ChimeraModel model = null;
341 // // the network is not added to the model in the currentChimMap
342 // List<String> attrsFound =
343 // CytoUtils.getMatchingAttributes(rin.getDefaultNodeTable(),
344 // getCurrentStructureKeys(rin));
345 // for (CyNode node : rin.getNodeList()) {
346 // if (!networkMap.containsKey(node)) {
347 // networkMap.put(node, new HashSet<CyNetwork>());
349 // networkMap.get(node).add(rin);
350 // List<String> specsFound =
351 // ChimUtils.getResidueKeys(rin.getDefaultNodeTable(), node,
353 // for (String residueSpec : specsFound) {
354 // // if (!rin.getRow(node).isSet(ChimUtils.RESIDUE_ATTR)) {
357 // // String residueSpec = rin.getRow(node).get(ChimUtils.RESIDUE_ATTR,
359 // ChimeraStructuralObject chimObj = ChimUtils.fromAttribute(residueSpec,
361 // // chimObj.getChimeraModel().addCyObject(node, rin);
362 // if (chimObj == null || chimObj instanceof ChimeraModel) {
365 // model = chimObj.getChimeraModel();
366 // if (!currentCyMap.containsKey(node)) {
367 // currentCyMap.put(node, new HashSet<ChimeraStructuralObject>());
369 // currentCyMap.get(node).add(chimObj);
370 // if (!currentChimMap.containsKey(chimObj)) {
371 // currentChimMap.put(chimObj, new HashSet<CyIdentifiable>());
373 // currentChimMap.get(chimObj).add(node);
376 // if (model != null) {
377 // model.addCyObject(rin, rin);
378 // if (!currentCyMap.containsKey(rin)) {
379 // currentCyMap.put(rin, new HashSet<ChimeraStructuralObject>());
381 // currentCyMap.get(rin).add(model);
385 public void exitChimera()
387 // // exit chimera, invokes clearOnExitChimera
388 // if (mnDialog != null) {
389 // mnDialog.setVisible(false);
392 // if (alDialog != null) {
393 // alDialog.setVisible(false);
395 chimeraManager.exitChimera();
398 // invoked by ChimeraManager whenever Chimera exits
399 public void clearOnChimeraExit()
401 // // clear structures
402 // currentCyMap.clear();
403 // currentChimMap.clear();
404 // networkMap.clear();
405 chimSelectionList.clear();
406 // if (chimTable != null) {
408 // getService(CyTableManager.class)).deleteTable(chimTable.getSUID());
410 // if (mnDialog != null) {
411 // if (mnDialog.isVisible()) {
412 // mnDialog.lostChimera();
413 // mnDialog.setVisible(false);
416 // if (alDialog != null) {
417 // alDialog.setVisible(false);
422 // We need to do this in two passes since some parts of a structure might be
423 // selected and some might not. Our selection model (unfortunately) only
425 // us that something has changed, not what...
426 public void updateCytoscapeSelection()
428 // List<ChimeraStructuralObject> selectedChimObj
429 ignoreCySelection = true;
430 // System.out.println("update Cytoscape selection");
431 // find all possibly selected Cytoscape objects and unselect them
432 // Set<CyNetwork> networks = new HashSet<CyNetwork>();
433 // for (CyIdentifiable currentCyObj : currentCyMap.keySet()) {
434 // if (!networkMap.containsKey(currentCyObj)) {
437 // Set<CyNetwork> currentCyNetworks = networkMap.get(currentCyObj);
438 // if (currentCyNetworks == null || currentCyNetworks.size() == 0) {
442 // for (CyNetwork network : currentCyNetworks) {
443 // if ((currentCyObj instanceof CyNode && network.containsNode((CyNode)
445 // || (currentCyObj instanceof CyEdge && network
446 // .containsEdge((CyEdge) currentCyObj))) {
447 // network.getRow(currentCyObj).set(CyNetwork.SELECTED, false);
448 // networks.add(network);
453 // // select only those associated with selected Chimera objects
454 // Set<CyIdentifiable> currentCyObjs = new HashSet<CyIdentifiable>();
455 // for (ChimeraStructuralObject chimObj : chimSelectionList) {
456 // ChimeraModel currentSelModel = chimObj.getChimeraModel();
457 // if (currentChimMap.containsKey(currentSelModel)) {
458 // currentCyObjs.addAll(currentChimMap.get(currentSelModel));
460 // if (currentChimMap.containsKey(chimObj)) {
461 // currentCyObjs.addAll(currentChimMap.get(chimObj));
463 // // System.out.println(chimObj.toSpec() + ": " +
464 // // currentCyObjs.size());
466 // for (CyIdentifiable cyObj : currentCyObjs) {
467 // // System.out.println(cyObj.toString());
468 // if (cyObj == null || !networkMap.containsKey(cyObj)) {
471 // Set<CyNetwork> currentCyNetworks = networkMap.get(cyObj);
472 // if (currentCyNetworks == null || currentCyNetworks.size() == 0) {
475 // for (CyNetwork network : currentCyNetworks) {
476 // if ((cyObj instanceof CyNode && network.containsNode((CyNode) cyObj))
477 // || (cyObj instanceof CyEdge && network.containsEdge((CyEdge) cyObj))) {
478 // network.getRow(cyObj).set(CyNetwork.SELECTED, true);
479 // networks.add(network);
484 // CyNetworkViewManager cyNetViewManager = (CyNetworkViewManager)
485 // getService(CyNetworkViewManager.class);
486 // // Update network views
487 // for (CyNetwork network : networks) {
488 // Collection<CyNetworkView> views =
489 // cyNetViewManager.getNetworkViews(network);
490 // for (CyNetworkView view : views) {
491 // view.updateView();
494 ignoreCySelection = false;
497 public void cytoscapeSelectionChanged(Map<Long, Boolean> selectedRows)
499 // if (ignoreCySelection || currentCyMap.size() == 0) {
502 // // clearSelectionList();
503 // // System.out.println("cytoscape selection changed");
504 // // iterate over all cy objects with associated models
505 // for (CyIdentifiable cyObj : currentCyMap.keySet()) {
506 // if (cyObj instanceof CyNetwork ||
507 // !selectedRows.containsKey(cyObj.getSUID())) {
510 // for (ChimeraStructuralObject chimObj : currentCyMap.get(cyObj)) {
511 // if (selectedRows.get(cyObj.getSUID())) {
512 // addChimSelection(chimObj);
513 // if (chimObj instanceof ChimeraResidue) {
514 // if (chimObj.getChimeraModel().isSelected()) {
515 // removeChimSelection(chimObj.getChimeraModel());
516 // } else if (chimObj.getChimeraModel()
517 // .getChain(((ChimeraResidue) chimObj).getChainId()).isSelected()) {
518 // removeChimSelection(chimObj.getChimeraModel().getChain(
519 // ((ChimeraResidue) chimObj).getChainId()));
523 // removeChimSelection(chimObj);
524 // if (chimObj.hasSelectedChildren() && chimObj instanceof ChimeraModel) {
525 // for (ChimeraResidue residue : ((ChimeraModel) chimObj)
526 // .getSelectedResidues()) {
527 // removeChimSelection(residue);
533 // System.out.println("selection list: " + getChimSelectionCount());
534 updateChimeraSelection();
538 // Save models in a HashMap/Set for better performance?
539 public void updateChimeraSelection()
541 // System.out.println("update Chimera selection");
543 for (int i = 0; i < chimSelectionList.size(); i++)
545 ChimeraStructuralObject nodeInfo = chimSelectionList.get(i);
546 // we do not care about the model anymore
547 selSpec = selSpec.concat(nodeInfo.toSpec());
548 if (i < chimSelectionList.size() - 1)
553 if (selSpec.length() > 0)
555 chimeraManager.select("sel " + selSpec);
559 chimeraManager.select("~sel");
564 * This is called by the selectionListener to let us know that the user has
565 * changed their selection in Chimera. We need to go back to Chimera to find
566 * out what is currently selected and update our list.
568 public void chimeraSelectionChanged()
570 // System.out.println("Chimera selection changed");
571 clearSelectionList();
572 // Execute the command to get the list of models with selections
573 Map<Integer, ChimeraModel> selectedModelsMap = chimeraManager
574 .getSelectedModels();
575 // Now get the residue-level data
576 chimeraManager.getSelectedResidues(selectedModelsMap);
577 // Get the selected objects
580 for (ChimeraModel selectedModel : selectedModelsMap.values())
582 int modelNumber = selectedModel.getModelNumber();
583 int subModelNumber = selectedModel.getSubModelNumber();
584 // Get the corresponding "real" model
585 if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber))
587 ChimeraModel dataModel = chimeraManager
588 .getChimeraModel(modelNumber, subModelNumber);
589 if (dataModel.getResidueCount() == selectedModel.getResidueCount()
591 .getModelType() == StructureManager.ModelType.SMILES)
593 // Select the entire model
594 addChimSelection(dataModel);
595 // dataModel.setSelected(true);
599 for (ChimeraChain selectedChain : selectedModel.getChains())
601 ChimeraChain dataChain = dataModel
602 .getChain(selectedChain.getChainId());
603 if (selectedChain.getResidueCount() == dataChain
606 addChimSelection(dataChain);
607 // dataChain.setSelected(true);
610 // Need to select individual residues
611 for (ChimeraResidue res : selectedChain.getResidues())
613 String residueIndex = res.getIndex();
614 ChimeraResidue residue = dataChain.getResidue(residueIndex);
619 addChimSelection(residue);
620 // residue.setSelected(true);
623 } // chainIter.hasNext()
626 } // modelIter.hasNext()
627 } catch (Exception ex)
629 logger.warn("Could not update selection", ex);
631 // System.out.println("selection list: " + getChimSelectionCount());
632 // Finally, update the navigator panel
634 updateCytoscapeSelection();
637 public void selectFunctResidues(Collection<ChimeraModel> models)
639 clearSelectionList();
640 for (ChimeraModel model : models)
642 for (ChimeraResidue residue : model.getFuncResidues())
644 addChimSelection(residue);
647 updateChimeraSelection();
648 updateCytoscapeSelection();
652 // public void selectFunctResidues(CyNode node, CyNetwork network) {
653 // clearSelectionList();
654 // if (currentCyMap.containsKey(node)) {
655 // Set<ChimeraStructuralObject> chimObjects = currentCyMap.get(node);
656 // for (ChimeraStructuralObject obj : chimObjects) {
657 // if (obj instanceof ChimeraModel) {
658 // ChimeraModel model = (ChimeraModel) obj;
659 // for (ChimeraResidue residue : model.getFuncResidues()) {
660 // addChimSelection(residue);
665 // updateChimeraSelection();
666 // updateCytoscapeSelection();
667 // selectionChanged();
670 public List<ChimeraStructuralObject> getChimSelectionList()
672 return chimSelectionList;
675 public int getChimSelectionCount()
677 return chimSelectionList.size();
681 * Add a selection to the selection list. This is called primarily by the
682 * Model Navigator Dialog to keep the selections in sync
684 * @param selectionToAdd
685 * the selection to add to our list
687 public void addChimSelection(ChimeraStructuralObject selectionToAdd)
689 if (selectionToAdd != null
690 && !chimSelectionList.contains(selectionToAdd))
692 chimSelectionList.add(selectionToAdd);
693 selectionToAdd.setSelected(true);
698 * Remove a selection from the selection list. This is called primarily by the
699 * Model Navigator Dialog to keep the selections in sync
701 * @param selectionToRemove
702 * the selection to remove from our list
704 public void removeChimSelection(ChimeraStructuralObject selectionToRemove)
706 if (selectionToRemove != null
707 && chimSelectionList.contains(selectionToRemove))
709 chimSelectionList.remove(selectionToRemove);
710 selectionToRemove.setSelected(false);
715 * Clear the list of selected objects
717 public void clearSelectionList()
719 for (ChimeraStructuralObject cso : chimSelectionList)
723 cso.setSelected(false);
726 chimSelectionList.clear();
730 * Associate a new network with the corresponding Chimera objects.
736 * Dump and refresh all of our model/chain/residue info
738 public void updateModels()
740 // Stop all of our listeners while we try to handle this
741 chimeraManager.stopListening();
743 // Get all of the open models
744 List<ChimeraModel> newModelList = chimeraManager.getModelList();
746 // Match them up -- assume that the model #'s haven't changed
747 for (ChimeraModel newModel : newModelList)
749 // Get the color (for our navigator)
750 newModel.setModelColor(chimeraManager.getModelColor(newModel));
752 // Get our model info
753 int modelNumber = newModel.getModelNumber();
754 int subModelNumber = newModel.getSubModelNumber();
756 // If we already know about this model number, get the Structure,
757 // which tells us about the associated CyNode
758 if (chimeraManager.hasChimeraModel(modelNumber, subModelNumber))
760 ChimeraModel oldModel = chimeraManager.getChimeraModel(modelNumber,
762 chimeraManager.removeChimeraModel(modelNumber, subModelNumber);
763 newModel.setModelType(oldModel.getModelType());
764 if (oldModel.getModelType() == ModelType.SMILES)
766 newModel.setModelName(oldModel.getModelName());
768 // re-assign associations to cytoscape objects
769 // Map<CyIdentifiable, CyNetwork> oldModelCyObjs =
770 // oldModel.getCyObjects();
771 // for (CyIdentifiable cyObj : oldModelCyObjs.keySet()) {
772 // // add cy objects to the new model
773 // newModel.addCyObject(cyObj, oldModelCyObjs.get(cyObj));
774 // if (currentCyMap.containsKey(cyObj)) {
775 // currentCyMap.get(cyObj).add(newModel);
776 // if (currentCyMap.get(cyObj).contains(oldModel)) {
777 // currentCyMap.get(cyObj).remove(oldModel);
781 // // add new model to the chimera objects map and remove old model
782 // if (currentChimMap.containsKey(oldModel)) {
783 // currentChimMap.put(newModel, currentChimMap.get(oldModel));
784 // currentChimMap.remove(oldModel);
787 // add new model to ChimeraManager
788 chimeraManager.addChimeraModel(modelNumber, subModelNumber, newModel);
790 // Get the residue information
791 if (newModel.getModelType() != ModelType.SMILES)
793 chimeraManager.addResidues(newModel);
795 // for (CyIdentifiable cyObj : newModel.getCyObjects().keySet()) {
796 // if (cyObj != null && cyObj instanceof CyNetwork) {
797 // addStructureNetwork((CyNetwork) cyObj);
798 // } else if (cyObj != null && cyObj instanceof CyNode) {
799 // newModel.setFuncResidues(ChimUtils.parseFuncRes(
800 // getResidueList(newModel.getCyObjects().get(cyObj), cyObj),
801 // newModel.getModelName()));
806 // associate all models with any node or network
807 // aTask.associate();
809 // Restart all of our listeners
810 chimeraManager.startListening();
814 public void launchModelNavigatorDialog()
816 // TODO: [Optional] Use haveGUI flag
820 // if (mnDialog == null) {
821 // CySwingApplication cyApplication = (CySwingApplication)
822 // getService(CySwingApplication.class);
823 // mnDialog = new ModelNavigatorDialog(cyApplication.getJFrame(), this);
826 // mnDialog.setVisible(true);
829 public boolean isMNDialogOpen()
831 // if (mnDialog != null && mnDialog.isVisible()) {
838 * Invoked by the listener thread.
840 public void modelChanged()
842 // if (mnDialog != null) {
843 // mnDialog.modelChanged();
848 * Inform our interface that the selection has changed
850 public void selectionChanged()
852 // if (mnDialog != null) {
853 // // System.out.println("update dialog selection");
854 // mnDialog.updateSelection(new
855 // ArrayList<ChimeraStructuralObject>(chimSelectionList));
859 public void launchAlignDialog(boolean useChains)
861 // TODO: [Optional] Use haveGUI flag
862 // Sometimes it does not appear in Windows
866 // if (alDialog != null) {
867 // alDialog.setVisible(false);
868 // alDialog.dispose();
870 // System.out.println("launch align dialog");
871 List<ChimeraStructuralObject> chimObjectList = new ArrayList<>();
872 for (ChimeraModel model : chimeraManager.getChimeraModels())
876 for (ChimeraChain chain : model.getChains())
878 chimObjectList.add(chain);
883 chimObjectList.add(model);
886 // Bring up the dialog
887 // CySwingApplication cyApplication = (CySwingApplication)
888 // getService(CySwingApplication.class);
889 // alDialog = new AlignStructuresDialog(cyApplication.getJFrame(), this,
892 // alDialog.setVisible(true);
895 public List<String> getAllStructureKeys()
897 return Arrays.asList(defaultStructureKeys);
900 public List<String> getAllChemStructKeys()
902 return Arrays.asList(defaultChemStructKeys);
905 public List<String> getAllResidueKeys()
907 return Arrays.asList(defaultResidueKeys);
910 public List<String> getAllChimeraResidueAttributes()
912 List<String> attributes = new ArrayList<>();
913 // attributes.addAll(rinManager.getResAttrs());
914 attributes.addAll(chimeraManager.getAttrList());
918 StructureSettings defaultSettings = null;
920 // TODO: [Optional] Change priority of Chimera paths
921 public static List<String> getChimeraPaths(boolean isChimeraX)
923 List<String> pathList = new ArrayList<>();
925 // if no network is available and the settings have been modified by the
929 // For Jalview, Preferences/Cache plays this role instead
930 // if (defaultSettings != null)
932 // String defaultPath = defaultSettings.getChimeraPath();
933 // if (defaultPath != null && !defaultPath.equals(""))
935 // pathList.add(defaultPath);
940 String os = System.getProperty("os.name");
941 String userPath = Cache
942 .getDefault(isChimeraX ? Preferences.CHIMERAX_PATH
943 : Preferences.CHIMERA_PATH, null);
946 * paths are based on getChimeraPaths() in
948 * https://github.com/RBVI/structureViz2/blob/master/src/main/java/edu/ucsf/rbvi/structureViz2/internal/model/StructureManager.java
950 * https://github.com/RBVI/structureVizX/blob/master/src/main/java/edu/ucsf/rbvi/structureVizX/internal/model/StructureManager.java
952 String chimera = isChimeraX ? "ChimeraX" : "Chimera";
953 String chimeraExe = isChimeraX ? "ChimeraX" : "chimera";
956 * Jalview addition: check if path set in user preferences
958 if (userPath != null)
960 // in macos, deal with the user selecting the .app folder
961 boolean adjusted = false;
962 if (os.startsWith("Mac") && userPath.endsWith((".app")))
964 String possiblePath = String.format("%s/Contents/MacOS/%s",
965 userPath, chimeraExe);
966 if (new File(possiblePath).exists())
968 pathList.add(possiblePath);
974 pathList.add(userPath);
978 // Add default installation paths
979 if (os.startsWith("Linux"))
981 // ChimeraX .deb and .rpm packages put symbolic link from
983 pathList.add(String.format("/usr/bin/%s",
984 chimeraExe.toLowerCase(Locale.ROOT)));
985 pathList.add(String.format("/usr/bin/%s", chimeraExe));
987 pathList.add(String.format("/usr/local/bin/%s",
988 chimeraExe.toLowerCase(Locale.ROOT)));
989 pathList.add(String.format("/usr/local/bin/%s", chimeraExe));
991 // these paths also used by .deb and .rpm
992 pathList.add(String.format("/usr/lib/ucsf-%s/bin/%s",
993 chimera.toLowerCase(Locale.ROOT), chimeraExe));
994 pathList.add(String.format("/usr/libexec/UCSF-%s/bin/%s", chimera,
997 pathList.add(String.format("/usr/local/chimera/bin/%s", chimeraExe));
1001 String.format("%s/bin/%s", System.getProperty("user.home"),
1002 chimeraExe.toLowerCase(Locale.ROOT)));
1003 pathList.add(String.format("%s/bin/%s",
1004 System.getProperty("user.home"), chimeraExe));
1005 pathList.add(String.format("%s/opt/bin/%s",
1006 System.getProperty("user.home"),
1007 chimeraExe.toLowerCase(Locale.ROOT)));
1008 pathList.add(String.format("%s/opt/bin/%s",
1009 System.getProperty("user.home"), chimeraExe));
1010 pathList.add(String.format("%s/local/bin/%s",
1011 System.getProperty("user.home"),
1012 chimeraExe.toLowerCase(Locale.ROOT)));
1013 pathList.add(String.format("%s/local/bin/%s",
1014 System.getProperty("user.home"), chimeraExe));
1016 else if (os.startsWith("Windows"))
1018 for (String root : new String[] { "\\Program Files",
1019 "C:\\Program Files", "\\Program Files (x86)",
1020 "C:\\Program Files (x86)", String.format("%s\\AppData\\Local",
1021 System.getProperty("user.home")) })
1023 String[] candidates = isChimeraX ? CHIMERAX_VERSIONS
1025 for (String version : candidates)
1027 // TODO original code doesn't include version in path; which is right?
1028 String path = String.format("%s\\%s %s\\bin\\%s", root, chimera,
1029 version, chimeraExe);
1031 pathList.add(path + ".exe");
1033 // try without a version number too
1034 String path = String.format("%s\\%s\\bin\\%s", root, chimera,
1037 pathList.add(path + ".exe");
1040 else if (os.startsWith("Mac"))
1042 // check for installations with version numbers first
1043 String[] candidates = isChimeraX ? CHIMERAX_VERSIONS
1045 for (String version : candidates)
1048 String.format("/Applications/%s-%s.app/Contents/MacOS/%s",
1049 chimera, version, chimeraExe));
1051 String.format("%s/Applications/%s-%s.app/Contents/MacOS/%s",
1052 System.getProperty("user.home"), chimera, version,
1055 pathList.add(String.format("/Applications/%s.app/Contents/MacOS/%s",
1056 chimera, chimeraExe));
1057 pathList.add(String.format("%s/Applications/%s.app/Contents/MacOS/%s",
1058 System.getProperty("user.home"), chimera, chimeraExe));
1063 public void setChimeraPathProperty(String path)
1065 // CytoUtils.setDefaultChimeraPath(registrar, chimeraPropertyName,
1066 // chimeraPathPropertyKey,
1070 public void setStructureSettings(StructureSettings structureSettings)
1072 this.defaultSettings = structureSettings;
1075 public String getCurrentChimeraPath(Object object)
1077 if (defaultSettings != null)
1079 return defaultSettings.getChimeraPath();
1087 // public void initChimTable() {
1088 // CyTableManager manager = (CyTableManager) getService(CyTableManager.class);
1089 // CyTableFactory factory = (CyTableFactory) getService(CyTableFactory.class);
1090 // for (CyTable table : manager.getGlobalTables()) {
1091 // if (table.getTitle().equals(chimeraOutputTable)) {
1092 // manager.deleteTable(table.getSUID());
1095 // chimTable = factory.createTable(chimeraOutputTable, chimeraCommandAttr,
1098 // manager.addTable(chimTable);
1099 // if (chimTable.getColumn(chimeraOutputAttr) == null) {
1100 // chimTable.createListColumn(chimeraOutputAttr, String.class, false);
1104 // public void addChimReply(String command, List<String> reply) {
1105 // chimTable.getRow(command).set(chimeraOutputAttr, reply);