JAL-629 Attempts to add PAE to structure. --headless working. Make HTML output single...
[jalview.git] / src / jalview / bin / Commands.java
1 package jalview.bin;
2
3 import java.io.File;
4 import java.util.ArrayList;
5 import java.util.Arrays;
6 import java.util.Collections;
7 import java.util.HashMap;
8 import java.util.Iterator;
9 import java.util.List;
10 import java.util.Locale;
11 import java.util.Map;
12
13 import jalview.analysis.AlignmentUtils;
14 import jalview.api.AlignmentViewPanel;
15 import jalview.bin.ArgParser.Arg;
16 import jalview.bin.ArgParser.ArgValues;
17 import jalview.bin.ArgParser.SubVal;
18 import jalview.datamodel.AlignmentAnnotation;
19 import jalview.datamodel.AlignmentI;
20 import jalview.datamodel.SequenceI;
21 import jalview.datamodel.annotations.AlphaFoldAnnotationRowBuilder;
22 import jalview.gui.AlignFrame;
23 import jalview.gui.AlignmentPanel;
24 import jalview.gui.Desktop;
25 import jalview.gui.StructureChooser;
26 import jalview.io.AppletFormatAdapter;
27 import jalview.io.DataSourceType;
28 import jalview.io.FileFormatException;
29 import jalview.io.FileFormatI;
30 import jalview.io.FileLoader;
31 import jalview.io.HtmlSvgOutput;
32 import jalview.io.IdentifyFile;
33 import jalview.structure.StructureImportSettings;
34 import jalview.structure.StructureImportSettings.TFType;
35 import jalview.structure.StructureSelectionManager;
36 import jalview.util.HttpUtils;
37 import jalview.util.MessageManager;
38 import jalview.util.Platform;
39 import jalview.ws.dbsources.EBIAlfaFold;
40
41 public class Commands
42 {
43   Desktop desktop;
44
45   private static boolean headless;
46
47   private static ArgParser argParser;
48
49   private Map<String, AlignFrame> afMap;
50
51   public static void processArgs(ArgParser ap, boolean h)
52   {
53     argParser = ap;
54     headless = h;
55
56     if (headless)
57     {
58       System.setProperty("java.awt.headless", "true");
59     }
60
61     if (argParser != null && argParser.linkedIds() != null)
62     {
63       for (String id : argParser.linkedIds())
64       {
65         Console.debug("##### id=" + id);
66         Commands cmds = new Commands();
67         if (id == null)
68         {
69           cmds.processUnlinked(id);
70         }
71         else
72         {
73           cmds.processLinked(id);
74         }
75         cmds.processImages(id);
76       }
77
78     }
79     if (argParser.getBool(Arg.QUIT))
80     {
81       Jalview.getInstance().quit();
82       // Desktop.instance.quit();
83     }
84   }
85
86   public Commands()
87   {
88     this(Desktop.instance);
89   }
90
91   public Commands(Desktop d)
92   {
93     this.desktop = d;
94     afMap = new HashMap<String, AlignFrame>();
95   }
96
97   protected void processUnlinked(String id)
98   {
99     Map<Arg, ArgValues> m = argParser.linkedArgs(id);
100
101     processLinked(id);
102   }
103
104   protected void processLinked(String id)
105   {
106     Map<Arg, ArgValues> m = argParser.linkedArgs(id);
107
108     /*
109     // script to execute after all loading is completed one way or another
110     String groovyscript = m.get(Arg.GROOVY) == null ? null
111             : m.get(Arg.GROOVY).getValue();
112     String file = m.get(Arg.OPEN) == null ? null
113             : m.get(Arg.OPEN).getValue();
114     String data = null;
115     FileFormatI format = null;
116     DataSourceType protocol = null;
117     */
118     if (ArgParser.getArgValues(m, Arg.OPEN) != null)
119     {
120       long progress = -1;
121
122       boolean first = true;
123       AlignFrame af;
124       OPEN: for (String openFile : ArgParser.getValues(m, Arg.OPEN))
125       {
126         if (openFile == null)
127           continue OPEN;
128
129         if (first)
130         {
131           first = false;
132           if (!headless)
133           {
134             desktop.setProgressBar(
135                     MessageManager.getString(
136                             "status.processing_commandline_args"),
137                     progress = System.currentTimeMillis());
138           }
139         }
140
141         if (!Platform.isJS())
142         /**
143          * ignore in JavaScript -- can't just file existence - could load it?
144          * 
145          * @j2sIgnore
146          */
147         {
148           if (!HttpUtils.startsWithHttpOrHttps(openFile))
149           {
150             if (!(new File(openFile)).exists())
151             {
152               Console.warn("Can't find file '" + openFile + "'");
153               continue OPEN;
154             }
155           }
156         }
157
158         DataSourceType protocol = AppletFormatAdapter
159                 .checkProtocol(openFile);
160
161         FileFormatI format = null;
162         try
163         {
164           format = new IdentifyFile().identify(openFile, protocol);
165         } catch (FileFormatException e1)
166         {
167           Console.error("Unknown file format for '" + openFile + "'");
168         }
169
170         af = afMap.get(id);
171         if (af == null)
172         {
173           /*
174            * this approach isn't working yet
175           // get default annotations before opening AlignFrame
176           if (m.get(Arg.SSANNOTATION) != null)
177           {
178             Console.debug("***** SSANNOTATION="
179                     + m.get(Arg.SSANNOTATION).getBoolean());
180           }
181           if (m.get(Arg.NOTEMPFAC) != null)
182           {
183             Console.debug(
184                     "***** NOTEMPFAC=" + m.get(Arg.NOTEMPFAC).getBoolean());
185           }
186           boolean showSecondaryStructure = (m.get(Arg.SSANNOTATION) != null)
187                   ? m.get(Arg.SSANNOTATION).getBoolean()
188                   : false;
189           boolean showTemperatureFactor = (m.get(Arg.NOTEMPFAC) != null)
190                   ? !m.get(Arg.NOTEMPFAC).getBoolean()
191                   : false;
192           Console.debug("***** tempfac=" + showTemperatureFactor
193                   + ", showSS=" + showSecondaryStructure);
194           StructureSelectionManager ssm = StructureSelectionManager
195                   .getStructureSelectionManager(Desktop.instance);
196           if (ssm != null)
197           {
198             ssm.setAddTempFacAnnot(showTemperatureFactor);
199             ssm.setProcessSecondaryStructure(showSecondaryStructure);
200           }
201            */
202
203           // get kind of temperature factor annotation
204           StructureImportSettings.TFType tempfacType = TFType.DEFAULT;
205           if ((!ArgParser.getBoolean(m, Arg.NOTEMPFAC))
206                   && ArgParser.getArgValues(m, Arg.TEMPFAC) != null)
207           {
208             try
209             {
210               tempfacType = StructureImportSettings.TFType.valueOf(ArgParser
211                       .getValue(m, Arg.TEMPFAC).toUpperCase(Locale.ROOT));
212               Console.debug("Obtained Temperature Factor type of '"
213                       + tempfacType + "'");
214             } catch (IllegalArgumentException e)
215             {
216               // Just an error message!
217               StringBuilder sb = new StringBuilder().append("Cannot set --")
218                       .append(Arg.TEMPFAC.getName()).append(" to '")
219                       .append(tempfacType)
220                       .append("', ignoring.  Valid values are: ");
221               Iterator<StructureImportSettings.TFType> it = Arrays
222                       .stream(StructureImportSettings.TFType.values())
223                       .iterator();
224               while (it.hasNext())
225               {
226                 sb.append(it.next().toString().toLowerCase(Locale.ROOT));
227                 if (it.hasNext())
228                   sb.append(", ");
229               }
230               Console.warn(sb.toString());
231             }
232           }
233
234           Console.debug(
235                   "Opening '" + openFile + "' in new alignment frame");
236           FileLoader fileLoader = new FileLoader(!headless);
237
238           StructureImportSettings.setTemperatureFactorType(tempfacType);
239
240           af = fileLoader.LoadFileWaitTillLoaded(openFile, protocol,
241                   format);
242
243           // wrap alignment?
244           if (ArgParser.getBoolean(m, Arg.WRAP))
245           {
246             af.getCurrentView().setWrapAlignment(true);
247           }
248
249           // change alignment frame title
250           if (ArgParser.getValue(m, Arg.TITLE) != null)
251             af.setTitle(ArgParser.getValue(m, Arg.TITLE));
252
253           /* hacky approach to hiding the annotations */
254           // show secondary structure annotations?
255           if (ArgParser.getBoolean(m, Arg.SSANNOTATION))
256           {
257             // do this better (annotation types?)
258             AlignmentUtils.showOrHideSequenceAnnotations(
259                     af.getCurrentView().getAlignment(),
260                     Collections.singleton("Secondary Structure"), null,
261                     false, false);
262           }
263
264           // show temperature factor annotations?
265           if (ArgParser.getBoolean(m, Arg.NOTEMPFAC))
266           {
267             // do this better (annotation types?)
268             List<String> hideThese = new ArrayList<>();
269             hideThese.add("Temperature Factor");
270             hideThese.add(AlphaFoldAnnotationRowBuilder.LABEL);
271             AlignmentUtils.showOrHideSequenceAnnotations(
272                     af.getCurrentView().getAlignment(), hideThese, null,
273                     false, false);
274           }
275           else
276           /* comment out hacky approach up to here and add this line:
277            if (showTemperatureFactor)
278              */
279           {
280             if (ArgParser.getValue(m, Arg.TEMPFAC_LABEL) != null)
281             {
282               AlignmentAnnotation aa = AlignmentUtils
283                       .getFirstSequenceAnnotationOfType(
284                               af.getCurrentView().getAlignment(),
285                               AlignmentAnnotation.LINE_GRAPH);
286               String label = ArgParser.getValue(m, Arg.TEMPFAC_LABEL);
287               if (aa != null)
288               {
289                 aa.label = label;
290               }
291               else
292               {
293                 Console.info(
294                         "Could not find annotation to apply tempfac_label '"
295                                 + label);
296               }
297             }
298           }
299
300           // store the AlignFrame for this id
301           afMap.put(id, af);
302
303           // is it its own structure file?
304           if (format.isStructureFile())
305           {
306             StructureSelectionManager ssm = StructureSelectionManager
307                     .getStructureSelectionManager(Desktop.instance);
308             SequenceI seq = af.alignPanel.getAlignment().getSequenceAt(0);
309             ssm.computeMapping(false, new SequenceI[] { seq }, null,
310                     openFile, DataSourceType.FILE, null);
311           }
312         }
313         else
314         {
315           Console.debug(
316                   "Opening '" + openFile + "' in existing alignment frame");
317           af.getCurrentView().addFile(new File(openFile), format);
318         }
319
320         System.out
321                 .println("Command " + Arg.OPEN + " executed successfully!");
322
323       }
324       if (first) // first=true means nothing opened
325       {
326         if (headless)
327         {
328           Console.error("Could not open any files in headless mode");
329           System.exit(1);
330         }
331       }
332       else
333       {
334         Console.warn("No more files to open");
335         if (desktop != null)
336           desktop.setProgressBar(null, progress);
337       }
338
339     }
340
341     // load a pAE file if given
342     if (ArgParser.getValues(m, Arg.PAEMATRIX) != null)
343     {
344       AlignFrame af = afMap.get(id);
345       if (af != null)
346       {
347         for (String val : ArgParser.getValues(m, Arg.PAEMATRIX))
348         {
349           SubVal subVal = ArgParser.getSubVal(val);
350           File paeFile = new File(subVal.content);
351           String structId = "structid".equals(subVal.keyName)
352                   ? subVal.keyValue
353                   : null;
354           if (subVal.notSet())
355           {
356             // take structid from pdbfilename
357           }
358           if ("structfile".equals(subVal.keyName))
359           {
360             EBIAlfaFold.addAlphaFoldPAEToStructure(
361                     af.getCurrentView().getAlignment(), paeFile,
362                     subVal.index, subVal.keyValue, false);
363           }
364           else if ("structid".equals(subVal.keyName))
365           {
366             EBIAlfaFold.addAlphaFoldPAEToStructure(
367                     af.getCurrentView().getAlignment(), paeFile,
368                     subVal.index, subVal.keyValue, true);
369           }
370           else
371           {
372             EBIAlfaFold.addAlphaFoldPAEToSequence(
373                     af.getCurrentView().getAlignment(), paeFile,
374                     subVal.index,
375                     "seqid".equals(subVal.keyName) ? subVal.keyValue
376                             : null);
377             // required to readjust the height and position of the pAE
378             // annotation
379           }
380           for (AlignmentViewPanel ap : af.getAlignPanels())
381           {
382             ap.adjustAnnotationHeight();
383           }
384         }
385       }
386     }
387
388     // open the structure (from same PDB file or given PDBfile)
389     if (!ArgParser.getBoolean(m, Arg.NOSTRUCTURE))
390     {
391       AlignFrame af = afMap.get(id);
392       if (ArgParser.getArgValues(m, Arg.STRUCTURE) != null)
393       {
394         STRUCTURE: for (String val : ArgParser.getValues(m, Arg.STRUCTURE))
395         {
396           SubVal subId = new SubVal(val);
397           SequenceI seq = getSpecifiedSequence(af, subId);
398           if (seq == null)
399           {
400             Console.warn("Could not find sequence for argument --"
401                     + Arg.STRUCTURE + "=" + val);
402             break STRUCTURE;
403           }
404           File structureFile = null;
405           if (subId.content != null && subId.content.length() != 0)
406           {
407             structureFile = new File(subId.content);
408             Console.debug("Using structure file (from argument) '"
409                     + structureFile.getAbsolutePath() + "'");
410           }
411           /* THIS DOESN'T WORK */
412           else if (seq.getAllPDBEntries() != null
413                   && seq.getAllPDBEntries().size() > 0)
414           {
415             structureFile = new File(
416                     seq.getAllPDBEntries().elementAt(0).getFile());
417             Console.debug("Using structure file (from sequence) '"
418                     + structureFile.getAbsolutePath() + "'");
419           }
420
421           if (structureFile == null)
422           {
423             Console.warn("Not provided structure file with '" + val + "'");
424             continue STRUCTURE;
425           }
426
427           if (!structureFile.exists())
428           {
429             Console.warn("Structure file '"
430                     + structureFile.getAbsoluteFile() + "' not found.");
431             continue STRUCTURE;
432           }
433
434           Console.debug("Using structure file "
435                   + structureFile.getAbsolutePath());
436
437           // open structure view
438           AlignmentPanel ap = af.alignPanel;
439           StructureChooser.openStructureFileForSequence(ap, seq,
440                   structureFile);
441         }
442       }
443     }
444   }
445
446   protected void processImages(String id)
447   {
448     Map<Arg, ArgValues> m = argParser.linkedArgs(id);
449     AlignFrame af = afMap.get(id);
450
451     if (af == null)
452     {
453       Console.warn("Did not have an alignment window for id=" + id);
454       return;
455     }
456
457     if (ArgParser.getValues(m, Arg.IMAGE) != null)
458     {
459       for (String val : ArgParser.getValues(m, Arg.IMAGE))
460       {
461         SubVal subVal = new SubVal(val);
462         String type = "png"; // default
463         String fileName = subVal.content;
464         File file = new File(fileName);
465         if ("type".equals(subVal.keyName))
466         {
467           type = subVal.keyValue;
468         }
469         else if (fileName != null)
470         {
471           for (String ext : new String[] { "svg", "png", "html" })
472           {
473             if (fileName.toLowerCase(Locale.ROOT).endsWith("." + ext))
474             {
475               type = ext;
476             }
477           }
478         }
479         switch (type)
480         {
481         case "svg":
482           Console.debug("Outputting type '" + type + "' to " + fileName);
483           af.createSVG(file);
484           break;
485         case "png":
486           Console.debug("Outputting type '" + type + "' to " + fileName);
487           af.createPNG(file);
488           break;
489         case "html":
490           Console.debug("Outputting type '" + type + "' to " + fileName);
491           HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel);
492           htmlSVG.exportHTML(fileName);
493           break;
494         default:
495           Console.warn("--image type '" + type + "' not known. Ignoring");
496           break;
497         }
498       }
499     }
500   }
501
502   private SequenceI getSpecifiedSequence(AlignFrame af, SubVal subId)
503   {
504     AlignmentI al = af.getCurrentView().getAlignment();
505     if (-1 < subId.index && subId.index < al.getSequences().size())
506     {
507       return al.getSequenceAt(subId.index);
508     }
509     else if ("id".equals(subId.keyName))
510     {
511       return al.findName(subId.keyValue);
512     }
513     return null;
514   }
515 }