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