Merge branch 'features/JAL-1541_BioJsMSAViewer-export-option' into develop
[jalview.git] / src / jalview / ext / jmol / PDBFileWithJmol.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.ext.jmol;
22
23 import jalview.datamodel.AlignmentAnnotation;
24 import jalview.datamodel.Annotation;
25 import jalview.datamodel.PDBEntry;
26 import jalview.datamodel.Sequence;
27 import jalview.datamodel.SequenceI;
28 import jalview.io.AlignFile;
29 import jalview.io.FileParse;
30 import jalview.util.MessageManager;
31
32 import java.io.IOException;
33 import java.util.Hashtable;
34 import java.util.Map;
35
36 import org.jmol.api.JmolStatusListener;
37 import org.jmol.api.JmolViewer;
38 import org.jmol.constant.EnumCallback;
39 import org.jmol.modelset.Group;
40 import org.jmol.modelset.Model;
41 import org.jmol.modelset.ModelSet;
42 import org.jmol.modelset.Polymer;
43 import org.jmol.modelsetbio.BioPolymer;
44 import org.jmol.viewer.Viewer;
45 import org.openscience.jmol.app.JmolApp;
46
47 /**
48  * Import and process PDB files with Jmol
49  * 
50  * @author jprocter
51  * 
52  */
53 public class PDBFileWithJmol extends AlignFile implements
54         JmolStatusListener
55 {
56
57   JmolApp jmolApp = null;
58
59   Viewer viewer = null;
60
61   public PDBFileWithJmol(String inFile, String type) throws IOException
62   {
63     super(inFile, type);
64   }
65
66   public PDBFileWithJmol(FileParse fp) throws IOException
67   {
68     super(fp);
69   }
70
71   public PDBFileWithJmol()
72   {
73     // TODO Auto-generated constructor stub
74   }
75
76   /**
77    * create a headless jmol instance for dataprocessing
78    * 
79    * @return
80    */
81   private Viewer getJmolData()
82   {
83     if (viewer == null)
84     { // note that -o -n -x are all implied
85       jmolApp = new JmolApp();
86       jmolApp.isDataOnly = true;
87       jmolApp.haveConsole = false;
88       jmolApp.haveDisplay = false;
89       jmolApp.exitUponCompletion = true;
90       try
91       {
92         viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
93                 null, jmolApp.commandOptions, this);
94         viewer.setScreenDimension(jmolApp.startupWidth,
95                 jmolApp.startupHeight);
96         jmolApp.startViewer(viewer, null);
97       } catch (ClassCastException x)
98       {
99         throw new Error(MessageManager.formatMessage("error.jmol_version_not_compatible_with_jalview_version", new String[]{JmolViewer.getJmolVersion()}),
100                 x);
101       }
102     }
103     return viewer;
104   }
105
106   private void waitForScript(Viewer jmd)
107   {
108     while (jmd.isScriptExecuting())
109     {
110       try
111       {
112         Thread.sleep(50);
113
114       } catch (InterruptedException x)
115       {
116       }
117     }
118   }
119
120   /*
121    * (non-Javadoc)
122    * 
123    * @see jalview.io.AlignFile#parse()
124    */
125   @Override
126   public void parse() throws IOException
127   {
128     Viewer jmd = getJmolData();
129     jmd.openReader(getDataName(), getDataName(), getReader());
130     waitForScript(jmd);
131     if (jmd.getModelCount() > 0)
132     {
133       ModelSet ms = jmd.getModelSet();
134       String structs = ms.calculateStructures(null, true, false, true);
135       // System.out.println("Structs\n"+structs);
136       for (Model model : ms.getModels())
137       {
138         for (int _bp = 0, _bpc = model.getBioPolymerCount(); _bp < _bpc; _bp++)
139         {
140           Polymer bp = model.getBioPolymer(_bp);
141           if (bp instanceof BioPolymer)
142           {
143             BioPolymer biopoly = (BioPolymer) bp;
144             char _lastChainId = 0;
145             int[] groups = biopoly.getLeadAtomIndices();
146             Group[] bpgrp = biopoly.getGroups();
147             char seq[] = new char[groups.length], secstr[] = new char[groups.length], secstrcode[] = new char[groups.length];
148             int groupc = 0, len = 0, firstrnum = 1, lastrnum = 0;
149             do
150             {
151               if (groupc >= groups.length
152                       || ms.atoms[groups[groupc]].getChainID() != _lastChainId)
153               {
154                 if (len > 0)
155                 {
156                   char newseq[] = new char[len];
157                   System.arraycopy(seq, 0, newseq, 0, len);
158                   Annotation asecstr[] = new Annotation[len+firstrnum-1];
159                   for (int p = 0; p < len; p++)
160                   {
161                     if (secstr[p] >= 'A' && secstr[p] <= 'z')
162                     {
163                       asecstr[p] = new Annotation("" + secstr[p], null,
164                               secstrcode[p], Float.NaN);
165                     }
166                   }
167                   SequenceI sq = new Sequence("" + getDataName() + "|"
168                           + model.getModelTitle() + "|" + _lastChainId,
169                           newseq, firstrnum, lastrnum);
170                   PDBEntry pdbe = new PDBEntry();
171                   pdbe.setFile(getDataName());
172                   pdbe.setId(getDataName());
173                   sq.addPDBId(pdbe);
174                   pdbe.setProperty(new Hashtable());
175                   pdbe.getProperty().put("CHAIN", "" + _lastChainId);
176                   // JAL-1533
177                   // Need to put the number of models for this polymer somewhere for Chimera/others to grab
178                   //                  pdbe.getProperty().put("PDBMODELS", biopoly.)
179                   seqs.add(sq);
180                   if (!(biopoly.isDna() || biopoly.isRna()))
181                   {
182                     AlignmentAnnotation ann = new AlignmentAnnotation(
183                             "Secondary Structure",
184                             "Secondary Structure from PDB File", asecstr);
185                     ann.belowAlignment=true;
186                     ann.visible=true;
187                     ann.autoCalculated=false;
188                     ann.setCalcId(getClass().getName());
189                     sq.addAlignmentAnnotation(ann);
190                     ann.adjustForAlignment();
191                     ann.validateRangeAndDisplay();
192                     annotations.add(ann);
193                   }
194                 }
195                 len = 0;
196                 firstrnum = 1;
197                 lastrnum = 0;
198               }
199               if (groupc < groups.length)
200               {
201                 if (len == 0)
202                 {
203                   firstrnum = bpgrp[groupc].getResno();
204                   _lastChainId = bpgrp[groupc].getChainID();
205                 }
206                 else
207                 {
208                   lastrnum = bpgrp[groupc].getResno();
209                 }
210                 seq[len] = bpgrp[groupc].getGroup1();
211                 switch (bpgrp[groupc].getProteinStructureSubType())
212                 {
213                 case HELIX_310:
214                   if (secstr[len] == 0)
215                   {
216                     secstr[len] = '3';
217                   }
218                 case HELIX_ALPHA:
219                   if (secstr[len] == 0)
220                   {
221                     secstr[len] = 'H';
222                   }
223                 case HELIX_PI:
224                   if (secstr[len] == 0)
225                   {
226                     secstr[len] = 'P';
227                   }
228                 case HELIX:
229                   if (secstr[len] == 0)
230                   {
231                     secstr[len] = 'H';
232                   }
233                   secstrcode[len] = 'H';
234                   break;
235                 case SHEET:
236                   secstr[len] = 'E';
237                   secstrcode[len] = 'E';
238                   break;
239                 default:
240                   secstr[len] = 0;
241                   secstrcode[len] = 0;
242                 }
243                 len++;
244               }
245             } while (groupc++ < groups.length);
246
247           }
248         }
249       }
250
251       /*
252        * lastScriptTermination = -9465; String dsspOut =
253        * jmd.evalString("calculate STRUCTURE"); if (dsspOut.equals("pending")) {
254        * while (lastScriptTermination == -9465) { try { Thread.sleep(50); }
255        * catch (Exception x) { } ; } } System.out.println(lastConsoleEcho);
256        */
257     }
258   }
259
260   /*
261    * (non-Javadoc)
262    * 
263    * @see jalview.io.AlignFile#print()
264    */
265   @Override
266   public String print()
267   {
268     // TODO Auto-generated method stub
269     return null;
270   }
271
272   @Override
273   public void setCallbackFunction(String callbackType,
274           String callbackFunction)
275   {
276     // TODO Auto-generated method stub
277
278   }
279
280   /*
281    * @Override public void notifyCallback(EnumCallback type, Object[] data) {
282    * try { switch (type) { case ERROR: case SCRIPT:
283    * notifyScriptTermination((String) data[2], ((Integer) data[3]).intValue());
284    * break; case MESSAGE: sendConsoleMessage((data == null) ? ((String) null) :
285    * (String) data[1]); break; case LOADSTRUCT: notifyFileLoaded((String)
286    * data[1], (String) data[2], (String) data[3], (String) data[4], ((Integer)
287    * data[5]).intValue());
288    * 
289    * break; default: // System.err.println("Unhandled callback " + type + " " //
290    * + data[1].toString()); break; } } catch (Exception e) {
291    * System.err.println("Squashed Jmol callback handler error:");
292    * e.printStackTrace(); } }
293    */
294   public void notifyCallback(EnumCallback type, Object[] data)
295   {
296     String strInfo = (data == null || data[1] == null ? null : data[1]
297             .toString());
298     switch (type)
299     {
300     case ECHO:
301       sendConsoleEcho(strInfo);
302       break;
303     case SCRIPT:
304       notifyScriptTermination((String) data[2],
305               ((Integer) data[3]).intValue());
306       break;
307     case MEASURE:
308       String mystatus = (String) data[3];
309       if (mystatus.indexOf("Picked") >= 0
310               || mystatus.indexOf("Sequence") >= 0)
311       {
312         // Picking mode
313         sendConsoleMessage(strInfo);
314       }
315       else if (mystatus.indexOf("Completed") >= 0)
316       {
317         sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
318                 strInfo.length() - 1));
319       }
320       break;
321     case MESSAGE:
322       sendConsoleMessage(data == null ? null : strInfo);
323       break;
324     case PICK:
325       sendConsoleMessage(strInfo);
326       break;
327     default:
328       break;
329     }
330   }
331
332   private void notifyFileLoaded(String string, String string2,
333           String string3, String string4, int intValue)
334   {
335     // TODO Auto-generated method stub
336
337   }
338
339   String lastConsoleEcho = "";
340
341   private void sendConsoleEcho(String string)
342   {
343     lastConsoleEcho += string;
344     lastConsoleEcho += "\n";
345   }
346
347   String lastConsoleMessage = "";
348
349   private void sendConsoleMessage(String string)
350   {
351     lastConsoleMessage += string;
352     lastConsoleMessage += "\n";
353   }
354
355   int lastScriptTermination = -1;
356
357   String lastScriptMessage = "";
358
359   private void notifyScriptTermination(String string, int intValue)
360   {
361     lastScriptMessage += string;
362     lastScriptMessage += "\n";
363     lastScriptTermination = intValue;
364   }
365
366   @Override
367   public boolean notifyEnabled(EnumCallback callbackPick)
368   {
369     switch (callbackPick)
370     {
371     case MESSAGE:
372     case SCRIPT:
373     case ECHO:
374     case LOADSTRUCT:
375     case ERROR:
376       return true;
377     case MEASURE:
378     case PICK:
379     case HOVER:
380     case RESIZE:
381     case SYNC:
382     case CLICK:
383     case ANIMFRAME:
384     case MINIMIZATION:
385     }
386     return false;
387   }
388
389   @Override
390   public String eval(String strEval)
391   {
392     // TODO Auto-generated method stub
393     return null;
394   }
395
396   @Override
397   public float[][] functionXY(String functionName, int x, int y)
398   {
399     // TODO Auto-generated method stub
400     return null;
401   }
402
403   @Override
404   public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
405   {
406     // TODO Auto-generated method stub
407     return null;
408   }
409
410   @Override
411   public String createImage(String fileName, String type,
412           Object text_or_bytes, int quality)
413   {
414     // TODO Auto-generated method stub
415     return null;
416   }
417
418   @Override
419   public Map<String, Object> getRegistryInfo()
420   {
421     // TODO Auto-generated method stub
422     return null;
423   }
424
425   @Override
426   public void showUrl(String url)
427   {
428     // TODO Auto-generated method stub
429
430   }
431
432   @Override
433   public void resizeInnerPanel(String data)
434   {
435     // TODO Auto-generated method stub
436
437   }
438
439 }