77755f8d06fe1b42ae03bb09267da5d30e1336be
[jalview.git] / src / jalview / ext / jmol / PDBFileWithJmol.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.ext.jmol;
19
20 import java.io.IOException;
21 import java.util.Map;
22
23 import org.jmol.api.JmolStatusListener;
24 import org.jmol.api.JmolViewer;
25 import org.jmol.constant.EnumCallback;
26 import org.jmol.modelset.Group;
27 import org.jmol.modelset.Model;
28 import org.jmol.modelset.ModelSet;
29 import org.jmol.modelset.Polymer;
30 import org.jmol.modelsetbio.BioPolymer;
31 import org.jmol.viewer.Viewer;
32 import org.openscience.jmol.app.JmolApp;
33
34 import jalview.datamodel.AlignmentAnnotation;
35 import jalview.datamodel.Annotation;
36 import jalview.datamodel.PDBEntry;
37 import jalview.datamodel.Sequence;
38 import jalview.datamodel.SequenceI;
39 import jalview.io.AlignFile;
40 import jalview.io.FileParse;
41
42 /**
43  * Import and process PDB files with Jmol
44  * 
45  * @author jprocter
46  * 
47  */
48 public class PDBFileWithJmol extends AlignFile implements
49         JmolStatusListener
50 {
51
52   JmolApp jmolApp = null;
53
54   Viewer viewer = null;
55
56   public PDBFileWithJmol(String inFile, String type)
57           throws IOException
58   {
59     super(inFile, type);
60   }
61   
62
63   public PDBFileWithJmol(FileParse fp) throws IOException
64   {
65     super(fp);
66   }
67
68   public PDBFileWithJmol()
69   {
70     // TODO Auto-generated constructor stub
71   }
72
73   /**
74    * create a headless jmol instance for dataprocessing
75    * 
76    * @return
77    */
78   private Viewer getJmolData()
79   {
80     if (viewer == null)
81     { // note that -o -n -x are all implied
82       jmolApp = new JmolApp();
83       jmolApp.isDataOnly = true;
84       jmolApp.haveConsole = false;
85       jmolApp.haveDisplay = false;
86       jmolApp.exitUponCompletion = true;
87       try
88       {
89         viewer = (Viewer) JmolViewer.allocateViewer(null, null, null, null,
90                 null, jmolApp.commandOptions, this);
91         viewer.setScreenDimension(jmolApp.startupWidth,
92                 jmolApp.startupHeight);
93         jmolApp.startViewer(viewer, null);
94       } catch (ClassCastException x)
95       {
96         throw new Error(
97                 "Jmol version "
98                         + JmolViewer.getJmolVersion()
99                         + " is not compatible with this version of Jalview. Report this problem at issues.jalview.org",
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];
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                   seqs.add(sq);
175                   if (!(biopoly.isDna() || biopoly.isRna()))
176                   {
177                     AlignmentAnnotation ann = new AlignmentAnnotation(
178                             "Secondary Structure",
179                             "Secondary Structure from PDB File", asecstr);
180                     sq.addAlignmentAnnotation(ann);
181                     annotations.add(ann);
182                   }
183                 }
184                 len = 0;
185                 firstrnum = 1;
186                 lastrnum = 0;
187               }
188               if (groupc < groups.length)
189               {
190                 if (len == 0)
191                 {
192                   firstrnum = bpgrp[groupc].getResno();
193                   _lastChainId = bpgrp[groupc].getChainID();
194                 }
195                 else
196                 {
197                   lastrnum = bpgrp[groupc].getResno();
198                 }
199                 seq[len] = bpgrp[groupc].getGroup1();
200                 switch (bpgrp[groupc].getProteinStructureSubType())
201                 {
202                 case HELIX_310:
203                   if (secstr[len] == 0)
204                   {
205                     secstr[len] = '3';
206                   }
207                 case HELIX_ALPHA:
208                   if (secstr[len] == 0)
209                   {
210                     secstr[len] = 'H';
211                   }
212                 case HELIX_PI:
213                   if (secstr[len] == 0)
214                   {
215                     secstr[len] = 'P';
216                   }
217                 case HELIX:
218                   if (secstr[len] == 0)
219                   {
220                     secstr[len] = 'H';
221                   }
222                   secstrcode[len] = 'H';
223                   break;
224                 case SHEET:
225                   secstr[len] = 'E';
226                   secstrcode[len] = 'E';
227                   break;
228                 default:
229                   secstr[len] = 0;
230                   secstrcode[len] = 0;
231                 }
232                 len++;
233               }
234             } while (groupc++ < groups.length);
235
236           }
237         }
238       }
239
240       /*
241        * lastScriptTermination = -9465; String dsspOut =
242        * jmd.evalString("calculate STRUCTURE"); if (dsspOut.equals("pending")) {
243        * while (lastScriptTermination == -9465) { try { Thread.sleep(50); }
244        * catch (Exception x) { } ; } } System.out.println(lastConsoleEcho);
245        */
246     }
247   }
248
249   /*
250    * (non-Javadoc)
251    * 
252    * @see jalview.io.AlignFile#print()
253    */
254   @Override
255   public String print()
256   {
257     // TODO Auto-generated method stub
258     return null;
259   }
260
261   @Override
262   public void setCallbackFunction(String callbackType,
263           String callbackFunction)
264   {
265     // TODO Auto-generated method stub
266
267   }
268
269   /*
270    * @Override public void notifyCallback(EnumCallback type, Object[] data) {
271    * try { switch (type) { case ERROR: case SCRIPT:
272    * notifyScriptTermination((String) data[2], ((Integer) data[3]).intValue());
273    * break; case MESSAGE: sendConsoleMessage((data == null) ? ((String) null) :
274    * (String) data[1]); break; case LOADSTRUCT: notifyFileLoaded((String)
275    * data[1], (String) data[2], (String) data[3], (String) data[4], ((Integer)
276    * data[5]).intValue());
277    * 
278    * break; default: // System.err.println("Unhandled callback " + type + " " //
279    * + data[1].toString()); break; } } catch (Exception e) {
280    * System.err.println("Squashed Jmol callback handler error:");
281    * e.printStackTrace(); } }
282    */
283   public void notifyCallback(EnumCallback type, Object[] data)
284   {
285     String strInfo = (data == null || data[1] == null ? null : data[1]
286             .toString());
287     switch (type)
288     {
289     case ECHO:
290       sendConsoleEcho(strInfo);
291       break;
292     case SCRIPT:
293       notifyScriptTermination((String) data[2],
294               ((Integer) data[3]).intValue());
295       break;
296     case MEASURE:
297       String mystatus = (String) data[3];
298       if (mystatus.indexOf("Picked") >= 0
299               || mystatus.indexOf("Sequence") >= 0) // picking mode
300         sendConsoleMessage(strInfo);
301       else if (mystatus.indexOf("Completed") >= 0)
302         sendConsoleEcho(strInfo.substring(strInfo.lastIndexOf(",") + 2,
303                 strInfo.length() - 1));
304       break;
305     case MESSAGE:
306       sendConsoleMessage(data == null ? null : strInfo);
307       break;
308     case PICK:
309       sendConsoleMessage(strInfo);
310       break;
311     default:
312       break;
313     }
314   }
315
316   private void notifyFileLoaded(String string, String string2,
317           String string3, String string4, int intValue)
318   {
319     // TODO Auto-generated method stub
320
321   }
322
323   String lastConsoleEcho = "";
324
325   private void sendConsoleEcho(String string)
326   {
327     lastConsoleEcho += string;
328     lastConsoleEcho += "\n";
329   }
330
331   String lastConsoleMessage = "";
332
333   private void sendConsoleMessage(String string)
334   {
335     lastConsoleMessage += string;
336     lastConsoleMessage += "\n";
337   }
338
339   int lastScriptTermination = -1;
340
341   String lastScriptMessage = "";
342
343   private void notifyScriptTermination(String string, int intValue)
344   {
345     lastScriptMessage += string;
346     lastScriptMessage += "\n";
347     lastScriptTermination = intValue;
348   }
349
350   @Override
351   public boolean notifyEnabled(EnumCallback callbackPick)
352   {
353     switch (callbackPick)
354     {
355     case MESSAGE:
356     case SCRIPT:
357     case ECHO:
358     case LOADSTRUCT:
359     case ERROR:
360       return true;
361     case MEASURE:
362     case PICK:
363     case HOVER:
364     case RESIZE:
365     case SYNC:
366     case CLICK:
367     case ANIMFRAME:
368     case MINIMIZATION:
369     }
370     return false;
371   }
372
373   @Override
374   public String eval(String strEval)
375   {
376     // TODO Auto-generated method stub
377     return null;
378   }
379
380   @Override
381   public float[][] functionXY(String functionName, int x, int y)
382   {
383     // TODO Auto-generated method stub
384     return null;
385   }
386
387   @Override
388   public float[][][] functionXYZ(String functionName, int nx, int ny, int nz)
389   {
390     // TODO Auto-generated method stub
391     return null;
392   }
393
394   @Override
395   public String createImage(String fileName, String type,
396           Object text_or_bytes, int quality)
397   {
398     // TODO Auto-generated method stub
399     return null;
400   }
401
402   @Override
403   public Map<String, Object> getRegistryInfo()
404   {
405     // TODO Auto-generated method stub
406     return null;
407   }
408
409   @Override
410   public void showUrl(String url)
411   {
412     // TODO Auto-generated method stub
413
414   }
415
416   @Override
417   public void resizeInnerPanel(String data)
418   {
419     // TODO Auto-generated method stub
420
421   }
422
423 }