JAL-3551 pull up Close Viewer dialog to base class
[jalview.git] / src / jalview / gui / PymolBindingModel.java
1 package jalview.gui;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import jalview.api.AlignmentViewPanel;
9 import jalview.datamodel.PDBEntry;
10 import jalview.datamodel.SequenceI;
11 import jalview.ext.pymol.PymolCommands;
12 import jalview.ext.pymol.PymolManager;
13 import jalview.gui.StructureViewer.ViewerType;
14 import jalview.structure.AtomSpec;
15 import jalview.structure.StructureCommand;
16 import jalview.structure.StructureCommandI;
17 import jalview.structure.StructureSelectionManager;
18 import jalview.structures.models.AAStructureBindingModel;
19
20 public class PymolBindingModel extends AAStructureBindingModel
21 {
22   /*
23    * format for labels shown on structures when mousing over sequence;
24    * see https://pymolwiki.org/index.php/Label#examples
25    * left not final so customisable e.g. with a Groovy script
26    */
27   private static String LABEL_FORMAT = "\"%s %s\" % (resn,resi)";
28
29   private PymolManager pymolManager;
30
31   private Thread pymolMonitor;
32
33   /*
34    * full paths to structure files opened in PyMOL
35    */
36   List<String> structureFiles = new ArrayList<>();
37
38   /*
39    * lookup from file path to PyMOL object name
40    */
41   Map<String, String> pymolObjects = new HashMap<>();
42
43   private String lastLabelSpec;
44
45   /**
46    * Constructor
47    * 
48    * @param viewer
49    * @param ssm
50    * @param pdbentry
51    * @param sequenceIs
52    */
53   public PymolBindingModel(StructureViewerBase viewer,
54           StructureSelectionManager ssm, PDBEntry[] pdbentry,
55           SequenceI[][] sequenceIs)
56   {
57     super(ssm, pdbentry, sequenceIs, null);
58     pymolManager = new PymolManager();
59     setStructureCommands(new PymolCommands());
60     setViewer(viewer);
61   }
62
63   @Override
64   public String[] getStructureFiles()
65   {
66     return structureFiles.toArray(new String[structureFiles.size()]);
67   }
68
69   @Override
70   public void highlightAtoms(List<AtomSpec> atoms)
71   {
72     /*
73      * https://pymolwiki.org/index.php/Label#examples
74      */
75     StringBuilder sb = new StringBuilder();
76     for (AtomSpec atom : atoms)
77     {
78       // todo promote to StructureCommandsI.showLabel()
79       // todo handle CA|P correctly
80       String modelId = getModelIdForFile(atom.getPdbFile());
81       sb.append(String.format(" %s//%s/%d/CA", modelId,
82               atom.getChain(),
83               atom.getPdbResNum()));
84     }
85     String labelSpec = sb.toString();
86     if (labelSpec.equals(lastLabelSpec))
87     {
88       return;
89     }
90     StructureCommandI command = new StructureCommand("label", labelSpec, LABEL_FORMAT);
91     executeCommand(command, false);
92
93     /*
94      * and remove the label(s) previously shown
95      */
96     if (lastLabelSpec != null)
97     {
98       command = new StructureCommand("label", lastLabelSpec, "");
99       executeCommand(command, false);
100     }
101
102     lastLabelSpec = labelSpec;
103   }
104
105   @Override
106   public SequenceRenderer getSequenceRenderer(AlignmentViewPanel alignment)
107   {
108     // pull up?
109     return new SequenceRenderer(alignment.getAlignViewport());
110   }
111
112   @Override
113   protected List<String> executeCommand(StructureCommandI command,
114           boolean getReply)
115   {
116     // System.out.println(command.toString()); // debug
117     return pymolManager.sendCommand(command, getReply);
118   }
119
120   @Override
121   protected String getModelIdForFile(String file)
122   {
123     return pymolObjects.containsKey(file) ? pymolObjects.get(file) : "";
124   }
125
126   @Override
127   protected ViewerType getViewerType()
128   {
129     return ViewerType.PYMOL;
130   }
131
132   @Override
133   public boolean isViewerRunning()
134   {
135     return pymolManager.isPymolLaunched();
136   }
137
138   @Override
139   public void closeViewer(boolean closePymol)
140   {
141     super.closeViewer(closePymol);
142     if (closePymol)
143     {
144       pymolManager.exitPymol();
145     }
146     pymolManager = null;
147
148     if (pymolMonitor != null)
149     {
150       pymolMonitor.interrupt();
151     }
152   }
153
154   public boolean openSession(String pymolSessionFile)
155   {
156     StructureCommandI cmd = getCommandGenerator()
157             .loadFile(pymolSessionFile);
158     executeCommand(cmd, false);
159     return true;
160   }
161
162   public boolean launchPymol()
163   {
164     if (pymolManager.isPymolLaunched())
165     {
166       return true;
167     }
168
169     boolean launched = pymolManager.launchPymol();
170     if (launched)
171     {
172       // start listening for PyMOL selections - how??
173     }
174     else
175     {
176       System.err.println("Failed to launch PyMOL!");
177     }
178     return launched;
179   }
180
181   public void openFile(PDBEntry pe)
182   {
183     // todo : check not already open, remap / rename, etc
184     String file = pe.getFile();
185     StructureCommandI cmd = getCommandGenerator().loadFile(file);
186
187     /*
188      * a second parameter sets the pdbid as the loaded PyMOL object name
189      */
190     String pdbId = pe.getId();
191     cmd.addParameter(pdbId);
192
193     executeCommand(cmd, false);
194
195     pymolObjects.put(file, pdbId);
196     if (!structureFiles.contains(file))
197     {
198       structureFiles.add(file);
199     }
200     if (getSsm() != null)
201     {
202       getSsm().addStructureViewerListener(this);
203     }
204
205   }
206
207   @Override
208   protected String getModelId(int pdbfnum, String file)
209   {
210     return file;
211   }
212
213   /**
214    * Returns the file extension to use for a saved viewer session file (.pse)
215    * 
216    * @return
217    * @see https://pymolwiki.org/index.php/Save
218    */
219   @Override
220   public String getSessionFileExtension()
221   {
222     return ".pse";
223   }
224
225 }