Merge branch 'develop' into features/filetypeEnum
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 30 Aug 2016 11:56:34 +0000 (12:56 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 30 Aug 2016 11:56:34 +0000 (12:56 +0100)
Conflicts:
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/FormatAdapter.java
src/jalview/io/MSFfile.java
src/jalview/io/RnamlFile.java
src/jalview/io/StockholmFile.java
src/jalview/ws/dbsources/Pdb.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/gui/AlignViewportTest.java
test/jalview/ws/jabaws/RNAStructExportImport.java

60 files changed:
1  2 
src/MCview/PDBfile.java
src/jalview/appletgui/APopupMenu.java
src/jalview/appletgui/AlignFrame.java
src/jalview/bin/Jalview.java
src/jalview/bin/JalviewLite.java
src/jalview/controller/AlignViewController.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/PDBEntry.java
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/ext/jmol/JmolParser.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/Jalview2XML_V1.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/gui/SequenceFetcher.java
src/jalview/gui/TreePanel.java
src/jalview/gui/UserDefinedColours.java
src/jalview/gui/WsParamSetManager.java
src/jalview/io/AlignFile.java
src/jalview/io/AppletFormatAdapter.java
src/jalview/io/BioJsHTMLOutput.java
src/jalview/io/FileFormat.java
src/jalview/io/HTMLOutput.java
src/jalview/io/HtmlSvgOutput.java
src/jalview/io/JSONFile.java
src/jalview/io/JalviewFileChooser.java
src/jalview/io/MSFfile.java
src/jalview/io/PfamFile.java
src/jalview/io/RnamlFile.java
src/jalview/io/StockholmFile.java
src/jalview/io/StructureFile.java
src/jalview/jbgui/GFinder.java
src/jalview/structure/StructureImportSettings.java
src/jalview/structure/StructureSelectionManager.java
src/jalview/util/ImageMaker.java
src/jalview/ws/dbsources/Pdb.java
src/jalview/ws/jws1/Annotate3D.java
src/jalview/ws/jws1/JPredThread.java
src/jalview/ws/jws1/SeqSearchWSThread.java
src/jalview/ws/rest/params/Alignment.java
test/jalview/analysis/AlignmentUtilsTests.java
test/jalview/analysis/DnaTest.java
test/jalview/datamodel/AlignmentAnnotationTests.java
test/jalview/datamodel/AlignmentTest.java
test/jalview/ext/jmol/JmolParserTest.java
test/jalview/ext/jmol/JmolVsJalviewPDBParserEndToEndTest.java
test/jalview/gui/AlignViewportTest.java
test/jalview/io/AnnotatedPDBFileInputTest.java
test/jalview/io/FormatAdapterTest.java
test/jalview/io/Jalview2xmlTests.java
test/jalview/io/StockholmFileTest.java
test/jalview/structure/StructureSelectionManagerTest.java
test/jalview/util/MappingUtilsTest.java
test/jalview/ws/jabaws/RNAStructExportImport.java
test/jalview/ws/sifts/SiftsClientTest.java

@@@ -23,10 -23,8 +23,9 @@@ package MCview
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.DBRefSource;
  import jalview.datamodel.SequenceI;
- import jalview.io.FileParse;
 +import jalview.io.DataSourceType;
+ import jalview.io.FileParse;
  import jalview.io.StructureFile;
- import jalview.structure.StructureImportSettings;
  import jalview.util.MessageManager;
  
  import java.io.IOException;
@@@ -67,7 -64,7 +66,7 @@@ public class PDBfile extends StructureF
    }
  
    @Override
--  public String print()
++  public String print(SequenceI[] seqs, boolean jvSuffix)
    {
      return null;
    }
Simple merge
Simple merge
Simple merge
@@@ -37,8 -37,6 +37,9 @@@ import jalview.datamodel.SequenceGroup
  import jalview.datamodel.SequenceI;
  import jalview.io.AnnotationFile;
  import jalview.io.AppletFormatAdapter;
 +import jalview.io.DataSourceType;
++import jalview.io.FileFormat;
 +import jalview.io.FileFormatI;
  import jalview.io.FileParse;
  import jalview.io.IdentifyFile;
  import jalview.io.JPredFile;
@@@ -522,21 -513,21 +517,23 @@@ public class JalviewLite extends Apple
    {
      try
      {
++      FileFormatI theFormat = FileFormat.valueOf(format);
        boolean seqlimits = suffix.equalsIgnoreCase(TRUE);
        if (alf.viewport.getSelectionGroup() != null)
        {
          // JBPNote: getSelectionAsNewSequence behaviour has changed - this
          // method now returns a full copy of sequence data
          // TODO consider using getSequenceSelection instead here
--        String reply = new AppletFormatAdapter().formatSequences(format,
++        String reply = new AppletFormatAdapter().formatSequences(theFormat,
                  new Alignment(alf.viewport.getSelectionAsNewSequence()),
                  seqlimits);
          return reply;
        }
--    } catch (Exception ex)
++    } catch (IllegalArgumentException ex)
      {
        ex.printStackTrace();
--      return "Error retrieving alignment in " + format + " format. ";
++      return "Error retrieving alignment, possibly invalid format specifier: "
++              + format;
      }
      return "";
    }
      {
        boolean seqlimits = suffix.equalsIgnoreCase(TRUE);
  
--      String reply = new AppletFormatAdapter().formatSequences(format,
++      FileFormatI theFormat = FileFormat.valueOf(format);
++      String reply = new AppletFormatAdapter().formatSequences(theFormat,
                alf.viewport.getAlignment(), seqlimits);
        return reply;
--    } catch (Exception ex)
++    } catch (IllegalArgumentException ex)
      {
        ex.printStackTrace();
--      return "Error retrieving alignment in " + format + " format. ";
++      return "Error retrieving alignment, possibly invalid format specifier: "
++              + format;
      }
    }
  
@@@ -1737,7 -1742,7 +1742,7 @@@ public class Alignment implements Align
    @Override
    public String toString()
    {
--    return new FastaFile().print(getSequencesArray());
++    return new FastaFile().print(getSequencesArray(), true);
    }
  
    /**
@@@ -34,10 -34,10 +34,30 @@@ public class PDBEntr
  
    public enum Type
    {
--    PDB, MMCIF, FILE
++    // TODO is FILE needed; if not is this needed or can we
++    // use FileFormatI for PDB, MMCIF?
++    PDB("pdb", "xml"), MMCIF("mmcif", "mmcif"), FILE("?", "?");
++    String ext;
++
++    String format;
++
++    private Type(String fmt, String ex)
++    {
++      format = fmt;
++      ext = ex;
++    }
++
++    public String getFormat()
++    {
++      return format;
++    }
++    public String getExtension()
++    {
++      return ext;
++    }
    }
  
 -  Hashtable properties;
 +  Hashtable<String, String> properties;
  
    /*
     * (non-Javadoc)
@@@ -1,5 -1,5 +1,6 @@@
  package jalview.ext.ensembl;
  
++import jalview.io.DataSourceType;
  import jalview.io.FileParse;
  import jalview.util.StringUtils;
  
@@@ -196,7 -208,7 +209,7 @@@ abstract class EnsemblRestClient extend
      URL url = getUrl(ids);
    
      BufferedReader reader = getHttpResponse(url, ids);
--    FileParse fp = new FileParse(reader, url.toString(), "HTTP_POST");
++    FileParse fp = new FileParse(reader, url.toString(), DataSourceType.URL);
      return fp;
    }
  
@@@ -22,10 -22,8 +22,9 @@@ package jalview.ext.jmol
  
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.Annotation;
- import jalview.datamodel.DBRefSource;
  import jalview.datamodel.SequenceI;
- import jalview.io.FileParse;
 +import jalview.io.DataSourceType;
+ import jalview.io.FileParse;
  import jalview.io.StructureFile;
  import jalview.schemes.ResidueProperties;
  import jalview.structure.StructureImportSettings;
@@@ -398,7 -443,7 +444,7 @@@ public class JmolParser extends Structu
     * Not implemented - returns null
     */
    @Override
--  public String print()
++  public String print(SequenceI[] seqs, boolean jvSuffix)
    {
      return null;
    }
@@@ -1106,11 -1103,11 +1107,11 @@@ public class AlignFrame extends GAlignF
    @Override
    public void saveAs_actionPerformed(ActionEvent e)
    {
--    JalviewFileChooser chooser = new JalviewFileChooser(
 -            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
 -            jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS,
 -            jalview.io.AppletFormatAdapter.WRITABLE_FNAMES,
 -            currentFileFormat, false);
++    JalviewFileChooser chooser = JalviewFileChooser.forWrite(
 +            Cache.getProperty("LAST_DIRECTORY"),
 +            // AppletFormatAdapter.WRITABLE_EXTENSIONS,
 +            // AppletFormatAdapter.WRITABLE_FNAMES,
-             currentFileFormat, false);
++            currentFileFormat.toString(), false);
  
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager
@@@ -1866,7 -1865,7 +1867,8 @@@ fileFormat
        omitHidden = viewport.getViewAsString(true);
      }
  
--    String output = new FormatAdapter().formatSequences("Fasta", seqs,
++    String output = new FormatAdapter().formatSequences(FileFormat.Fasta,
++            seqs,
              omitHidden, null);
  
      StringSelection ss = new StringSelection(output);
Simple merge
Simple merge
@@@ -446,12 -443,11 +446,11 @@@ public class Desktop extends jalview.jb
        public void run()
        {
          Cache.log.debug("Filechooser init thread started.");
-         FileFormat fileFormat = FileFormat.valueOf(Cache
-                 .getProperty("DEFAULT_FILE_FORMAT"));
-         new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"),
 -        new JalviewFileChooser(
 -                jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
 -                jalview.io.AppletFormatAdapter.READABLE_EXTENSIONS,
 -                jalview.io.AppletFormatAdapter.READABLE_FNAMES,
 -                jalview.bin.Cache.getProperty("DEFAULT_FILE_FORMAT"));
++        String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
++        JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
 +        // jalview.io.AppletFormatAdapter.READABLE_EXTENSIONS,
 +        // jalview.io.AppletFormatAdapter.READABLE_FNAMES,
-                 fileFormat);
++                fileFormat, true);
          Cache.log.debug("Filechooser init thread finished.");
        }
      }).start();
    @Override
    public void inputLocalFileMenuItem_actionPerformed(AlignViewport viewport)
    {
-     FileFormat fileFormat = FileFormat.valueOf(Cache
-             .getProperty("DEFAULT_FILE_FORMAT"));
--    JalviewFileChooser chooser = new JalviewFileChooser(
 -            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
 -            jalview.io.AppletFormatAdapter.READABLE_EXTENSIONS,
 -            jalview.io.AppletFormatAdapter.READABLE_FNAMES,
 -            jalview.bin.Cache.getProperty("DEFAULT_FILE_FORMAT"));
++    String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
++    JalviewFileChooser chooser = JalviewFileChooser.forRead(
 +            Cache.getProperty("LAST_DIRECTORY"),
 +            // AppletFormatAdapter.READABLE_EXTENSIONS,
 +            // AppletFormatAdapter.READABLE_FNAMES,
-             fileFormat);
++            fileFormat, true);
  
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager
     */
    @Override
    public void inputURLMenuItem_actionPerformed(AlignViewport viewport)
-           throws FileFormatException
++  // throws FileFormatException
    {
      // This construct allows us to have a wider textfield
      // for viewing
      }
      else
      {
-       FileFormatI format = new IdentifyFile().identify(url,
-               DataSourceType.URL);
 -      String format = new IdentifyFile().identify(url, FormatAdapter.URL);
++      FileFormatI format = null;
++      try
++      {
++        format = new IdentifyFile().identify(url, DataSourceType.URL);
++      } catch (FileFormatException e)
++      {
++        // TODO revise error handling, distinguish between
++        // URL not found and response not valid
++      }
  
--      if (format.equals("URL NOT FOUND"))
++      if (format == null)
        {
          JOptionPane.showInternalMessageDialog(Desktop.desktop,
                  MessageManager.formatMessage("label.couldnt_locate",
    public void saveState_actionPerformed(ActionEvent e)
    {
      JalviewFileChooser chooser = new JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "jvp" }, new String[] { "Jalview Project" },
++            Cache.getProperty("LAST_DIRECTORY"), "jvp", "Jalview Project",
              "Jalview Project");
  
      chooser.setFileView(new JalviewFileView());
    public void loadState_actionPerformed(ActionEvent e)
    {
      JalviewFileChooser chooser = new JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[] {
++            Cache.getProperty("LAST_DIRECTORY"), new String[] {
                  "jvp", "jar" }, new String[] { "Jalview Project",
                  "Jalview Project (old)" }, "Jalview Project");
      chooser.setFileView(new JalviewFileView());
        final File selectedFile = chooser.getSelectedFile();
        setProjectFile(selectedFile);
        final String choice = selectedFile.getAbsolutePath();
--      jalview.bin.Cache.setProperty("LAST_DIRECTORY",
++      Cache.setProperty("LAST_DIRECTORY",
                selectedFile.getParent());
        new Thread(new Runnable()
        {
      if (v_client != null)
      {
        JalviewFileChooser chooser = new JalviewFileChooser(
--              jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
--              { "vdj" }, // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
--              new String[] { "Vamsas Document" }, "Vamsas Document");
++              Cache.getProperty("LAST_DIRECTORY"), "vdj",
++              "Vamsas Document", "Vamsas Document");
  
        chooser.setFileView(new JalviewFileView());
        chooser.setDialogTitle(MessageManager
          JPanel progpanel = addProgressPanel(MessageManager.formatMessage(
                  "label.saving_vamsas_doc",
                  new Object[] { choice.getName() }));
--        jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
++        Cache.setProperty("LAST_DIRECTORY", choice.getParent());
          String warnmsg = null;
          String warnttl = null;
          try
@@@ -736,10 -750,10 +750,8 @@@ public class FeatureSettings extends JP
    void load()
    {
      JalviewFileChooser chooser = new JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "fc" },
--            new String[] { "Sequence Feature Colours" },
--            "Sequence Feature Colours");
++            Cache.getProperty("LAST_DIRECTORY"), "fc",
++            "Sequence Feature Colours", "Sequence Feature Colours");
      chooser.setFileView(new jalview.io.JalviewFileView());
      chooser.setDialogTitle(MessageManager
              .getString("label.load_feature_colours"));
    void save()
    {
      JalviewFileChooser chooser = new JalviewFileChooser(
--            Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "fc" },
--            new String[] { "Sequence Feature Colours" },
--            "Sequence Feature Colours");
++            Cache.getProperty("LAST_DIRECTORY"), "fc",
++            "Sequence Feature Colours", "Sequence Feature Colours");
      chooser.setFileView(new jalview.io.JalviewFileView());
      chooser.setDialogTitle(MessageManager
              .getString("label.save_feature_colours"));
@@@ -36,7 -36,6 +36,8 @@@ import jalview.datamodel.StructureViewe
  import jalview.datamodel.StructureViewerModel.StructureData;
  import jalview.ext.varna.RnaModel;
  import jalview.gui.StructureViewer.ViewerType;
 +import jalview.io.DataSourceType;
++import jalview.io.FileFormat;
  import jalview.schemabinding.version2.AlcodMap;
  import jalview.schemabinding.version2.AlcodonFrame;
  import jalview.schemabinding.version2.Annotation;
@@@ -4104,7 -4260,7 +4261,7 @@@ public class Jalview2XM
      af = new AlignFrame(al, view.getWidth(), view.getHeight(),
              uniqueSeqSetId, viewId);
  
--    af.setFileName(file, "Jalview");
++    af.setFileName(file, FileFormat.Jalview);
  
      for (int i = 0; i < JSEQ.length; i++)
      {
@@@ -35,6 -35,6 +35,7 @@@ import jalview.binding.Tree
  import jalview.binding.UserColours;
  import jalview.binding.Viewport;
  import jalview.datamodel.PDBEntry;
++import jalview.io.FileFormat;
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemeProperty;
  import jalview.schemes.ResidueProperties;
@@@ -305,7 -305,7 +306,7 @@@ public class Jalview2XML_V
  
      AlignFrame af = new AlignFrame(al, view.getWidth(), view.getHeight());
  
--    af.setFileName(file, "Jalview");
++    af.setFileName(file, FileFormat.Jalview);
  
      for (int i = 0; i < JSEQ.length; i++)
      {
@@@ -38,7 -38,6 +38,8 @@@ import jalview.datamodel.Sequence
  import jalview.datamodel.SequenceFeature;
  import jalview.datamodel.SequenceGroup;
  import jalview.datamodel.SequenceI;
 +import jalview.io.FileFormat;
++import jalview.io.FileFormatI;
  import jalview.io.FormatAdapter;
  import jalview.io.SequenceAnnotationReport;
  import jalview.schemes.AnnotationColourGradient;
@@@ -2339,8 -2334,8 +2336,8 @@@ public class PopupMenu extends JPopupMe
      // or we simply trust the user wants
      // wysiwig behaviour
  
-     FileFormat fileFormat = FileFormat.forName(e.getActionCommand());
 -    cap.setText(new FormatAdapter(ap).formatSequences(e.getActionCommand(),
 -            ap, true));
++    FileFormatI fileFormat = FileFormat.forName(e.getActionCommand());
 +    cap.setText(new FormatAdapter(ap).formatSequences(fileFormat, ap, true));
    }
  
    public void sequenceFeature_actionPerformed()
@@@ -684,14 -683,12 +683,14 @@@ public class Preferences extends GPrefe
    @Override
    public void startupFileTextfield_mouseClicked()
    {
-     FileFormat fileFormat = FileFormat.valueOf(Cache.getProperty("DEFAULT_FILE_FORMAT"));
--    JalviewFileChooser chooser = new JalviewFileChooser(
-     // fixme push into enum
-             Cache.getProperty("LAST_DIRECTORY"), new String[] {
-                 "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc",
-                 "jar" }, new String[] { "Fasta", "Clustal", "PFAM", "MSF",
-                 "PIR", "BLC", "Jalview" },
-             fileFormat);
 -            jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[] {
 -                "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc",
 -                "jar" }, new String[] { "Fasta", "Clustal", "PFAM", "MSF",
 -                "PIR", "BLC", "Jalview" },
 -            jalview.bin.Cache.getProperty("DEFAULT_FILE_FORMAT"));
++    String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
++    JalviewFileChooser chooser = JalviewFileChooser.forRead(
++            Cache.getProperty("LAST_DIRECTORY"), fileFormat, true);
++    // new String[] {
++    // "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc",
++    // "jar" }, new String[] { "Fasta", "Clustal", "PFAM", "MSF",
++    // "PIR", "BLC", "Jalview" },
++    // fileFormat);
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager
              .getString("label.select_startup_file"));
Simple merge
@@@ -42,6 -42,6 +42,7 @@@ import jalview.io.JalviewFileView
  import jalview.io.NewickFile;
  import jalview.jbgui.GTreePanel;
  import jalview.schemes.ResidueProperties;
++import jalview.util.ImageMaker;
  import jalview.util.MessageManager;
  import jalview.viewmodel.AlignmentViewport;
  
@@@ -747,24 -747,24 +748,24 @@@ public class TreePanel extends GTreePan
  
      try
      {
--      jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
--              jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
--              { "eps" }, new String[] { "Encapsulated Postscript" },
--              "Encapsulated Postscript");
--      chooser.setFileView(new jalview.io.JalviewFileView());
++      JalviewFileChooser chooser = new JalviewFileChooser(
++              Cache.getProperty("LAST_DIRECTORY"),
++              ImageMaker.EPS_EXTENSION, ImageMaker.EPS_EXTENSION,
++              ImageMaker.EPS_EXTENSION);
++      chooser.setFileView(new JalviewFileView());
        chooser.setDialogTitle(MessageManager
                .getString("label.create_eps_from_tree"));
        chooser.setToolTipText(MessageManager.getString("action.save"));
  
        int value = chooser.showSaveDialog(this);
  
--      if (value != jalview.io.JalviewFileChooser.APPROVE_OPTION)
++      if (value != JalviewFileChooser.APPROVE_OPTION)
        {
          return;
        }
  
--      jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
--              .getSelectedFile().getParent());
++      Cache.setProperty("LAST_DIRECTORY", chooser.getSelectedFile()
++              .getParent());
  
        FileOutputStream out = new FileOutputStream(chooser.getSelectedFile());
        EpsGraphics2D pg = new EpsGraphics2D("Tree", out, 0, 0, width, height);
  
      try
      {
--      jalview.io.JalviewFileChooser chooser = new jalview.io.JalviewFileChooser(
--              jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
--              { "png" }, new String[] { "Portable network graphics" },
--              "Portable network graphics");
++      JalviewFileChooser chooser = new JalviewFileChooser(
++              Cache.getProperty("LAST_DIRECTORY"),
++              ImageMaker.PNG_EXTENSION, ImageMaker.PNG_DESCRIPTION,
++              ImageMaker.PNG_DESCRIPTION);
  
        chooser.setFileView(new jalview.io.JalviewFileView());
        chooser.setDialogTitle(MessageManager
@@@ -21,6 -21,6 +21,7 @@@
  package jalview.gui;
  
  import jalview.api.structures.JalviewStructureDisplayI;
++import jalview.bin.Cache;
  import jalview.datamodel.SequenceGroup;
  import jalview.io.JalviewFileChooser;
  import jalview.jbgui.GUserDefinedColours;
@@@ -597,9 -597,9 +598,8 @@@ public class UserDefinedColours extend
      lowerCaseButtons = new ArrayList<JButton>();
  
      JalviewFileChooser chooser = new JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "jc" }, new String[] { "Jalview User Colours" },
--            "Jalview User Colours");
++            Cache.getProperty("LAST_DIRECTORY"), "jc",
++            "Jalview User Colours", "Jalview User Colours");
      chooser.setFileView(new jalview.io.JalviewFileView());
      chooser.setDialogTitle(MessageManager
              .getString("label.load_colour_scheme"));
        userColourSchemes.remove(schemeName.getText());
      }
      JalviewFileChooser chooser = new JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "jc" }, new String[] { "Jalview User Colours" },
--            "Jalview User Colours");
++            Cache.getProperty("LAST_DIRECTORY"), "jc",
++            "Jalview User Colours", "Jalview User Colours");
  
      chooser.setFileView(new jalview.io.JalviewFileView());
      chooser.setDialogTitle(MessageManager
@@@ -22,6 -22,6 +22,7 @@@ package jalview.gui
  
  import jalview.bin.Cache;
  import jalview.io.JalviewFileChooser;
++import jalview.io.JalviewFileView;
  import jalview.util.MessageManager;
  import jalview.ws.params.ParamDatastoreI;
  import jalview.ws.params.ParamManager;
@@@ -185,11 -185,11 +186,9 @@@ public class WsParamSetManager implemen
      if (filename == null)
      {
        JalviewFileChooser chooser = new JalviewFileChooser(
--              jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
--              { "wsparams" },
--              new String[] { "Web Service Parameter File" },
--              "Web Service Parameter File");
--      chooser.setFileView(new jalview.io.JalviewFileView());
++              Cache.getProperty("LAST_DIRECTORY"), "wsparams",
++              "Web Service Parameter File", "Web Service Parameter File");
++      chooser.setFileView(new JalviewFileView());
        chooser.setDialogTitle(MessageManager
                .getString("label.choose_filename_for_param_file"));
        chooser.setToolTipText(MessageManager.getString("action.save"));
@@@ -370,18 -371,16 +370,23 @@@ public abstract class AlignFile extend
    }
  
    /**
--   * Creates the output id. Adds prefix Uniprot format source|id And suffix
--   * Jalview /start-end
++   * Creates the output id. Adds prefix Uniprot format source|id and optionally
++   * suffix Jalview /start-end
 +   * 
 +   * @param jvsuffix
     * 
     * @String id Id to be parsed
     */
 +  String printId(SequenceI seq, boolean jvsuffix)
 +  {
 +    return seq.getDisplayId(jvsuffix);
 +  }
 +
+   String printId(SequenceI seq)
+   {
 -    return seq.getDisplayId(jvSuffix);
++    return printId(seq, true);
+   }
    /**
     * vector of String[] treeName, newickString pairs
     */
@@@ -26,8 -26,9 +26,10 @@@ import jalview.datamodel.Alignment
  import jalview.datamodel.AlignmentAnnotation;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.AlignmentView;
+ import jalview.datamodel.PDBEntry.Type;
 +import jalview.datamodel.SequenceI;
++import jalview.ext.jmol.JmolParser;
  import jalview.structure.StructureImportSettings;
 -import jalview.util.MessageManager;
  
  import java.io.File;
  import java.io.IOException;
@@@ -177,45 -229,118 +179,68 @@@ public class AppletFormatAdapte
     *
     * @param inFile
     *          data/data location
 -   * @param type
 +   * @param sourceType
     *          type of datasource
 -   * @param format
 -   *          File format of data provided by datasource
 +   * @param fileFormat
     *
 -   * @return DOCUMENT ME!
 +   * @return
     */
 -  public AlignmentI readFile(String inFile, String type, String format)
 -          throws java.io.IOException
 +  public AlignmentI readFile(String file, DataSourceType sourceType,
 +          FileFormatI fileFormat) throws IOException
    {
 -    // TODO: generalise mapping between format string and io. class instances
 -    // using Constructor.invoke reflection
 -    this.inFile = inFile;
 +    this.inFile = file;
      try
      {
 -      if (format.equals("FASTA"))
 -      {
 -        alignFile = new FastaFile(inFile, type);
 -      }
 -      else if (format.equals("MSF"))
 -      {
 -        alignFile = new MSFfile(inFile, type);
 -      }
 -      else if (format.equals("PileUp"))
 -      {
 -        alignFile = new PileUpfile(inFile, type);
 -      }
 -      else if (format.equals("CLUSTAL"))
 -      {
 -        alignFile = new ClustalFile(inFile, type);
 -      }
 -      else if (format.equals("BLC"))
 -      {
 -        alignFile = new BLCFile(inFile, type);
 -      }
 -      else if (format.equals("PIR"))
 -      {
 -        alignFile = new PIRFile(inFile, type);
 -      }
 -      else if (format.equals("PFAM"))
 -      {
 -        alignFile = new PfamFile(inFile, type);
 -      }
 -      else if (format.equals("JnetFile"))
 -      {
 -        alignFile = new JPredFile(inFile, type);
 -        ((JPredFile) alignFile).removeNonSequences();
 -      }
 -      else if (format.equals("PDB"))
 +      if (fileFormat == FileFormat.PDB || fileFormat == FileFormat.MMCif)
        {
-         StructureImportSettings.addSettings(annotFromStructure,
-                 localSecondaryStruct, serviceSecondaryStruct);
-         alignFile = fileFormat.getAlignmentFile(inFile, sourceType);
+         // TODO obtain config value from preference settings.
+         // Set value to 'true' to test PDB processing with Jmol: JAL-1213
+         boolean isParseWithJMOL = StructureImportSettings
+                 .getDefaultPDBFileParser().equalsIgnoreCase(
+                         StructureImportSettings.StructureParser.JMOL_PARSER
+                                 .toString());
+         if (isParseWithJMOL)
+         {
+           StructureImportSettings.addSettings(annotFromStructure,
+                   localSecondaryStruct, serviceSecondaryStruct);
 -          alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
++          alignFile = new JmolParser(annotFromStructure,
+                   localSecondaryStruct, serviceSecondaryStruct, inFile,
 -                  type);
++                  sourceType);
+         }
+         else
+         {
+           StructureImportSettings.addSettings(annotFromStructure,
+                   localSecondaryStruct, serviceSecondaryStruct);
+           StructureImportSettings.setShowSeqFeatures(true);
+           alignFile = new MCview.PDBfile(annotFromStructure,
+                   localSecondaryStruct, serviceSecondaryStruct, inFile,
 -                  type);
++                  sourceType);
+         }
 -        ((StructureFile) alignFile).setDbRefType(format);
 -      }
 -      else if (format.equalsIgnoreCase("mmCIF"))
 -      {
 -        StructureImportSettings.addSettings(annotFromStructure,
 -                localSecondaryStruct, serviceSecondaryStruct);
 -        alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
 -                localSecondaryStruct, serviceSecondaryStruct, inFile, type);
 -        ((StructureFile) alignFile).setDbRefType(format);
 -      }
 -      else if (format.equals("STH"))
 -      {
 -        alignFile = new StockholmFile(inFile, type);
++        ((StructureFile) alignFile)
++                .setDbRefType(fileFormat == FileFormat.PDB ? Type.PDB
++                        : Type.MMCIF);
        }
 -      else if (format.equals("SimpleBLAST"))
 -      {
 -        alignFile = new SimpleBlastFile(inFile, type);
 -      }
 -      else if (format.equals(PhylipFile.FILE_DESC))
 -      {
 -        alignFile = new PhylipFile(inFile, type);
 -      }
 -      else if (format.equals(JSONFile.FILE_DESC))
 -      {
 -        alignFile = new JSONFile(inFile, type);
 -      }
 -      else if (format.equals(HtmlFile.FILE_DESC))
 -      {
 -        alignFile = new HtmlFile(inFile, type);
 -      }
 -      else if (format.equals("RNAML"))
 -      {
 -        alignFile = new RnamlFile(inFile, type);
 -      }
 -      else if (format.equals(IdentifyFile.FeaturesFile))
 +      else
        {
 -        alignFile = new FeaturesFile(true, inFile, type);
 -      }
 -      return buildAlignmentFrom(alignFile);
 +        alignFile = fileFormat.getAlignmentFile(inFile, sourceType);
 +      }
 +        // new FastaFile(inFile, sourceType);
 +        // new MSFfile(inFile, sourceType);
 +        // new PileUpfile(inFile, sourceType);
 +        // new ClustalFile(inFile, sourceType);
 +        // new BLCFile(inFile, sourceType);
 +        // new PIRFile(inFile, sourceType);
 +        // new PfamFile(inFile, sourceType);
 +        // alignFile = new JPredFile(inFile, sourceType);
 +        // ((JPredFile) alignFile).removeNonSequences();
 +        // new StockholmFile(inFile, sourceType);
 +        // new SimpleBlastFile(inFile, sourceType);
 +        // new PhylipFile(inFile, sourceType);
 +        // new JSONFile(inFile, sourceType);
 +        // new HtmlFile(inFile, sourceType);
 +        // new RnamlFile(inFile, sourceType);
 +//        alignFile = new FeaturesFile(true, inFile, sourceType);
 +      return buildAlignmentFromFile();
      } catch (Exception e)
      {
        e.printStackTrace();
     * @param format
     *          File format of data that will be provided by datasource
     *
 -   * @return DOCUMENT ME!
 +   * @return
     */
 -  public AlignmentI readFromFile(FileParse source, String format)
 -          throws java.io.IOException
 +  public AlignmentI readFromFile(FileParse source, FileFormatI format)
 +          throws IOException
    {
 -    // TODO: generalise mapping between format string and io. class instances
 -    // using Constructor.invoke reflection
 -    // This is exactly the same as the readFile method except we substitute
 -    // 'inFile, type' with 'source'
      this.inFile = source.getInFile();
 -    String type = source.type;
 +    DataSourceType type = source.dataSourceType;
      try
      {
 -      if (format.equals("FASTA"))
 -      {
 -        alignFile = new FastaFile(source);
 -      }
 -      else if (format.equals("MSF"))
 -      {
 -        alignFile = new MSFfile(source);
 -      }
 -      else if (format.equals("PileUp"))
 -      {
 -        alignFile = new PileUpfile(source);
 -      }
 -      else if (format.equals("CLUSTAL"))
 -      {
 -        alignFile = new ClustalFile(source);
 -      }
 -      else if (format.equals("BLC"))
 -      {
 -        alignFile = new BLCFile(source);
 -      }
 -      else if (format.equals("PIR"))
 -      {
 -        alignFile = new PIRFile(source);
 -      }
 -      else if (format.equals("PFAM"))
 -      {
 -        alignFile = new PfamFile(source);
 -      }
 -      else if (format.equals("JnetFile"))
 -      {
 -        alignFile = new JPredFile(source);
 -        ((JPredFile) alignFile).removeNonSequences();
 -      }
 -      else if (format.equals("PDB"))
 +      if (format == FileFormat.PDB || format == FileFormat.MMCif)
        {
-         StructureImportSettings.addSettings(annotFromStructure,
-                 localSecondaryStruct, serviceSecondaryStruct);
-         alignFile = format.getAlignmentFile(source);
+         // TODO obtain config value from preference settings
+         boolean isParseWithJMOL = false;
+         if (isParseWithJMOL)
+         {
+           StructureImportSettings.addSettings(annotFromStructure,
+                   localSecondaryStruct, serviceSecondaryStruct);
 -          alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
++          alignFile = new JmolParser(annotFromStructure,
+                   localSecondaryStruct, serviceSecondaryStruct, source);
+         }
+         else
+         {
+           StructureImportSettings.setShowSeqFeatures(true);
+           alignFile = new MCview.PDBfile(annotFromStructure,
+                   localSecondaryStruct, serviceSecondaryStruct, source);
+         }
+         ((StructureFile) alignFile).setDbRefType(Type.PDB);
        }
 -      else if (format.equalsIgnoreCase("mmCIF"))
 -      {
 -        StructureImportSettings.addSettings(annotFromStructure,
 -                localSecondaryStruct, serviceSecondaryStruct);
 -        alignFile = new jalview.ext.jmol.JmolParser(annotFromStructure,
 -                localSecondaryStruct, serviceSecondaryStruct, source);
 -        ((StructureFile) alignFile).setDbRefType(Type.MMCIF);
 -      }
 -      else if (format.equals("STH"))
 -      {
 -        alignFile = new StockholmFile(source);
 -      }
 -      else if (format.equals("RNAML"))
 -      {
 -        alignFile = new RnamlFile(source);
 -      }
 -      else if (format.equals("SimpleBLAST"))
 -      {
 -        alignFile = new SimpleBlastFile(source);
 -      }
 -      else if (format.equals(PhylipFile.FILE_DESC))
 -      {
 -        alignFile = new PhylipFile(source);
 -      }
 -      else if (format.equals(IdentifyFile.FeaturesFile))
 -      {
 -        alignFile = new FeaturesFile(inFile, type);
 -      }
 -      else if (format.equals(JSONFile.FILE_DESC))
 -      {
 -        alignFile = new JSONFile(source);
 -      }
 -      else if (format.equals(HtmlFile.FILE_DESC))
 +      else
        {
 -        alignFile = new HtmlFile(source);
 +        alignFile = format.getAlignmentFile(source);
        }
  
 -      return buildAlignmentFrom(alignFile);
 +      return buildAlignmentFromFile();
  
      } catch (Exception e)
      {
@@@ -22,13 -22,12 +22,15 @@@ package jalview.io
  
  import jalview.api.AlignExportSettingI;
  import jalview.api.AlignmentViewPanel;
++import jalview.bin.Cache;
  import jalview.datamodel.AlignmentExportData;
  import jalview.exceptions.NoFileSelectedException;
 +import jalview.gui.AlignFrame;
  import jalview.gui.IProgressIndicator;
  import jalview.gui.OOMWarning;
  import jalview.json.binding.biojs.BioJSReleasePojo;
  import jalview.json.binding.biojs.BioJSRepositoryPojo;
++import jalview.util.ImageMaker;
  import jalview.util.MessageManager;
  
  import java.io.BufferedInputStream;
@@@ -177,9 -176,9 +179,8 @@@ public class BioJsHTMLOutpu
      }
  
      JalviewFileChooser jvFileChooser = new JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "html" }, new String[] { "HTML files" },
--            "HTML files");
++            Cache.getProperty("LAST_DIRECTORY"), ImageMaker.HTML_EXTENSION,
++            ImageMaker.HTML_EXTENSION, ImageMaker.HTML_EXTENSION);
      jvFileChooser.setFileView(new JalviewFileView());
  
      jvFileChooser.setDialogTitle(MessageManager
      int fileChooserOpt = jvFileChooser.showSaveDialog(null);
      if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
      {
--      jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser
++      Cache.setProperty("LAST_DIRECTORY", jvFileChooser
                .getSelectedFile().getParent());
        selectedFile = jvFileChooser.getSelectedFile().getPath();
      }
index bca365f,0000000..a7113f6
mode 100644,000000..100644
--- /dev/null
@@@ -1,529 -1,0 +1,530 @@@
 +package jalview.io;
 +
++import jalview.datamodel.PDBEntry;
 +import jalview.ext.jmol.JmolParser;
 +import jalview.structure.StructureImportSettings;
 +
 +import java.io.IOException;
 +import java.util.HashMap;
 +import java.util.Map;
 +
 +public enum FileFormat implements FileFormatI
 +{
 +  Fasta("FASTA", "fa, fasta, mfa, fastq", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new FastaFile(inFile, sourceType);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new FastaFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new FastaFile();
 +    }
 +  },
 +  Pfam("PFAM", "pfam", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new PfamFile(inFile, sourceType);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new PfamFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new PfamFile();
 +    }
 +  },
 +  Stockholm("STH", "sto,stk", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new StockholmFile(inFile, sourceType);
 +    }
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new StockholmFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new StockholmFile();
 +    }
 +
 +  },
 +
 +  PIR("PIR", "pir", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new PIRFile(inFile, sourceType);
 +    }
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new PIRFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new PIRFile();
 +    }
 +  },
 +  BLC("BLC", "BLC", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new BLCFile(inFile, sourceType);
 +    }    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new BLCFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new BLCFile();
 +    }
 +  },
 +  Html("HTML", "html", true, false)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new HtmlFile(inFile, sourceType);
 +    }    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new HtmlFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new HtmlFile();
 +    }
 +
 +    @Override
 +    public boolean isComplexAlignFile()
 +    {
 +      return true;
 +    }
 +
 +  },
 +  Rnaml("RNAML", "xml,rnaml", true, false)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new RnamlFile(inFile, sourceType);
 +    }    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new RnamlFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new RnamlFile();
 +    }
 +
 +  },
 +  Json("JSON","json", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new JSONFile(inFile, sourceType);
 +    }    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new JSONFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new JSONFile();
 +    }
 +
 +    @Override
 +    public boolean isComplexAlignFile()
 +    {
 +      return true;
 +    }
 +
 +  },
 +  Pileup("PileUp", "?", false, false)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new PileUpfile(inFile, sourceType);
 +    }    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new PileUpfile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new PileUpfile();
 +    }
 +
 +  },
 +  MSF("MSF", "msf", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new MSFfile(inFile, sourceType);
 +    }    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new MSFfile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new MSFfile();
 +    }
 +
 +  },
 +  Clustal("CLUSTAL", "aln", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new ClustalFile(inFile, sourceType);
 +    }    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new ClustalFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new ClustalFile();
 +    }
 +  },
 +  Phylip("PHYLIP", "phy", true, true)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new PhylipFile(inFile, sourceType);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new PhylipFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new PhylipFile();
 +    }
 +  },
 +  Jnet("JnetFile", "", false, false)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      JPredFile af = new JPredFile(inFile, sourceType);
 +      af.removeNonSequences();
 +      return af;
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      JPredFile af = new JPredFile(source);
 +      af.removeNonSequences();
 +      return af;
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return null; // todo is this called?
 +    }
 +
 +  },
 +  Features("GFF or Jalview features", "gff2,gff3", false, false)
 +  {
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new FeaturesFile(true, inFile, sourceType);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new FeaturesFile(source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new FeaturesFile();
 +    }
 +  },
 +  PDB("PDB", "", false, false)
 +  {
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      // TODO obtain config value from preference settings.
 +      // Set value to 'true' to test PDB processing with Jmol: JAL-1213
-       boolean isParseWithJMOL = !StructureImportSettings
-               .getCurrentDefaultFormat().equalsIgnoreCase("PDB");
++      boolean isParseWithJMOL = StructureImportSettings
++              .getDefaultStructureFileFormat() != PDBEntry.Type.PDB;
 +      if (isParseWithJMOL)
 +      {
 +        return new JmolParser(
 +                StructureImportSettings.isVisibleChainAnnotation(),
-                 StructureImportSettings.isPredictSecondaryStructure(),
++                StructureImportSettings.isProcessSecondaryStructure(),
 +                StructureImportSettings.isExternalSecondaryStructure(),
 +                inFile,
 +                sourceType);
 +      }
 +      else
 +      {
 +        StructureImportSettings.setShowSeqFeatures(true);
 +        return new MCview.PDBfile(
 +                StructureImportSettings.isVisibleChainAnnotation(),
-                 StructureImportSettings.isPredictSecondaryStructure(),
++                StructureImportSettings.isProcessSecondaryStructure(),
 +                StructureImportSettings.isExternalSecondaryStructure(),
 +                inFile,
 +                sourceType);
 +      }
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
-       boolean isParseWithJMOL = !StructureImportSettings
-               .getCurrentDefaultFormat().equalsIgnoreCase("PDB");
++      boolean isParseWithJMOL = StructureImportSettings
++              .getDefaultStructureFileFormat() != PDBEntry.Type.PDB;
 +      if (isParseWithJMOL)
 +      {
 +        return new JmolParser(
 +                StructureImportSettings.isVisibleChainAnnotation(),
-                 StructureImportSettings.isPredictSecondaryStructure(),
++                StructureImportSettings.isProcessSecondaryStructure(),
 +                StructureImportSettings.isExternalSecondaryStructure(),
 +                source);
 +      }
 +      else
 +      {
 +        StructureImportSettings.setShowSeqFeatures(true);
 +        return new MCview.PDBfile(
 +                StructureImportSettings.isVisibleChainAnnotation(),
-                 StructureImportSettings.isPredictSecondaryStructure(),
++                StructureImportSettings.isProcessSecondaryStructure(),
 +                StructureImportSettings.isExternalSecondaryStructure(),
 +                source);
 +      }
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new JmolParser(); // todo or null?
 +    }
 +  },
 +  MMCif("mmCIF", "cif", false, false)
 +  {
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return new JmolParser(
 +              StructureImportSettings.isVisibleChainAnnotation(),
-               StructureImportSettings.isPredictSecondaryStructure(),
++              StructureImportSettings.isProcessSecondaryStructure(),
 +              StructureImportSettings.isExternalSecondaryStructure(),
 +              inFile, sourceType);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return new JmolParser(
 +              StructureImportSettings.isVisibleChainAnnotation(),
-               StructureImportSettings.isPredictSecondaryStructure(),
++              StructureImportSettings.isProcessSecondaryStructure(),
 +              StructureImportSettings.isExternalSecondaryStructure(),
 +              source);
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return new JmolParser(); // todo or null?
 +    }
 +  },
 +  Jalview("Jalview", "jar,jvp", true, false)
 +  {
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(String inFile,
 +            DataSourceType sourceType) throws IOException
 +    {
 +      return null;
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile(FileParse source)
 +            throws IOException
 +    {
 +      return null;
 +    }
 +
 +    @Override
 +    public AlignmentFileI getAlignmentFile()
 +    {
 +      return null;
 +    }
 +  };
 +
 +  /**
 +   * A lookup map of enums by upper-cased name
 +   */
 +  private static Map<String, FileFormat> names;
 +  static
 +  {
 +    names = new HashMap<String, FileFormat>();
 +    for (FileFormat format : FileFormat.values())
 +    {
 +      names.put(format.toString().toUpperCase(), format);
 +    }
 +  }
 +
 +  private boolean writable;
 +
 +  private boolean readable;
 +
 +  private String extensions;
 +
 +  private String name;
 +
 +  @Override
 +  public boolean isComplexAlignFile()
 +  {
 +    return false;
 +  }
 +
 +  @Override
 +  public String getShortDescription()
 +  {
 +    return toString();
 +  }
 +
 +  /**
 +   * Returns the file format with the given name, or null if format is null or
 +   * invalid. Unlike valueOf(), this is not case-sensitive, to be kind to
 +   * writers of javascript.
 +   * 
 +   * @param format
 +   * @return
 +   */
 +  public static FileFormatI forName(String format)
 +  {
 +    // or could store format.getShortDescription().toUpperCase()
 +    // in order to decouple 'given name' from enum name
 +    return format == null ? null : names.get(format.toUpperCase());
 +  }
 +
 +  @Override
 +  public boolean isReadable()
 +  {
 +    return readable;
 +  }
 +
 +  @Override
 +  public boolean isWritable()
 +  {
 +    return writable;
 +  }
 +
 +  /**
 +   * Constructor
 +   * 
 +   * @param shortName
 +   * @param extensions
 +   *          comma-separated list of file extensions associated with the format
 +   * @param isReadable
 +   * @param isWritable
 +   */
 +  private FileFormat(String shortName, String extensions,
 +          boolean isReadable, boolean isWritable)
 +  {
 +    this.name = shortName;
 +    this.extensions = extensions;
 +    this.readable = isReadable;
 +    this.writable = isWritable;
 +  }
 +
 +  @Override
 +  public String getExtensions()
 +  {
 +    return extensions;
 +  }
 +}
   */
  package jalview.io;
  
++import jalview.bin.Cache;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.SequenceI;
  import jalview.gui.AlignViewport;
  import jalview.gui.AlignmentPanel;
  import jalview.gui.FeatureRenderer;
  import jalview.gui.SequenceRenderer;
++import jalview.util.BrowserLauncher;
++import jalview.util.ImageMaker;
  import jalview.util.MessageManager;
  
  import java.awt.Color;
  import java.awt.Font;
++import java.io.FileWriter;
  import java.io.PrintWriter;
  
  public class HTMLOutput
@@@ -52,9 -52,9 +56,8 @@@
      fr.transferSettings(fr1);
  
      JalviewFileChooser chooser = new JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "html" }, new String[] { "HTML files" },
--            "HTML files");
++            Cache.getProperty("LAST_DIRECTORY"), ImageMaker.HTML_EXTENSION,
++            "HTML files", "HTML files");
  
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager.getString("label.save_as_html"));
      if (value == JalviewFileChooser.APPROVE_OPTION)
      {
        String choice = chooser.getSelectedFile().getPath();
--      jalview.bin.Cache.setProperty("LAST_DIRECTORY", chooser
++      Cache.setProperty("LAST_DIRECTORY", chooser
                .getSelectedFile().getParent());
  
        try
        {
--        PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(
--                choice));
++        PrintWriter out = new PrintWriter(new FileWriter(choice));
          out.println("<HTML>");
          out.println("<style type=\"text/css\">");
          out.println("<!--");
  
          out.println("\n</body>\n</html>");
          out.close();
--        jalview.util.BrowserLauncher.openURL("file:///" + choice);
++        BrowserLauncher.openURL("file:///" + choice);
        } catch (Exception ex)
        {
          ex.printStackTrace();
@@@ -22,6 -22,6 +22,7 @@@ package jalview.io
  
  import jalview.api.AlignExportSettingI;
  import jalview.api.FeatureRenderer;
++import jalview.bin.Cache;
  import jalview.datamodel.AlignmentExportData;
  import jalview.datamodel.SequenceI;
  import jalview.gui.AlignViewport;
@@@ -30,6 -30,6 +31,7 @@@ import jalview.gui.HTMLOptions
  import jalview.gui.IProgressIndicator;
  import jalview.gui.OOMWarning;
  import jalview.math.AlignmentDimension;
++import jalview.util.ImageMaker;
  import jalview.util.MessageManager;
  
  import java.awt.Color;
@@@ -251,11 -252,11 +253,9 @@@ public class HtmlSvgOutpu
  
    static JalviewFileChooser getHTMLChooser()
    {
--    return new jalview.io.JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "html" },
--            new String[] { "Hypertext Markup Language" },
--            "Hypertext Markup Language");
++    return new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"),
++            ImageMaker.HTML_EXTENSION, ImageMaker.HTML_EXTENSION,
++            ImageMaker.HTML_EXTENSION);
    }
  
    public int printUnwrapped(int pwidth, int pheight, int pi, Graphics... pg)
Simple merge
@@@ -31,6 -31,6 +31,9 @@@ import java.awt.HeadlessException
  import java.awt.event.MouseAdapter;
  import java.awt.event.MouseEvent;
  import java.io.File;
++import java.util.ArrayList;
++import java.util.Collections;
++import java.util.List;
  import java.util.StringTokenizer;
  import java.util.Vector;
  
@@@ -41,6 -41,6 +44,7 @@@ import javax.swing.JOptionPane
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.SpringLayout;
++import javax.swing.plaf.basic.BasicFileChooserUI;
  
  /**
   * Enhanced file chooser dialog box.
   */
  public class JalviewFileChooser extends JFileChooser
  {
-   public JalviewFileChooser(String dir)
++  /**
++   * Factory method to return a file chooser that offers readable alignment file
++   * formats
++   * 
++   * @param directory
++   * @param selected
++   * @param selectAll
++   * @return
++   */
++  public static JalviewFileChooser forRead(String directory,
++          String selected, boolean selectAll)
 +  {
-     super(safePath(dir));
-     setAccessory(new RecentlyOpened());
++    List<String> extensions = new ArrayList<String>();
++    List<String> descs = new ArrayList<String>();
++    for (FileFormatI format : FileFormat.values())
++    {
++      if (format.isReadable())
++      {
++        extensions.add(format.getExtensions());
++        descs.add(format.getShortDescription());
++      }
++    }
++    return new JalviewFileChooser(directory,
++            extensions.toArray(new String[extensions.size()]),
++            descs.toArray(new String[descs.size()]),
++            selected);
 +  }
 +
-   private static File safePath(String dir)
++  /**
++   * Factory method to return a file chooser that offers writable alignment file
++   * formats
++   * 
++   * @param directory
++   * @param selected
++   * @param selectAll
++   * @return
++   */
++  public static JalviewFileChooser forWrite(String directory,
++          String selected, boolean selectAll)
 +  {
-     if (dir == null)
++    // TODO in Java 8, forRead and forWrite can be a single method
++    // with a lambda expression parameter for isReadable/isWritable
++    List<String> extensions = new ArrayList<String>();
++    List<String> descs = new ArrayList<String>();
++    for (FileFormatI format : FileFormat.values())
 +    {
-       return null;
++      if (format.isWritable())
++      {
++        extensions.add(format.getExtensions());
++        descs.add(format.getShortDescription());
++      }
 +    }
++    return new JalviewFileChooser(directory,
++            extensions.toArray(new String[extensions.size()]),
++            descs.toArray(new String[descs.size()]), selected);
++  }
 +
-     File f = new File(dir);
-     if (f.getName().indexOf(':') > -1)
-     {
-       return null;
-     }
-     return f;
+   public JalviewFileChooser(String dir)
+   {
+     super(safePath(dir));
+     setAccessory(new RecentlyOpened());
    }
  
-   public JalviewFileChooser(String dir, String[] suffix, String[] desc,
-           String selected, boolean selectAll)
++  public JalviewFileChooser(String dir, String extension, String desc,
++          String selected)
 +  {
 +    super(safePath(dir));
-     init(suffix, desc, selected, selectAll);
++    init(Collections.singletonList(new String[] { extension, desc }),
++            selected);
 +  }
 +
-   public JalviewFileChooser(String dir, String[] suffix, String[] desc,
++  public JalviewFileChooser(String dir, String[] extensions, String[] descs,
 +          String selected)
 +  {
 +    super(safePath(dir));
-     init(suffix, desc, selected, true);
++    if (extensions.length == descs.length)
++    {
++      List<String[]> formats = new ArrayList<String[]>();
++      for (int i = 0; i < extensions.length; i++)
++      {
++        formats.add(new String[] { extensions[i], descs[i] });
++      }
++      init(formats, selected);
++    }
++    else
++    {
++      System.err.println("JalviewFileChooser arguments mismatch: "
++              + extensions + ", " + descs);
++    }
 +  }
 +
-   public JalviewFileChooser(String property, FileFormatI currentFileFormat,
-           boolean b)
+   private static File safePath(String dir)
    {
-     todo write this
-     // TODO Auto-generated constructor stub
+     if (dir == null)
+     {
+       return null;
+     }
+     File f = new File(dir);
+     if (f.getName().indexOf(':') > -1)
+     {
+       return null;
+     }
+     return f;
    }
  
-   void init(String[] suffix, String[] desc, String selected,
-           boolean selectAll)
 -  public JalviewFileChooser(String dir, String[] suffix, String[] desc,
 -          String selected, boolean selectAll)
 -  {
 -    super(safePath(dir));
 -    init(suffix, desc, selected, selectAll);
 -  }
 -
 -  public JalviewFileChooser(String dir, String[] suffix, String[] desc,
 -          String selected)
 -  {
 -    super(safePath(dir));
 -    init(suffix, desc, selected, true);
 -  }
 -
 -  void init(String[] suffix, String[] desc, String selected,
 -          boolean selectAll)
++  /**
++   * 
++   * @param formats
++   *          a list of {extensions, description} for each file format
++   * @param selected
++   */
++  void init(List<String[]> formats, String selected)
    {
  
      JalviewFileFilter chosen = null;
  
      // SelectAllFilter needs to be set first before adding further
      // file filters to fix bug on Mac OSX
--    setAcceptAllFileFilterUsed(selectAll);
++    setAcceptAllFileFilterUsed(true);
  
--    for (int i = 0; i < suffix.length; i++)
++    for (String[] format : formats)
      {
--      JalviewFileFilter jvf = new JalviewFileFilter(suffix[i], desc[i]);
++      JalviewFileFilter jvf = new JalviewFileFilter(format[0], format[1]);
        addChoosableFileFilter(jvf);
--      if ((selected != null) && selected.equalsIgnoreCase(desc[i]))
++      if ((selected != null) && selected.equalsIgnoreCase(format[1]))
        {
          chosen = jvf;
        }
  
      try
      {
--      if (getUI() instanceof javax.swing.plaf.basic.BasicFileChooserUI)
++      if (getUI() instanceof BasicFileChooserUI)
        {
--        final javax.swing.plaf.basic.BasicFileChooserUI ui = (javax.swing.plaf.basic.BasicFileChooserUI) getUI();
--        final String name = ui.getFileName().trim();
++        final BasicFileChooserUI fcui = (BasicFileChooserUI) getUI();
++        final String name = fcui.getFileName().trim();
  
          if ((name == null) || (name.length() == 0))
          {
            @Override
            public void run()
            {
--            String currentName = ui.getFileName();
++            String currentName = fcui.getFileName();
              if ((currentName == null) || (currentName.length() == 0))
              {
--              ui.setFileName(name);
++              fcui.setFileName(name);
              }
            }
          });
      }
    }
  
-   public FileFormat getSelectedFormat()
 -  public String getSelectedFormat()
++  public FileFormatI getSelectedFormat()
    {
      if (getFileFilter() == null)
      {
@@@ -57,10 -58,9 +58,9 @@@ public class MSFfile extends AlignFil
     * @throws IOException
     *           DOCUMENT ME!
     */
-   public MSFfile(String inFile, DataSourceType sourceType)
-           throws IOException
 -  public MSFfile(String inFile, String type) throws IOException
++  public MSFfile(String inFile, DataSourceType type) throws IOException
    {
-     super(inFile, sourceType);
+     super(inFile, type);
    }
  
    public MSFfile(FileParse source) throws IOException
      return check % 10000;
    }
  
+   /**
+    * DOCUMENT ME!
+    * 
+    * @param s
+    *          DOCUMENT ME!
+    * @param is_NA
+    *          DOCUMENT ME!
+    * 
+    * @return DOCUMENT ME!
+    */
 -  public String print(SequenceI[] sqs)
 +  @Override
-   public String print(SequenceI[] sqs, boolean jvsuffix)
++  public String print(SequenceI[] sqs, boolean jvSuffix)
    {
  
      boolean is_NA = Comparison.isNucleotide(sqs);
      while ((i < s.length) && (s[i] != null))
      {
  
-       nameBlock[i] = new String("  Name: " + printId(s[i], jvsuffix) + " ");
 -      nameBlock[i] = new String("  Name: " + printId(s[i]) + " ");
++      nameBlock[i] = new String("  Name: " + printId(s[i], jvSuffix) + " ");
  
        idBlock[i] = new String("Len: "
                + maxLenpad.form(s[i].getSequence().length) + "  Check: "
  
        while ((j < s.length) && (s[j] != null))
        {
-         String name = printId(s[j], jvsuffix);
 -        String name = printId(s[j]);
++        String name = printId(s[j], jvSuffix);
  
          out.append(new Format("%-" + maxid + "s").form(name + " "));
  
Simple merge
@@@ -53,10 -54,9 +54,9 @@@ public class RnamlFile extends AlignFil
  
    }
  
-   public RnamlFile(String inFile, DataSourceType sourceType)
-           throws IOException
 -  public RnamlFile(String inFile, String type) throws IOException
++  public RnamlFile(String inFile, DataSourceType type) throws IOException
    {
-     super(inFile, sourceType);
+     super(inFile, type);
  
    }
  
  
      }
  
-     setSeqs(seqs);
+     setSeqs(sqs);
    }
  
 -  public static String print(SequenceI[] s)
 -  {
 -    return "not yet implemented";
 -  }
 -
    @Override
-   public String print(SequenceI[] sqs, boolean jvsuffix)
 -  public String print()
++  public String print(SequenceI[] s, boolean jvSuffix)
    {
 -    System.out.print("print :");
 -    return print(getSeqsAsArray());
 +    return "not yet implemented";
    }
  
-   public ArrayList getRNA()
+   public List<RNA> getRNA()
    {
      return result;
    }
@@@ -91,10 -97,9 +97,10 @@@ public class StockholmFile extends Alig
      this.al = al;
    }
  
-   public StockholmFile(String inFile, DataSourceType sourceType)
 -  public StockholmFile(String inFile, String type) throws IOException
++  public StockholmFile(String inFile, DataSourceType type)
 +          throws IOException
    {
-     super(inFile, sourceType);
+     super(inFile, type);
    }
  
    public StockholmFile(FileParse source) throws IOException
      return annot;
    }
  
 -  public String print(SequenceI[] s)
 +  @Override
-   public String print(SequenceI[] s, boolean jvsuffix)
++  public String print(SequenceI[] s, boolean jvSuffix)
    {
-     // out.append("# STOCKHOLM 1.0");
-     // out.append(newline);
++    out = new StringBuffer();
++    out.append("# STOCKHOLM 1.0");
++    out.append(newline);
 +
      // find max length of id
      int max = 0;
      int maxid = 0;
      Hashtable dataRef = null;
      while ((in < s.length) && (s[in] != null))
      {
-       String tmp = printId(s[in], jvsuffix);
 -      String tmp = printId(s[in]);
++      String tmp = printId(s[in], jvSuffix);
        if (s[in].getSequence().length > max)
        {
          max = s[in].getSequence().length;
  
              // out.append("#=GR ");
              out.append(new Format("%-" + maxid + "s").form("#=GR "
-                     + printId(s[i], jvsuffix) + " " + key + " "));
 -                    + printId(s[i]) + " " + key + " "));
++                    + printId(s[i], jvSuffix) + " " + key + " "));
              ann = alAnot[j].annotations;
              boolean isrna = alAnot[j].isValidStruc();
              String seq = "";
          }
        }
  
 -      out.append(new Format("%-" + maxid + "s").form(printId(s[i]) + " "));
 +      out.append(new Format("%-" + maxid + "s")
-               .form(printId(s[i], jvsuffix) + " "));
++              .form(printId(s[i], jvSuffix) + " "));
        out.append(s[i].getSequenceAsString());
        out.append(newline);
        i++;
          out.append(newline);
        }
      }
-     // out.append("//");
-     // out.append(newline);
++
++    out.append("//");
++    out.append(newline);
++
      return out.toString();
    }
  
      return seq;
    }
  
 -  @Override
+   public String print()
+   {
+     out = new StringBuffer();
+     out.append("# STOCKHOLM 1.0");
+     out.append(newline);
 -    print(getSeqsAsArray());
++    print(getSeqsAsArray(), false);
+     out.append("//");
+     out.append(newline);
+     return out.toString();
+   }
    private static Hashtable typeIds = null;
    static
    {
      if (typeIds == null)
Simple merge
@@@ -21,6 -21,6 +21,8 @@@
  package jalview.jbgui;
  
  import jalview.datamodel.AlignmentI;
++import jalview.io.DataSourceType;
++import jalview.io.FileFormat;
  import jalview.io.FormatAdapter;
  import jalview.util.MessageManager;
  
@@@ -99,6 -99,6 +101,7 @@@ public class GFinder extends JPane
      findAll.setText(MessageManager.getString("action.find_all"));
      findAll.addActionListener(new java.awt.event.ActionListener()
      {
++      @Override
        public void actionPerformed(ActionEvent e)
        {
          findAll_actionPerformed(e);
      findNext.setText(MessageManager.getString("action.find_next"));
      findNext.addActionListener(new java.awt.event.ActionListener()
      {
++      @Override
        public void actionPerformed(ActionEvent e)
        {
          findNext_actionPerformed(e);
      createNewGroup.setText(MessageManager.getString("label.new_feature"));
      createNewGroup.addActionListener(new java.awt.event.ActionListener()
      {
++      @Override
        public void actionPerformed(ActionEvent e)
        {
          createNewGroup_actionPerformed(e);
      textfield.setLineWrap(true);
      textfield.addCaretListener(new CaretListener()
      {
++      @Override
        public void caretUpdate(CaretEvent e)
        {
          textfield_caretUpdate(e);
      });
      textfield.addKeyListener(new java.awt.event.KeyAdapter()
      {
++      @Override
        public void keyPressed(KeyEvent e)
        {
          textfield_keyPressed(e);
      {
        SwingUtilities.invokeLater(new Runnable()
        {
++        @Override
          public void run()
          {
            String str = textfield.getText();
            AlignmentI al = null;
            try
            {
--            al = new FormatAdapter().readFile(str, "Paste", "FASTA");
++            al = new FormatAdapter().readFile(str, DataSourceType.PASTE,
++                    FileFormat.Fasta);
            } catch (Exception ex)
            {
            }
@@@ -80,24 -101,33 +101,33 @@@ public class StructureImportSetting
      StructureImportSettings.showSeqFeatures = showSeqFeatures;
    }
  
-   public static String getCurrentDefaultFormat()
 -  public static String getDefaultStructureFileFormat()
++  public static PDBEntry.Type getDefaultStructureFileFormat()
+   {
 -    return defaultStructureFileFormat.toString();
++    return defaultStructureFileFormat;
+   }
+   public static void setDefaultStructureFileFormat(
+           String defaultStructureFileFormat)
    {
-     return currentDefaultFormat;
+     StructureImportSettings.defaultStructureFileFormat = PDBEntry.Type
+             .valueOf(defaultStructureFileFormat.toUpperCase());
    }
  
-   public static void setCurrentDefaultFormat(String currentDefaultFormat)
+   public static String getDefaultPDBFileParser()
    {
-     StructureImportSettings.currentDefaultFormat = currentDefaultFormat;
+     return defaultPDBFileParser.toString();
    }
  
-   public static boolean isProcessHETATMs()
+   public static void setDefaultPDBFileParser(
+           StructureParser defaultPDBFileParser)
    {
-     return processHETATMs;
+     StructureImportSettings.defaultPDBFileParser = defaultPDBFileParser;
    }
  
-   public static void setProcessHETATMs(boolean processHETATMs)
+   public static void setDefaultPDBFileParser(String defaultPDBFileParser)
    {
-     StructureImportSettings.processHETATMs = processHETATMs;
+     StructureImportSettings.defaultPDBFileParser = StructureParser
+             .valueOf(defaultPDBFileParser.toUpperCase());
    }
  
  }
@@@ -386,10 -385,14 +386,14 @@@ public class StructureSelectionManage
      try
      {
  
-       if (pdbFile != null && isCIFFile(pdbFile))
+       boolean isParseWithJMOL = StructureImportSettings
+               .getDefaultPDBFileParser().equalsIgnoreCase(
+                       StructureImportSettings.StructureParser.JMOL_PARSER
+                               .toString());
+       if (isParseWithJMOL || (pdbFile != null && isCIFFile(pdbFile)))
        {
 -        pdb = new jalview.ext.jmol.JmolParser(addTempFacAnnot, parseSecStr,
 -                secStructServices, pdbFile, protocol);
 +        pdb = new JmolParser(addTempFacAnnot, parseSecStr,
 +                secStructServices, pdbFile, sourceType);
        }
        else
        {
@@@ -20,6 -20,6 +20,7 @@@
   */
  package jalview.util;
  
++import jalview.bin.Cache;
  import jalview.bin.Jalview;
  import jalview.gui.EPSOptions;
  import jalview.gui.IProgressIndicator;
@@@ -42,6 -42,6 +43,22 @@@ import org.jibble.epsgraphics.EpsGraphi
  
  public class ImageMaker
  {
++  public static final String SVG_DESCRIPTION = "Scalable Vector Graphics";
++
++  public static final String SVG_EXTENSION = "svg";
++
++  public static final String EPS_DESCRIPTION = "Encapsulated Postscript";
++
++  public static final String EPS_EXTENSION = "eps";
++
++  public static final String PNG_EXTENSION = "png";
++
++  public static final String PNG_DESCRIPTION = "Portable  network graphics";
++
++  public static final String HTML_EXTENSION = "html";
++
++  public static final String HTML_DESCRIPTION = "Hypertext Markup Language";
++
    EpsGraphics2D pg;
  
    SVGGraphics2D g2;
          out.close();
          break;
        case PNG:
--        ImageIO.write(bi, "png", out);
++        ImageIO.write(bi, PNG_EXTENSION, out);
          out.flush();
          out.close();
          break;
      {
        return null;
      }
--    return new jalview.io.JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "png" },
--            new String[] { "Portable network graphics" },
--            "Portable network graphics");
++    return new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"),
++            PNG_EXTENSION, PNG_DESCRIPTION, PNG_DESCRIPTION);
    }
  
    static JalviewFileChooser getEPSChooser()
      {
        return null;
      }
--    return new jalview.io.JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "eps" },
--            new String[] { "Encapsulated Postscript" },
--            "Encapsulated Postscript");
++    return new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"),
++            EPS_EXTENSION, EPS_DESCRIPTION, EPS_DESCRIPTION);
    }
  
    private void setProgressMessage(String message)
      {
        return null;
      }
--    return new jalview.io.JalviewFileChooser(
--            jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
--            new String[] { "svg" },
--            new String[] { "Scalable Vector Graphics" },
--            "Scalable Vector Graphics");
++    return new JalviewFileChooser(Cache.getProperty("LAST_DIRECTORY"),
++            SVG_EXTENSION, SVG_DESCRIPTION, SVG_DESCRIPTION);
    }
  }
@@@ -27,7 -27,8 +27,11 @@@ import jalview.datamodel.AlignmentI
  import jalview.datamodel.DBRefEntry;
  import jalview.datamodel.DBRefSource;
  import jalview.datamodel.PDBEntry;
+ import jalview.datamodel.PDBEntry.Type;
  import jalview.datamodel.SequenceI;
++import jalview.io.DataSourceType;
++import jalview.io.FileFormat;
++import jalview.io.FileFormatI;
  import jalview.io.FormatAdapter;
  import jalview.io.PDBFeatureSettings;
  import jalview.structure.StructureImportSettings;
@@@ -132,13 -133,12 +136,11 @@@ public class Pdb extends EbiFileRetriev
        stopQuery();
        return null;
      }
-     String ext = StructureImportSettings.getCurrentDefaultFormat()
-             .equalsIgnoreCase("mmcif") ? ".cif"
-             : ".xml";
 -    String ext = StructureImportSettings.getDefaultStructureFileFormat()
 -            .equalsIgnoreCase(Type.MMCIF.toString()) ? ".cif" : ".xml";
++    Type pdbFileFormat = StructureImportSettings
++            .getDefaultStructureFileFormat();
++    String ext = "." + pdbFileFormat.getExtension();
      EBIFetchClient ebi = new EBIFetchClient();
--    file = ebi.fetchDataAsFile("pdb:" + id,
-             StructureImportSettings.getCurrentDefaultFormat().toLowerCase(),
-             ext)
 -            StructureImportSettings.getDefaultStructureFileFormat().toLowerCase(),
 -            ext)
++    file = ebi.fetchDataAsFile("pdb:" + id, pdbFileFormat.getFormat(), ext)
              .getAbsolutePath();
      stopQuery();
      if (file == null)
      }
      try
      {
--
++      // convert Type.PDB/MMCIF to FileFormat.PDB/MMCIF
++      // todo get rid of Type?
++      FileFormatI fileFormat = FileFormat.valueOf(pdbFileFormat.toString());
        pdbAlignment = new FormatAdapter().readFile(file,
-               jalview.io.DataSourceType.FILE,
-               StructureImportSettings.getCurrentDefaultFormat());
 -              jalview.io.AppletFormatAdapter.FILE,
 -              StructureImportSettings.getDefaultStructureFileFormat());
++              DataSourceType.FILE, fileFormat);
        if (pdbAlignment != null)
        {
          List<SequenceI> toremove = new ArrayList<SequenceI>();
@@@ -21,6 -21,6 +21,7 @@@
  package jalview.ws.jws1;
  
  import jalview.datamodel.AlignmentI;
++import jalview.io.FileFormat;
  import jalview.io.FileParse;
  import jalview.io.FormatAdapter;
  import jalview.io.InputStreamParser;
@@@ -86,7 -86,7 +87,8 @@@ public class Annotate3
        while (r.hasNext())
        {
          FileParse fp = new InputStreamParser(r.next(), source.getDataName());
--        AlignmentI nal = new FormatAdapter().readFromFile(fp, "RNAML");
++        AlignmentI nal = new FormatAdapter().readFromFile(fp,
++                FileFormat.Rnaml);
          if (al == null)
          {
            al = nal;
@@@ -364,8 -355,8 +364,8 @@@ class JPredThread extends JWS1Thread im
          if (msf.length > 1)
          {
            msa = new vamsas.objects.simple.Msfalignment();
 -          jalview.io.PileUpfile pileup = new jalview.io.PileUpfile();
 -          msa.setMsf(pileup.print(msf));
 +          PileUpfile pileup = new PileUpfile();
-           msa.setMsf(pileup.print(msf));
++          msa.setMsf(pileup.print(msf, true));
          }
        }
      }
@@@ -148,9 -147,9 +148,9 @@@ public class Alignment extends InputTyp
  
      if (tok.startsWith("format"))
      {
--      for (String fmt : jalview.io.FormatAdapter.WRITEABLE_FORMATS)
++      for (FileFormatI fmt : FileFormat.values())
        {
--        if (val.equalsIgnoreCase(fmt))
++        if (fmt.isWritable() && val.equalsIgnoreCase(fmt.toString()))
          {
            format = fmt;
            return true;
        }
        warnings.append("Invalid alignment format '" + val
                + "'. Must be one of (");
--      for (String fmt : jalview.io.FormatAdapter.WRITEABLE_FORMATS)
++      for (FileFormatI fmt : FileFormat.values())
        {
--        warnings.append(" " + fmt);
++        if (fmt.isWritable())
++        {
++          warnings.append(" " + fmt).toString();
++        }
        }
        warnings.append(")\n");
      }
              "Append jalview style /start-end suffix to ID", false, false,
              writeAsFile, null));
  
--    lst.add(new Option("format", "Alignment upload format", true, "FASTA",
--            format, Arrays
++    lst.add(new Option("format", "Alignment upload format", true,
++            FileFormat.Fasta.toString(),
++ format.toString(), Arrays
                      .asList(jalview.io.FormatAdapter.WRITEABLE_FORMATS),
              null));
      lst.add(createMolTypeOption("type", "Sequence type", false, type, null));
@@@ -29,10 -29,9 +29,11 @@@ import jalview.datamodel.AlignedCodon
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
+ import jalview.datamodel.Sequence;
  import jalview.datamodel.SequenceI;
  import jalview.gui.AlignViewport;
 +import jalview.io.DataSourceType;
 +import jalview.io.FileFormat;
  import jalview.io.FormatAdapter;
  
  import java.io.IOException;
@@@ -222,4 -219,65 +222,65 @@@ public class AlignmentAnnotationTest
      assertEquals(1, ann.annotations[1].value, 0.001);
      assertEquals(2, ann.annotations[2].value, 0.001);
    }
+   /**
+    * Test the method that defaults rna symbol to the one matching the preceding
+    * unmatched opening bracket (if any)
+    */
+   @Test(groups = { "Functional" })
+   public void testGetDefaultRnaHelixSymbol()
+   {
+     AlignmentAnnotation ann = new AlignmentAnnotation("SS",
+             "secondary structure", null);
+     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+     Annotation[] anns = new Annotation[20];
+     ann.annotations = anns;
+     assertEquals("(", ann.getDefaultRnaHelixSymbol(4));
+     anns[1] = new Annotation("(", "S", '(', 0f);
+     assertEquals("(", ann.getDefaultRnaHelixSymbol(0));
+     assertEquals("(", ann.getDefaultRnaHelixSymbol(1));
+     assertEquals(")", ann.getDefaultRnaHelixSymbol(2));
+     assertEquals(")", ann.getDefaultRnaHelixSymbol(3));
+     /*
+      * .(.[.{.<.}.>.).].
+      */
+     anns[1] = new Annotation("(", "S", '(', 0f);
+     anns[3] = new Annotation("[", "S", '[', 0f);
+     anns[5] = new Annotation("{", "S", '{', 0f);
+     anns[7] = new Annotation("<", "S", '<', 0f);
+     anns[9] = new Annotation("}", "S", '}', 0f);
+     anns[11] = new Annotation(">", "S", '>', 0f);
+     anns[13] = new Annotation(")", "S", ')', 0f);
+     anns[15] = new Annotation("]", "S", ']', 0f);
+     String expected = "(())]]}}>>>>]]]](";
+     for (int i = 0; i < expected.length(); i++)
+     {
+       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+               ann.getDefaultRnaHelixSymbol(i));
+     }
+     /*
+      * .(.[.(.).{.}.<.].D.
+      */
+     anns[1] = new Annotation("(", "S", '(', 0f);
+     anns[3] = new Annotation("[", "S", '[', 0f);
+     anns[5] = new Annotation("(", "S", '(', 0f);
+     anns[7] = new Annotation(")", "S", ')', 0f);
+     anns[9] = new Annotation("{", "S", '{', 0f);
+     anns[11] = new Annotation("}", "S", '}', 0f);
+     anns[13] = new Annotation("<", "S", '>', 0f);
+     anns[15] = new Annotation("]", "S", ']', 0f);
+     anns[17] = new Annotation("D", "S", 'D', 0f);
+     expected = "(())]]))]]}}]]>>>>dd";
+     for (int i = 0; i < expected.length(); i++)
+     {
+       assertEquals("column " + i, String.valueOf(expected.charAt(i)),
+               ann.getDefaultRnaHelixSymbol(i));
+     }
+   }
 -}
 +}
@@@ -28,10 -28,10 +28,10 @@@ import jalview.datamodel.Alignment
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.SequenceI;
  import jalview.gui.AlignFrame;
--import jalview.io.AppletFormatAdapter;
 +import jalview.io.DataSourceType;
  import jalview.io.FileLoader;
  import jalview.structure.StructureImportSettings;
+ import jalview.structure.StructureImportSettings.StructureParser;
  
  import java.util.Vector;
  
@@@ -98,8 -101,8 +101,7 @@@ public class JmolParserTes
      for (String f : testFile)
      {
        FileLoader fl = new jalview.io.FileLoader(false);
--      AlignFrame af = fl
-               .LoadFileWaitTillLoaded(f, DataSourceType.FILE);
 -              .LoadFileWaitTillLoaded(f, AppletFormatAdapter.FILE);
++      AlignFrame af = fl.LoadFileWaitTillLoaded(f, DataSourceType.FILE);
        validateSecStrRows(af.getViewport().getAlignment());
      }
    }
      for (String pdbStr : testFile)
      {
        PDBfile mctest = new PDBfile(false, false, false, pdbStr,
 -              AppletFormatAdapter.FILE);
 +              DataSourceType.FILE);
        JmolParser jtest = new JmolParser(false, false, false, pdbStr,
-               jalview.io.DataSourceType.FILE);
-       Vector<SequenceI> seqs = jtest.getSeqs(), mcseqs = mctest.getSeqs();
-       assertTrue(
-               "No sequences extracted from testfile\n"
-                       + (jtest.hasWarningMessage() ? jtest.getWarningMessage()
-                               : "(No warnings raised)"), seqs != null
-                       && seqs.size() > 0);
-       for (SequenceI sq : seqs)
-       {
-         assertEquals("JMol didn't process " + pdbStr
-                 + " to the same sequence as MCView",
-                 sq.getSequenceAsString(), mcseqs.remove(0)
-                         .getSequenceAsString());
-         AlignmentI al = new Alignment(new SequenceI[] { sq });
-         validateSecStrRows(al);
-       }
-     }
-     StructureImportSettings.setProcessHETATMs(true);
-     for (String pdbStr : testFile)
-     {
-       PDBfile mctest = new PDBfile(false, false, false, pdbStr,
 -              jalview.io.AppletFormatAdapter.FILE);
 +              DataSourceType.FILE);
-       JmolParser jtest = new JmolParser(false, false, false, pdbStr,
-               jalview.io.DataSourceType.FILE);
        Vector<SequenceI> seqs = jtest.getSeqs(), mcseqs = mctest.getSeqs();
  
        assertTrue(
    public void testParse_missingResidues() throws Exception
    {
      PDBfile mctest = new PDBfile(false, false, false,
--            pastePDBDataWithChainBreak,
-             DataSourceType.PASTE);
 -            AppletFormatAdapter.PASTE);
++            pastePDBDataWithChainBreak, DataSourceType.PASTE);
      boolean annotFromStructure = false;
      boolean localSecondaryStruct = false;
      boolean serviceSecondaryStruct = false;
      JmolParser jtest = new JmolParser(annotFromStructure,
              localSecondaryStruct, serviceSecondaryStruct,
--            pastePDBDataWithChainBreak,
-             jalview.io.DataSourceType.PASTE);
 -            jalview.io.AppletFormatAdapter.PASTE);
++            pastePDBDataWithChainBreak, DataSourceType.PASTE);
      Vector<SequenceI> seqs = jtest.getSeqs();
      Vector<SequenceI> mcseqs = mctest.getSeqs();
  
      boolean serviceSecondaryStruct = false;
      JmolParser jtest = new JmolParser(annotFromStructure,
              localSecondaryStruct, serviceSecondaryStruct, pdbWithAltLoc,
-             jalview.io.DataSourceType.PASTE);
 -            jalview.io.AppletFormatAdapter.PASTE);
++            DataSourceType.PASTE);
      Vector<SequenceI> seqs = jtest.getSeqs();
      Vector<SequenceI> mcseqs = mctest.getSeqs();
    
index 0000000,8a89830..01b4adf
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,102 +1,102 @@@
+ package jalview.ext.jmol;
+ import jalview.datamodel.SequenceI;
 -import jalview.io.AppletFormatAdapter;
++import jalview.io.DataSourceType;
+ import java.io.File;
+ import java.io.IOException;
+ import java.util.HashSet;
+ import java.util.Set;
+ import java.util.Vector;
+ import MCview.PDBfile;
+ /**
+  * This is not a unit test, rather it is a bulk End-to-End scan for sequences
+  * consistency for PDB files parsed with JmolParser vs. Jalview's PDBfile
+  * parser. The directory of PDB files to test must be provided in the launch
+  * args.
+  * 
+  * @author tcnofoegbu
+  *
+  */
+ public class JmolVsJalviewPDBParserEndToEndTest
+ {
+   public static void main(String[] args)
+   {
+     if (args == null || args[0] == null)
+     {
+       System.err
+               .println("You must provide a PDB directory in the launch argument");
+       return;
+     }
+     // args[0] must provide the directory of PDB files to run the test with
+     String testDir = args[0];
+     System.out.println("PDB directory : " + testDir);
+     File pdbDir = new File(testDir);
+     String testFiles[] = pdbDir.list();
+     testFileParser(testDir, testFiles);
+   }
+   public static void testFileParser(String testDir, String[] testFiles)
+   {
+     Set<String> failedFiles = new HashSet<String>();
+     int totalSeqScanned = 0, totalFail = 0;
+     for (String pdbStr : testFiles)
+     {
+       String testFile = testDir + "/" + pdbStr;
+       PDBfile mctest = null;
+       JmolParser jtest = null;
+       try
+       {
+         mctest = new PDBfile(false, false, false, testFile,
 -                AppletFormatAdapter.FILE);
++                DataSourceType.FILE);
+         jtest = new JmolParser(false, false, false, testFile,
 -                jalview.io.AppletFormatAdapter.FILE);
++                DataSourceType.FILE);
+       } catch (IOException e)
+       {
+         System.err.println("Exception thrown while parsing : " + pdbStr);
+       }
+       Vector<SequenceI> seqs = jtest.getSeqs();
+       Vector<SequenceI> mcseqs = mctest.getSeqs();
+       for (SequenceI sq : seqs)
+       {
+         try
+         {
+         String testSeq = mcseqs.remove(0).getSequenceAsString();
+           if (!sq.getSequenceAsString().equals(testSeq))
+         {
+           ++totalFail;
+             System.err.println("Test Failed for " + pdbStr + ". Diff:");
+           System.err.println(sq.getSequenceAsString());
+           System.err.println(testSeq);
+           failedFiles.add(pdbStr);
+         }
+           ++totalSeqScanned;
+         } catch (Exception e)
+         {
+           e.printStackTrace();
+         }
+       }
+     }
+     int count = 0;
+     System.out.println("\n\nTotal sequence Scanned : " + totalSeqScanned);
+     System.out.println("Total sequence passed : "
+             + (totalSeqScanned - totalFail));
+     System.out.println("Total sequence failed : " + totalFail);
+     System.out
+             .println("Success rate: "
+                     + ((totalSeqScanned - totalFail) * 100)
+                     / totalSeqScanned + "%");
+     System.out.println("\nList of " + failedFiles.size()
+             + " file(s) with sequence diffs:");
+     for (String problemFile : failedFiles)
+     {
+       System.out.println(++count + ". " + problemFile);
+     }
+   }
+ }
@@@ -33,9 -33,10 +33,10 @@@ import jalview.datamodel.PDBEntry
  import jalview.datamodel.PDBEntry.Type;
  import jalview.datamodel.Sequence;
  import jalview.datamodel.SequenceI;
 +import jalview.io.DataSourceType;
  import jalview.io.FileLoader;
 -import jalview.io.FormatAdapter;
  import jalview.structure.StructureSelectionManager;
+ import jalview.util.MapList;
  
  import java.util.ArrayList;
  import java.util.List;
@@@ -131,10 -132,15 +132,15 @@@ public class AlignViewportTes
       * alignment with reference to mappings
       */
      AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
 -            ">Seq1\nCAGT\n", FormatAdapter.PASTE);
 +            ">Seq1\nCAGT\n", DataSourceType.PASTE);
  
+     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
      AlignedCodonFrame acf1 = new AlignedCodonFrame();
+     acf1.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 1, 4 },
+             1, 1));
      AlignedCodonFrame acf2 = new AlignedCodonFrame();
+     acf2.addMap(s1, s1, new MapList(new int[] { 1, 4 }, new int[] { 4, 1 },
+             1, 1));
  
      List<AlignedCodonFrame> mappings = new ArrayList<AlignedCodonFrame>();
      mappings.add(acf1);
      ssm.resetAll();
  
      AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
 -            ">Seq1\nRSVQ\n", FormatAdapter.PASTE);
 +            ">Seq1\nRSVQ\n", DataSourceType.PASTE);
      AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
 -            ">Seq2\nDGEL\n", FormatAdapter.PASTE);
 +            ">Seq2\nDGEL\n", DataSourceType.PASTE);
+     SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
+     SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
+     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
+     SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
+     // need to be distinct
      AlignedCodonFrame acf1 = new AlignedCodonFrame();
+     acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
+             new int[] { 1, 12 }, 1, 3));
      AlignedCodonFrame acf2 = new AlignedCodonFrame();
+     acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
+             new int[] { 1, 12 }, 1, 3));
      AlignedCodonFrame acf3 = new AlignedCodonFrame();
+     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
+         12 }, 1, 1));
  
      List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
      mappings1.add(acf1);
      ssm.resetAll();
  
      AlignFrame af1 = new FileLoader().LoadFileWaitTillLoaded(
 -            ">Seq1\nRSVQ\n", FormatAdapter.PASTE);
 +            ">Seq1\nRSVQ\n", DataSourceType.PASTE);
      AlignFrame af2 = new FileLoader().LoadFileWaitTillLoaded(
 -            ">Seq2\nDGEL\n", FormatAdapter.PASTE);
 +            ">Seq2\nDGEL\n", DataSourceType.PASTE);
+     SequenceI cs1 = new Sequence("cseq1", "CCCGGGTTTAAA");
+     SequenceI cs2 = new Sequence("cseq2", "CTTGAGTCTAGA");
+     SequenceI s1 = af1.getViewport().getAlignment().getSequenceAt(0);
+     SequenceI s2 = af2.getViewport().getAlignment().getSequenceAt(0);
+     // need to be distinct
      AlignedCodonFrame acf1 = new AlignedCodonFrame();
+     acf1.addMap(cs1, s1, new MapList(new int[] { 1, 4 },
+             new int[] { 1, 12 }, 1, 3));
      AlignedCodonFrame acf2 = new AlignedCodonFrame();
+     acf2.addMap(cs2, s2, new MapList(new int[] { 1, 4 },
+             new int[] { 1, 12 }, 1, 3));
      AlignedCodonFrame acf3 = new AlignedCodonFrame();
+     acf3.addMap(cs2, cs2, new MapList(new int[] { 1, 12 }, new int[] { 1,
+         12 }, 1, 1));
  
      List<AlignedCodonFrame> mappings1 = new ArrayList<AlignedCodonFrame>();
      mappings1.add(acf1);
index 0000000,81e336e..6bf954a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,138 +1,135 @@@
+ package jalview.io;
+ import static org.testng.AssertJUnit.assertEquals;
+ import static org.testng.AssertJUnit.assertNotNull;
+ import static org.testng.AssertJUnit.fail;
+ import jalview.datamodel.AlignmentI;
+ import jalview.datamodel.SequenceI;
+ import java.io.IOException;
+ import java.util.ArrayList;
 -import java.util.Arrays;
+ import java.util.List;
+ import org.testng.annotations.DataProvider;
+ import org.testng.annotations.Test;
+ public class FormatAdapterTest
+ {
+   /**
+    * Test saving and re-reading in a specified format
+    * 
+    * @throws IOException
+    */
+   @Test(groups = { "Functional" }, dataProvider = "formats")
 -  public void testRoundTrip(String format) throws IOException
++  public void testRoundTrip(FileFormatI format) throws IOException
+   {
+     try
+     {
+       AlignmentI al = new FormatAdapter().readFile("examples/uniref50.fa",
 -              FormatAdapter.FILE, "FASTA");
++              DataSourceType.FILE, FileFormat.Fasta);
+       /*
+        * 'gap' is the gap character used in the alignment data file here,
+        * not the user preferred gap character
+        */
+       char gap = al.getGapCharacter();
+       assertNotNull(al);
+       SequenceI[] seqs = al.getSequencesArray();
+       String formatted = new FormatAdapter().formatSequences(format, al,
+               false);
+       AlignmentI reloaded = new FormatAdapter().readFile(formatted,
 -              FormatAdapter.PASTE, format);
++              DataSourceType.PASTE, format);
+       List<SequenceI> reread = reloaded.getSequences();
+       assertEquals("Wrong number of reloaded sequences", seqs.length,
+               reread.size());
+       int i = 0;
+       for (SequenceI seq : reread)
+       {
+         String sequenceString = seq.getSequenceAsString();
+         /*
+          * special case: MSF always uses '.' as gap character
+          */
+         sequenceString = adjustForGapTreatment(sequenceString, gap, format);
+         assertEquals(
+                 String.format("Sequence %d: %s", i,
+                         seqs[i].getName()), seqs[i].getSequenceAsString(),
+                 sequenceString);
+         i++;
+       }
+     } catch (IOException e)
+     {
+       fail(String
+               .format("Format %s failed with %s", format, e.getMessage()));
+     }
+   }
+   /**
+    * Optionally change the gap character in the string to the given character,
+    * depending on the sequence file format
+    * 
+    * @param sequenceString
+    *          a sequence (as written in 'format' format)
+    * @param gap
+    *          the sequence's original gap character
+    * @param format
+    * @return
+    */
+   String adjustForGapTreatment(String sequenceString, char gap,
 -          String format)
++          FileFormatI format)
+   {
 -    if ("MSF".equals(format))
++    if (format == FileFormat.MSF)
+     {
+       /*
+        * MSF forces gap character to '.', so change it back
+        * for comparison purposes
+        */
+       sequenceString = sequenceString.replace('.', gap);
+     }
+     return sequenceString;
+   }
+   /**
+    * Data provider that serves alignment formats that are both readable and
+    * writable
+    * 
+    * @return
+    */
+   @DataProvider(name = "formats")
+   static Object[][] getFormats()
+   {
 -    List<String> both = new ArrayList<String>();
 -    String[] readable = FormatAdapter.READABLE_FORMATS;
 -    List<String> writeable = Arrays.asList(FormatAdapter.WRITEABLE_FORMATS);
 -    for (String r : readable)
++    List<FileFormatI> both = new ArrayList<FileFormatI>();
++    for (FileFormat format : FileFormat.values())
+     {
 -      if (writeable.contains(r))
++      if (format.isReadable() && format.isWritable())
+       {
 -        both.add(r);
++        both.add(format);
+       }
+     }
+     Object[][] formats = new Object[both.size()][];
+     int i = 0;
 -    for (String format : both)
++    for (FileFormatI format : both)
+     {
+       formats[i] = new Object[] { format };
+       i++;
+     }
+     return formats;
+   }
+   /**
+    * Enable this to isolate testing to a single file format
+    * 
+    * @throws IOException
+    */
+   @Test(groups = { "Functional" }, enabled = false)
+   public void testOneFormatRoundTrip() throws IOException
+   {
 -    testRoundTrip("JSON");
++    testRoundTrip(FileFormat.Json);
+   }
+ }
@@@ -270,12 -286,13 +286,13 @@@ public class Jalview2xmlTest
    @Test(groups = { "Functional" })
    public void viewRefPdbAnnotation() throws Exception
    {
-     Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
-             Boolean.TRUE.toString());
-     Cache.applicationProperties.setProperty("ADD_SS_ANN",
-             Boolean.TRUE.toString());
+     // TODO: Make this pass without setting StructureParser.JALVIEW_PARSER
+     // StructureImportSettings
+     // .setDefaultPDBFileParser(StructureParser.JALVIEW_PARSER);
+     StructureImportSettings.setProcessSecondaryStructure(true);
+     StructureImportSettings.setVisibleChainAnnotation(true);
      AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
 -            "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
 +            "examples/exampleFile_2_7.jar", DataSourceType.FILE);
      assertTrue("Didn't read in the example file correctly.", af != null);
      AlignmentViewPanel sps = null;
      for (AlignmentViewPanel ap : af.alignPanel.alignFrame.getAlignPanels())
    @Test(groups = { "Functional" }, enabled = true)
    public void testStoreAndRecoverExpandedviews() throws Exception
    {
+     Desktop.instance.closeAll_actionPerformed(null);
      AlignFrame af = new jalview.io.FileLoader().LoadFileWaitTillLoaded(
 -            "examples/exampleFile_2_7.jar", FormatAdapter.FILE);
 +            "examples/exampleFile_2_7.jar", DataSourceType.FILE);
      assertTrue("Didn't read in the example file correctly.", af != null);
+     Assert.assertEquals(Desktop.getAlignFrames().length, 1);
      String afid = af.getViewport().getSequenceSetId();
-     {
-       final AlignFrame xaf = af;
-       af = null;
-       new Thread(new Runnable()
-       {
-         @Override
-         public void run()
-         {
-           Desktop.instance.explodeViews(xaf);
-         }
-       }).start();
-       Thread.sleep(1000);
-     }
-     // int times = 0;
-     // while (++times < 5 && Desktop.getAlignFrames().length < )
-     // {
-     // Thread.sleep(300);
-     // }
+     // check FileLoader returned a reference to the one alignFrame that is
+     // actually on the Desktop
+     assertTrue(
+             "Jalview2XML.loadAlignFrame() didn't return correct AlignFrame reference for multiple view window",
+             af == Desktop.getAlignFrameFor(af.getViewport()));
+     Desktop.explodeViews(af);
      int oldviews = Desktop.getAlignFrames().length;
      Assert.assertEquals(Desktop.getAlignFrames().length,
              Desktop.getAlignmentPanels(afid).length);
                hidden.size(), hs.getSize());
      }
    }
+   /**
+    * Test save and reload of PDBEntry in Jalview project
+    * 
+    * @throws Exception
+    */
+   @Test(groups = { "Functional" })
+   public void testStoreAndRecoverPDBEntry() throws Exception
+   {
+     Desktop.instance.closeAll_actionPerformed(null);
+     String exampleFile = "examples/3W5V.pdb";
+     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(exampleFile,
 -            FormatAdapter.FILE);
++            DataSourceType.FILE);
+     assertTrue("Didn't read in the example file correctly.", af != null);
+     String afid = af.getViewport().getSequenceSetId();
+     AlignmentPanel[] alignPanels = Desktop.getAlignmentPanels(afid);
+     System.out.println();
+     AlignmentViewPanel ap = alignPanels[0];
+     String tfileBase = new File(".").getAbsolutePath().replace(".", "");
+     String testFile = tfileBase + exampleFile;
+     AlignmentI alignment = ap.getAlignment();
+     System.out.println("blah");
+     SequenceI[] seqs = alignment.getSequencesArray();
+     Assert.assertNotNull(seqs[0]);
+     Assert.assertNotNull(seqs[1]);
+     Assert.assertNotNull(seqs[2]);
+     Assert.assertNotNull(seqs[3]);
+     Assert.assertNotNull(seqs[0].getDatasetSequence());
+     Assert.assertNotNull(seqs[1].getDatasetSequence());
+     Assert.assertNotNull(seqs[2].getDatasetSequence());
+     Assert.assertNotNull(seqs[3].getDatasetSequence());
+     PDBEntry[] pdbEntries = new PDBEntry[4];
+     pdbEntries[0] = new PDBEntry("3W5V", "A", null, testFile);
+     pdbEntries[1] = new PDBEntry("3W5V", "B", null, testFile);
+     pdbEntries[2] = new PDBEntry("3W5V", "C", null, testFile);
+     pdbEntries[3] = new PDBEntry("3W5V", "D", null, testFile);
+     Assert.assertTrue(seqs[0].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[0]));
+     Assert.assertTrue(seqs[1].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[1]));
+     Assert.assertTrue(seqs[2].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[2]));
+     Assert.assertTrue(seqs[3].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[3]));
+     File tfile = File.createTempFile("testStoreAndRecoverPDBEntry", ".jvp");
+     try
+     {
+       new Jalview2XML(false).saveState(tfile);
+     } catch (Throwable e)
+     {
+       Assert.fail("Didn't save the state", e);
+     }
+     Desktop.instance.closeAll_actionPerformed(null);
+     if (Desktop.getAlignFrames() != null)
+     {
+       Assert.assertEquals(Desktop.getAlignFrames().length, 0);
+     }
+     AlignFrame restoredFrame = new FileLoader().LoadFileWaitTillLoaded(
 -            tfile.getAbsolutePath(), FormatAdapter.FILE);
++            tfile.getAbsolutePath(), DataSourceType.FILE);
+     String rfid = restoredFrame.getViewport().getSequenceSetId();
+     AlignmentPanel[] rAlignPanels = Desktop.getAlignmentPanels(rfid);
+     AlignmentViewPanel rap = rAlignPanels[0];
+     AlignmentI rAlignment = rap.getAlignment();
+     System.out.println("blah");
+     SequenceI[] rseqs = rAlignment.getSequencesArray();
+     Assert.assertNotNull(rseqs[0]);
+     Assert.assertNotNull(rseqs[1]);
+     Assert.assertNotNull(rseqs[2]);
+     Assert.assertNotNull(rseqs[3]);
+     Assert.assertNotNull(rseqs[0].getDatasetSequence());
+     Assert.assertNotNull(rseqs[1].getDatasetSequence());
+     Assert.assertNotNull(rseqs[2].getDatasetSequence());
+     Assert.assertNotNull(rseqs[3].getDatasetSequence());
+     // The Asserts below are expected to fail until the PDB chainCode is
+     // recoverable from a Jalview projects
+     Assert.assertTrue(rseqs[0].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[0]));
+     Assert.assertTrue(rseqs[1].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[1]));
+     Assert.assertTrue(rseqs[2].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[2]));
+     Assert.assertTrue(rseqs[3].getDatasetSequence().getAllPDBEntries()
+             .get(0).equals(pdbEntries[3]));
+   }
  }
@@@ -27,8 -27,9 +27,9 @@@ import jalview.datamodel.AlignedCodonFr
  import jalview.datamodel.Sequence;
  import jalview.datamodel.SequenceFeature;
  import jalview.datamodel.SequenceI;
 -import jalview.io.FormatAdapter;
 +import jalview.io.DataSourceType;
  import jalview.io.StructureFile;
+ import jalview.util.MapList;
  
  import java.util.ArrayList;
  import java.util.List;