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