file format enum wip changes
[jalview.git] / src / jalview / io / JSONFile.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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
22 package jalview.io;
23
24 import jalview.api.AlignExportSettingI;
25 import jalview.api.AlignViewportI;
26 import jalview.api.AlignmentViewPanel;
27 import jalview.api.ComplexAlignFile;
28 import jalview.api.FeatureRenderer;
29 import jalview.api.FeatureSettingsModelI;
30 import jalview.api.FeaturesDisplayedI;
31 import jalview.bin.BuildDetails;
32 import jalview.datamodel.AlignmentAnnotation;
33 import jalview.datamodel.AlignmentI;
34 import jalview.datamodel.Annotation;
35 import jalview.datamodel.ColumnSelection;
36 import jalview.datamodel.HiddenSequences;
37 import jalview.datamodel.Sequence;
38 import jalview.datamodel.SequenceFeature;
39 import jalview.datamodel.SequenceGroup;
40 import jalview.datamodel.SequenceI;
41 import jalview.json.binding.biojson.v1.AlignmentAnnotationPojo;
42 import jalview.json.binding.biojson.v1.AlignmentPojo;
43 import jalview.json.binding.biojson.v1.AnnotationDisplaySettingPojo;
44 import jalview.json.binding.biojson.v1.AnnotationPojo;
45 import jalview.json.binding.biojson.v1.ColourSchemeMapper;
46 import jalview.json.binding.biojson.v1.SequenceFeaturesPojo;
47 import jalview.json.binding.biojson.v1.SequenceGrpPojo;
48 import jalview.json.binding.biojson.v1.SequencePojo;
49 import jalview.schemes.ColourSchemeProperty;
50 import jalview.schemes.UserColourScheme;
51 import jalview.viewmodel.seqfeatures.FeaturesDisplayed;
52
53 import java.awt.Color;
54 import java.io.IOException;
55 import java.io.Reader;
56 import java.util.ArrayList;
57 import java.util.Hashtable;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.Vector;
61
62 import org.json.simple.JSONArray;
63 import org.json.simple.JSONObject;
64 import org.json.simple.parser.JSONParser;
65
66 public class JSONFile extends AlignFile implements ComplexAlignFile
67 {
68   private static String version = new BuildDetails().getVersion();
69
70   private String webstartUrl = "http://www.jalview.org/services/launchApp";
71
72   private String application = "Jalview";
73
74   private String globalColourScheme;
75
76   private boolean showSeqFeatures;
77
78   private Hashtable<String, Sequence> seqMap;
79
80   private FeaturesDisplayedI displayedFeatures;
81
82   private FeatureRenderer fr;
83
84   private List<int[]> hiddenColumns;
85
86   private ColumnSelection columnSelection;
87
88   private List<String> hiddenSeqRefs;
89
90   private ArrayList<SequenceI> hiddenSequences;
91
92   private final static String TCOFFEE_SCORE = "TCoffeeScore";
93
94   public JSONFile()
95   {
96     super();
97   }
98
99   public JSONFile(FileParse source) throws IOException
100   {
101     super(source);
102   }
103
104   public JSONFile(String inFile, DataSourceType sourceType)
105           throws IOException
106   {
107     super(inFile, sourceType);
108   }
109
110   @Override
111   public void parse() throws IOException
112   {
113     parse(getReader());
114
115   }
116
117   @Override
118   public String print()
119   {
120     String jsonOutput = null;
121     try
122     {
123       AlignmentPojo jsonAlignmentPojo = new AlignmentPojo();
124       AlignExportSettingI exportSettings = getExportSettings();
125
126       // if no export settings were supplied use the following with all values
127       // defaulting to true
128       if (exportSettings == null)
129       {
130         exportSettings = new AlignExportSettingI()
131         {
132           @Override
133           public boolean isExportHiddenSequences()
134           {
135             return true;
136           }
137
138           @Override
139           public boolean isExportHiddenColumns()
140           {
141             return true;
142           }
143
144           @Override
145           public boolean isExportGroups()
146           {
147             return true;
148           }
149
150           @Override
151           public boolean isExportFeatures()
152           {
153             return true;
154           }
155
156           @Override
157           public boolean isExportAnnotations()
158           {
159             return true;
160           }
161
162           @Override
163           public boolean isCancelled()
164           {
165             return false;
166           }
167         };
168       }
169
170       int count = 0;
171       for (SequenceI seq : seqs)
172       {
173         StringBuilder name = new StringBuilder();
174         name.append(seq.getName()).append("/").append(seq.getStart())
175                 .append("-").append(seq.getEnd());
176         SequencePojo jsonSeqPojo = new SequencePojo();
177         jsonSeqPojo.setId(String.valueOf(seq.hashCode()));
178         jsonSeqPojo.setOrder(++count);
179         jsonSeqPojo.setEnd(seq.getEnd());
180         jsonSeqPojo.setStart(seq.getStart());
181         jsonSeqPojo.setName(name.toString());
182         jsonSeqPojo.setSeq(seq.getSequenceAsString());
183         jsonAlignmentPojo.getSeqs().add(jsonSeqPojo);
184       }
185       jsonAlignmentPojo.setGlobalColorScheme(globalColourScheme);
186       jsonAlignmentPojo.getAppSettings().put("application", application);
187       jsonAlignmentPojo.getAppSettings().put("version", version);
188       jsonAlignmentPojo.getAppSettings().put("webStartUrl", webstartUrl);
189       jsonAlignmentPojo.getAppSettings().put("showSeqFeatures",
190               String.valueOf(showSeqFeatures));
191
192       String[] hiddenSections = getHiddenSections();
193       if (hiddenSections != null)
194       {
195         if (hiddenSections[0] != null
196                 && exportSettings.isExportHiddenColumns())
197         {
198           jsonAlignmentPojo.getAppSettings().put("hiddenCols",
199                   String.valueOf(hiddenSections[0]));
200         }
201         if (hiddenSections[1] != null
202                 && exportSettings.isExportHiddenSequences())
203         {
204           jsonAlignmentPojo.getAppSettings().put("hiddenSeqs",
205                   String.valueOf(hiddenSections[1]));
206         }
207       }
208
209       if (exportSettings.isExportAnnotations())
210       {
211         jsonAlignmentPojo
212                 .setAlignAnnotation(annotationToJsonPojo(annotations));
213       }
214       else
215       {
216         // These color schemes require annotation, disable them if annotations
217         // are not exported
218         if (globalColourScheme.equalsIgnoreCase("RNA Helices")
219                 || globalColourScheme.equalsIgnoreCase("T-COFFEE SCORES"))
220         {
221           jsonAlignmentPojo.setGlobalColorScheme("None");
222         }
223       }
224
225       if (exportSettings.isExportFeatures())
226       {
227         jsonAlignmentPojo
228                 .setSeqFeatures(sequenceFeatureToJsonPojo(seqs, fr));
229       }
230
231       if (exportSettings.isExportGroups() && seqGroups != null
232               && seqGroups.size() > 0)
233       {
234         for (SequenceGroup seqGrp : seqGroups)
235         {
236           SequenceGrpPojo seqGrpPojo = new SequenceGrpPojo();
237           seqGrpPojo.setGroupName(seqGrp.getName());
238           seqGrpPojo.setColourScheme(ColourSchemeProperty
239                   .getColourName(seqGrp.cs));
240           seqGrpPojo.setColourText(seqGrp.getColourText());
241           seqGrpPojo.setDescription(seqGrp.getDescription());
242           seqGrpPojo.setDisplayBoxes(seqGrp.getDisplayBoxes());
243           seqGrpPojo.setDisplayText(seqGrp.getDisplayText());
244           seqGrpPojo.setEndRes(seqGrp.getEndRes());
245           seqGrpPojo.setStartRes(seqGrp.getStartRes());
246           seqGrpPojo.setShowNonconserved(seqGrp.getShowNonconserved());
247           for (SequenceI seq : seqGrp.getSequences())
248           {
249             seqGrpPojo.getSequenceRefs()
250                     .add(String.valueOf(seq.hashCode()));
251           }
252           jsonAlignmentPojo.getSeqGroups().add(seqGrpPojo);
253         }
254       }
255       org.json.JSONObject generatedJSon = new org.json.JSONObject(
256               jsonAlignmentPojo);
257       jsonOutput = generatedJSon.toString();
258       return jsonOutput.replaceAll("xstart", "xStart").replaceAll("xend",
259               "xEnd");
260     } catch (Exception e)
261     {
262       e.printStackTrace();
263     }
264     return jsonOutput;
265   }
266
267   public String[] getHiddenSections()
268   {
269     String[] hiddenSections = new String[2];
270     if (getViewport() == null)
271     {
272       return null;
273     }
274
275     // hidden column business
276     if (getViewport().hasHiddenColumns())
277     {
278       List<int[]> hiddenCols = getViewport().getColumnSelection()
279               .getHiddenColumns();
280       StringBuilder hiddenColsBuilder = new StringBuilder();
281       for (int[] range : hiddenCols)
282       {
283         hiddenColsBuilder.append(";").append(range[0]).append("-")
284                 .append(range[1]);
285       }
286
287       hiddenColsBuilder.deleteCharAt(0);
288       hiddenSections[0] = hiddenColsBuilder.toString();
289     }
290
291     // hidden rows/seqs business
292     HiddenSequences hiddenSeqsObj = getViewport().getAlignment()
293             .getHiddenSequences();
294     if (hiddenSeqsObj == null || hiddenSeqsObj.hiddenSequences == null)
295     {
296       return hiddenSections;
297     }
298
299     SequenceI[] hiddenSeqs = hiddenSeqsObj.hiddenSequences;
300     StringBuilder hiddenSeqsBuilder = new StringBuilder();
301     for (SequenceI hiddenSeq : hiddenSeqs)
302     {
303       if (hiddenSeq != null)
304       {
305         hiddenSeqsBuilder.append(";").append(hiddenSeq.hashCode());
306       }
307     }
308     if (hiddenSeqsBuilder.length() > 0)
309     {
310       hiddenSeqsBuilder.deleteCharAt(0);
311     }
312     hiddenSections[1] = hiddenSeqsBuilder.toString();
313
314     return hiddenSections;
315   }
316
317   public List<SequenceFeaturesPojo> sequenceFeatureToJsonPojo(
318           List<SequenceI> seqs, FeatureRenderer fr)
319   {
320     displayedFeatures = (fr == null) ? null : fr.getFeaturesDisplayed();
321     List<SequenceFeaturesPojo> sequenceFeaturesPojo = new ArrayList<SequenceFeaturesPojo>();
322     for (SequenceI seq : seqs)
323     {
324       SequenceI dataSetSequence = seq.getDatasetSequence();
325       SequenceFeature[] seqFeatures = (dataSetSequence == null) ? null
326               : seq.getDatasetSequence().getSequenceFeatures();
327
328       seqFeatures = (seqFeatures == null) ? seq.getSequenceFeatures()
329               : seqFeatures;
330       if (seqFeatures == null)
331       {
332         continue;
333       }
334
335       for (SequenceFeature sf : seqFeatures)
336       {
337         if (displayedFeatures != null
338                 && displayedFeatures.isVisible(sf.getType()))
339         {
340           SequenceFeaturesPojo jsonFeature = new SequenceFeaturesPojo(
341                   String.valueOf(seq.hashCode()));
342
343           String featureColour = (fr == null) ? null : jalview.util.Format
344                   .getHexString(fr.findFeatureColour(Color.white, seq,
345                           seq.findIndex(sf.getBegin())));
346           jsonFeature.setXstart(seq.findIndex(sf.getBegin()) - 1);
347           jsonFeature.setXend(seq.findIndex(sf.getEnd()));
348           jsonFeature.setType(sf.getType());
349           jsonFeature.setDescription(sf.getDescription());
350           jsonFeature.setLinks(sf.links);
351           jsonFeature.setOtherDetails(sf.otherDetails);
352           jsonFeature.setScore(sf.getScore());
353           jsonFeature.setFillColor(featureColour);
354           jsonFeature.setFeatureGroup(sf.getFeatureGroup());
355           sequenceFeaturesPojo.add(jsonFeature);
356         }
357       }
358     }
359     return sequenceFeaturesPojo;
360   }
361
362   public static List<AlignmentAnnotationPojo> annotationToJsonPojo(
363           Vector<AlignmentAnnotation> annotations)
364   {
365     List<AlignmentAnnotationPojo> jsonAnnotations = new ArrayList<AlignmentAnnotationPojo>();
366     if (annotations == null)
367     {
368       return jsonAnnotations;
369     }
370     for (AlignmentAnnotation annot : annotations)
371     {
372       AlignmentAnnotationPojo alignAnnotPojo = new AlignmentAnnotationPojo();
373       alignAnnotPojo.setDescription(annot.description);
374       alignAnnotPojo.setLabel(annot.label);
375       if (!Double.isNaN(annot.score))
376       {
377         alignAnnotPojo.setScore(annot.score);
378       }
379       alignAnnotPojo.setCalcId(annot.getCalcId());
380       alignAnnotPojo.setGraphType(annot.graph);
381
382       AnnotationDisplaySettingPojo annotSetting = new AnnotationDisplaySettingPojo();
383       annotSetting.setBelowAlignment(annot.belowAlignment);
384       annotSetting.setCentreColLabels(annot.centreColLabels);
385       annotSetting.setScaleColLabel(annot.scaleColLabel);
386       annotSetting.setShowAllColLabels(annot.showAllColLabels);
387       annotSetting.setVisible(annot.visible);
388       annotSetting.setHasIcon(annot.hasIcons);
389       alignAnnotPojo.setAnnotationSettings(annotSetting);
390       SequenceI refSeq = annot.sequenceRef;
391       if (refSeq != null)
392       {
393         alignAnnotPojo.setSequenceRef(String.valueOf(refSeq.hashCode()));
394       }
395       for (Annotation annotation : annot.annotations)
396       {
397         AnnotationPojo annotationPojo = new AnnotationPojo();
398         if (annotation != null)
399         {
400           annotationPojo.setDescription(annotation.description);
401           annotationPojo.setValue(annotation.value);
402           annotationPojo
403                   .setSecondaryStructure(annotation.secondaryStructure);
404           String displayChar = annotation.displayCharacter == null ? null
405                   : annotation.displayCharacter;
406           // System.out.println("--------------------->[" + displayChar + "]");
407           annotationPojo.setDisplayCharacter(displayChar);
408           if (annotation.colour != null)
409           {
410             annotationPojo.setColour(jalview.util.Format
411                     .getHexString(annotation.colour));
412           }
413           alignAnnotPojo.getAnnotations().add(annotationPojo);
414         }
415         else
416         {
417           if (annot.getCalcId() != null
418                   && annot.getCalcId().equalsIgnoreCase(TCOFFEE_SCORE))
419           {
420             // do nothing
421           }
422           else
423           {
424             alignAnnotPojo.getAnnotations().add(annotationPojo);
425           }
426         }
427       }
428       jsonAnnotations.add(alignAnnotPojo);
429     }
430     return jsonAnnotations;
431   }
432
433   @SuppressWarnings("unchecked")
434   public JSONFile parse(Reader jsonAlignmentString)
435   {
436     try
437     {
438       JSONParser jsonParser = new JSONParser();
439       JSONObject alignmentJsonObj = (JSONObject) jsonParser
440               .parse(jsonAlignmentString);
441       JSONArray seqJsonArray = (JSONArray) alignmentJsonObj.get("seqs");
442       JSONArray alAnnotJsonArray = (JSONArray) alignmentJsonObj
443               .get("alignAnnotation");
444       JSONArray jsonSeqArray = (JSONArray) alignmentJsonObj
445               .get("seqFeatures");
446       JSONArray seqGrpJsonArray = (JSONArray) alignmentJsonObj
447               .get("seqGroups");
448       JSONObject jvSettingsJsonObj = (JSONObject) alignmentJsonObj
449               .get("appSettings");
450
451       if (jvSettingsJsonObj != null)
452       {
453         globalColourScheme = (String) jvSettingsJsonObj
454                 .get("globalColorScheme");
455         Boolean showFeatures = Boolean.valueOf(jvSettingsJsonObj.get(
456                 "showSeqFeatures").toString());
457         setShowSeqFeatures(showFeatures);
458         parseHiddenSeqRefsAsList(jvSettingsJsonObj);
459         parseHiddenCols(jvSettingsJsonObj);
460       }
461
462       hiddenSequences = new ArrayList<SequenceI>();
463       seqMap = new Hashtable<String, Sequence>();
464       for (Iterator<JSONObject> sequenceIter = seqJsonArray.iterator(); sequenceIter
465               .hasNext();)
466       {
467         JSONObject sequence = sequenceIter.next();
468         String sequcenceString = sequence.get("seq").toString();
469         String sequenceName = sequence.get("name").toString();
470         String seqUniqueId = sequence.get("id").toString();
471         int start = Integer.valueOf(sequence.get("start").toString());
472         int end = Integer.valueOf(sequence.get("end").toString());
473         Sequence seq = new Sequence(sequenceName, sequcenceString, start,
474                 end);
475         if (hiddenSeqRefs != null && hiddenSeqRefs.contains(seqUniqueId))
476         {
477           hiddenSequences.add(seq);
478         }
479         seqs.add(seq);
480         seqMap.put(seqUniqueId, seq);
481       }
482
483       parseFeatures(jsonSeqArray);
484
485       for (Iterator<JSONObject> seqGrpIter = seqGrpJsonArray.iterator(); seqGrpIter
486               .hasNext();)
487       {
488         JSONObject seqGrpObj = seqGrpIter.next();
489         String grpName = seqGrpObj.get("groupName").toString();
490         String colourScheme = seqGrpObj.get("colourScheme").toString();
491         String description = (seqGrpObj.get("description") == null) ? null
492                 : seqGrpObj.get("description").toString();
493         boolean displayBoxes = Boolean.valueOf(seqGrpObj
494                 .get("displayBoxes").toString());
495         boolean displayText = Boolean.valueOf(seqGrpObj.get("displayText")
496                 .toString());
497         boolean colourText = Boolean.valueOf(seqGrpObj.get("colourText")
498                 .toString());
499         boolean showNonconserved = Boolean.valueOf(seqGrpObj.get(
500                 "showNonconserved").toString());
501         int startRes = Integer
502                 .valueOf(seqGrpObj.get("startRes").toString());
503         int endRes = Integer.valueOf(seqGrpObj.get("endRes").toString());
504         JSONArray sequenceRefs = (JSONArray) seqGrpObj.get("sequenceRefs");
505
506         ArrayList<SequenceI> grpSeqs = new ArrayList<SequenceI>();
507         if (sequenceRefs.size() > 0)
508         {
509           Iterator<String> seqHashIter = sequenceRefs.iterator();
510           while (seqHashIter.hasNext())
511           {
512             String seqHash = seqHashIter.next();
513             Sequence sequence = seqMap.get(seqHash);
514             if (sequence != null)
515             {
516               grpSeqs.add(sequence);
517             }
518           }
519         }
520         SequenceGroup seqGrp = new SequenceGroup(grpSeqs, grpName, null,
521                 displayBoxes, displayText, colourText, startRes, endRes);
522         seqGrp.cs = ColourSchemeMapper.getJalviewColourScheme(colourScheme,
523                 seqGrp);
524         seqGrp.setShowNonconserved(showNonconserved);
525         seqGrp.setDescription(description);
526         this.seqGroups.add(seqGrp);
527
528       }
529
530       for (Iterator<JSONObject> alAnnotIter = alAnnotJsonArray.iterator(); alAnnotIter
531               .hasNext();)
532       {
533         JSONObject alAnnot = alAnnotIter.next();
534         JSONArray annotJsonArray = (JSONArray) alAnnot.get("annotations");
535         Annotation[] annotations = new Annotation[annotJsonArray.size()];
536         int count = 0;
537         for (Iterator<JSONObject> annotIter = annotJsonArray.iterator(); annotIter
538                 .hasNext();)
539         {
540           JSONObject annot = annotIter.next();
541           if (annot == null)
542           {
543             annotations[count] = null;
544           }
545           else
546           {
547             float val = annot.get("value") == null ? null : Float
548                     .valueOf(annot.get("value").toString());
549             String desc = annot.get("description") == null ? null : annot
550                     .get("description").toString();
551             char ss = annot.get("secondaryStructure") == null
552                     || annot.get("secondaryStructure").toString()
553                             .equalsIgnoreCase("u0000") ? ' ' : annot
554                     .get("secondaryStructure").toString().charAt(0);
555             String displayChar = annot.get("displayCharacter") == null ? ""
556                     : annot.get("displayCharacter").toString();
557
558             annotations[count] = new Annotation(displayChar, desc, ss, val);
559             if (annot.get("colour") != null)
560             {
561               Color color = UserColourScheme.getColourFromString(annot.get(
562                       "colour").toString());
563               annotations[count].colour = color;
564             }
565           }
566           ++count;
567         }
568
569         AlignmentAnnotation alignAnnot = new AlignmentAnnotation(alAnnot
570                 .get("label").toString(), alAnnot.get("description")
571                 .toString(), annotations);
572         alignAnnot.graph = (alAnnot.get("graphType") == null) ? 0 : Integer
573                 .valueOf(alAnnot.get("graphType").toString());
574
575         JSONObject diplaySettings = (JSONObject) alAnnot
576                 .get("annotationSettings");
577         if (diplaySettings != null)
578         {
579
580           alignAnnot.scaleColLabel = (diplaySettings.get("scaleColLabel") == null) ? false
581                   : Boolean.valueOf(diplaySettings.get("scaleColLabel")
582                           .toString());
583           alignAnnot.showAllColLabels = (diplaySettings
584                   .get("showAllColLabels") == null) ? true : Boolean
585                   .valueOf(diplaySettings.get("showAllColLabels")
586                           .toString());
587           alignAnnot.centreColLabels = (diplaySettings
588                   .get("centreColLabels") == null) ? true
589                   : Boolean.valueOf(diplaySettings.get("centreColLabels")
590                           .toString());
591           alignAnnot.belowAlignment = (diplaySettings.get("belowAlignment") == null) ? false
592                   : Boolean.valueOf(diplaySettings.get("belowAlignment")
593                           .toString());
594           alignAnnot.visible = (diplaySettings.get("visible") == null) ? true
595                   : Boolean.valueOf(diplaySettings.get("visible")
596                           .toString());
597           alignAnnot.hasIcons = (diplaySettings.get("hasIcon") == null) ? true
598                   : Boolean.valueOf(diplaySettings.get("hasIcon")
599                           .toString());
600
601         }
602         if (alAnnot.get("score") != null)
603         {
604           alignAnnot.score = Double
605                   .valueOf(alAnnot.get("score").toString());
606         }
607
608         String calcId = (alAnnot.get("calcId") == null) ? "" : alAnnot.get(
609                 "calcId").toString();
610         alignAnnot.setCalcId(calcId);
611         String seqHash = (alAnnot.get("sequenceRef") != null) ? alAnnot
612                 .get("sequenceRef").toString() : null;
613
614         Sequence sequence = (seqHash != null) ? seqMap.get(seqHash) : null;
615         if (sequence != null)
616         {
617           alignAnnot.sequenceRef = sequence;
618           sequence.addAlignmentAnnotation(alignAnnot);
619           if (alignAnnot.label.equalsIgnoreCase("T-COFFEE"))
620           {
621             alignAnnot.createSequenceMapping(sequence, sequence.getStart(),
622                     false);
623             sequence.addAlignmentAnnotation(alignAnnot);
624             alignAnnot.adjustForAlignment();
625           }
626         }
627         alignAnnot.validateRangeAndDisplay();
628         this.annotations.add(alignAnnot);
629
630       }
631     } catch (Exception e)
632     {
633       e.printStackTrace();
634     }
635     return this;
636   }
637
638   public void parseHiddenSeqRefsAsList(JSONObject jvSettingsJson)
639   {
640     hiddenSeqRefs = new ArrayList<String>();
641     String hiddenSeqs = (String) jvSettingsJson.get("hiddenSeqs");
642     if (hiddenSeqs != null && !hiddenSeqs.isEmpty())
643     {
644       String[] seqRefs = hiddenSeqs.split(";");
645       for (String seqRef : seqRefs)
646       {
647         hiddenSeqRefs.add(seqRef);
648       }
649     }
650   }
651
652   public void parseHiddenCols(JSONObject jvSettingsJson)
653   {
654     String hiddenCols = (String) jvSettingsJson.get("hiddenCols");
655     if (hiddenCols != null && !hiddenCols.isEmpty())
656     {
657       columnSelection = new ColumnSelection();
658       String[] rangeStrings = hiddenCols.split(";");
659       for (String rangeString : rangeStrings)
660       {
661         String[] range = rangeString.split("-");
662         columnSelection.hideColumns(Integer.valueOf(range[0]),
663                 Integer.valueOf(range[1]));
664       }
665     }
666   }
667
668   @SuppressWarnings("unchecked")
669   private void parseFeatures(JSONArray jsonSeqFeatures)
670   {
671     if (jsonSeqFeatures != null)
672     {
673       displayedFeatures = new FeaturesDisplayed();
674       for (Iterator<JSONObject> seqFeatureItr = jsonSeqFeatures.iterator(); seqFeatureItr
675               .hasNext();)
676       {
677         JSONObject jsonFeature = seqFeatureItr.next();
678         Long begin = (Long) jsonFeature.get("xStart");
679         Long end = (Long) jsonFeature.get("xEnd");
680         String type = (String) jsonFeature.get("type");
681         String featureGrp = (String) jsonFeature.get("featureGroup");
682         String descripiton = (String) jsonFeature.get("description");
683         String seqRef = (String) jsonFeature.get("sequenceRef");
684         Float score = Float.valueOf(jsonFeature.get("score").toString());
685
686         Sequence seq = seqMap.get(seqRef);
687         SequenceFeature sequenceFeature = new SequenceFeature();
688         JSONArray linksJsonArray = (JSONArray) jsonFeature.get("links");
689         if (linksJsonArray != null && linksJsonArray.size() > 0)
690         {
691           Iterator<String> linkList = linksJsonArray.iterator();
692           while (linkList.hasNext())
693           {
694             String link = linkList.next();
695             sequenceFeature.addLink(link);
696           }
697         }
698         sequenceFeature.setFeatureGroup(featureGrp);
699         sequenceFeature.setScore(score);
700         sequenceFeature.setDescription(descripiton);
701         sequenceFeature.setType(type);
702         sequenceFeature.setBegin(seq.findPosition(begin.intValue()));
703         sequenceFeature.setEnd(seq.findPosition(end.intValue()) - 1);
704         seq.addSequenceFeature(sequenceFeature);
705         displayedFeatures.setVisible(type);
706       }
707     }
708   }
709
710   @Override
711   public String getGlobalColourScheme()
712   {
713     return globalColourScheme;
714   }
715
716   public void setGlobalColorScheme(String globalColourScheme)
717   {
718     this.globalColourScheme = globalColourScheme;
719   }
720
721   @Override
722   public FeaturesDisplayedI getDisplayedFeatures()
723   {
724     return displayedFeatures;
725   }
726
727   public void setDisplayedFeatures(FeaturesDisplayedI displayedFeatures)
728   {
729     this.displayedFeatures = displayedFeatures;
730   }
731
732   @Override
733   public void configureForView(AlignmentViewPanel avpanel)
734   {
735     super.configureForView(avpanel);
736     AlignViewportI viewport = avpanel.getAlignViewport();
737     AlignmentI alignment = viewport.getAlignment();
738     AlignmentAnnotation[] annots = alignment.getAlignmentAnnotation();
739
740     seqGroups = alignment.getGroups();
741     fr = avpanel.cloneFeatureRenderer();
742
743     // Add non auto calculated annotation to AlignFile
744     if (annots != null)
745     {
746       for (AlignmentAnnotation annot : annots)
747       {
748         if (annot != null && !annot.autoCalculated)
749         {
750           annotations.add(annot);
751         }
752       }
753     }
754     globalColourScheme = ColourSchemeProperty.getColourName(viewport
755             .getGlobalColourScheme());
756     setDisplayedFeatures(viewport.getFeaturesDisplayed());
757     showSeqFeatures = viewport.isShowSequenceFeatures();
758
759   }
760
761   @Override
762   public boolean isShowSeqFeatures()
763   {
764     return showSeqFeatures;
765   }
766
767   public void setShowSeqFeatures(boolean showSeqFeatures)
768   {
769     this.showSeqFeatures = showSeqFeatures;
770   }
771
772   public Vector<AlignmentAnnotation> getAnnotations()
773   {
774     return annotations;
775   }
776
777   public List<int[]> getHiddenColumns()
778   {
779     return hiddenColumns;
780   }
781
782   @Override
783   public ColumnSelection getColumnSelection()
784   {
785     return columnSelection;
786   }
787
788   public void setColumnSelection(ColumnSelection columnSelection)
789   {
790     this.columnSelection = columnSelection;
791   }
792
793   @Override
794   public SequenceI[] getHiddenSequences()
795   {
796     if (hiddenSequences == null || hiddenSequences.isEmpty())
797     {
798       return new SequenceI[] {};
799     }
800     synchronized (hiddenSequences)
801     {
802       return hiddenSequences.toArray(new SequenceI[hiddenSequences.size()]);
803     }
804   }
805
806   public void setHiddenSequences(ArrayList<SequenceI> hiddenSequences)
807   {
808     this.hiddenSequences = hiddenSequences;
809   }
810
811   public class JSONExportSettings
812   {
813     private boolean exportSequence;
814
815     private boolean exportSequenceFeatures;
816
817     private boolean exportAnnotations;
818
819     private boolean exportGroups;
820
821     private boolean exportJalviewSettings;
822
823     public boolean isExportSequence()
824     {
825       return exportSequence;
826     }
827
828     public void setExportSequence(boolean exportSequence)
829     {
830       this.exportSequence = exportSequence;
831     }
832
833     public boolean isExportSequenceFeatures()
834     {
835       return exportSequenceFeatures;
836     }
837
838     public void setExportSequenceFeatures(boolean exportSequenceFeatures)
839     {
840       this.exportSequenceFeatures = exportSequenceFeatures;
841     }
842
843     public boolean isExportAnnotations()
844     {
845       return exportAnnotations;
846     }
847
848     public void setExportAnnotations(boolean exportAnnotations)
849     {
850       this.exportAnnotations = exportAnnotations;
851     }
852
853     public boolean isExportGroups()
854     {
855       return exportGroups;
856     }
857
858     public void setExportGroups(boolean exportGroups)
859     {
860       this.exportGroups = exportGroups;
861     }
862
863     public boolean isExportJalviewSettings()
864     {
865       return exportJalviewSettings;
866     }
867
868     public void setExportJalviewSettings(boolean exportJalviewSettings)
869     {
870       this.exportJalviewSettings = exportJalviewSettings;
871     }
872   }
873
874   /**
875    * Returns a descriptor for suitable feature display settings with
876    * <ul>
877    * <li>ResNums or insertions features visible</li>
878    * <li>insertions features coloured red</li>
879    * <li>ResNum features coloured by label</li>
880    * <li>Insertions displayed above (on top of) ResNums</li>
881    * </ul>
882    */
883   @Override
884   public FeatureSettingsModelI getFeatureColourScheme()
885   {
886     return new PDBFeatureSettings();
887   }
888 }