Merge branch 'Jalview-BH/JAL-3026' into
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 1 Nov 2018 10:33:35 +0000 (10:33 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Thu, 1 Nov 2018 10:33:35 +0000 (10:33 +0000)
Jalview-BH/JAL-3026-JAL-3063-JAXB

Conflicts:
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/gui/Desktop.java
src/jalview/gui/UserDefinedColours.java
src/jalview/jbgui/GDesktop.java

1  2 
src/jalview/ext/ensembl/EnsemblRestClient.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/UserDefinedColours.java
src/jalview/jbgui/GDesktop.java

@@@ -20,6 -20,9 +20,7 @@@
   */
  package jalview.ext.ensembl;
  
+ import jalview.bin.Jalview;
 -import jalview.io.DataSourceType;
 -import jalview.io.FileParse;
  import jalview.util.StringUtils;
  
  import java.io.BufferedReader;
@@@ -64,9 -67,9 +65,9 @@@ abstract class EnsemblRestClient extend
     * @see https://github.com/Ensembl/ensembl-rest/wiki/Change-log
     * @see http://rest.ensembl.org/info/rest?content-type=application/json
     */
 -  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "6.3";
 +  private static final String LATEST_ENSEMBLGENOMES_REST_VERSION = "7.0";
  
 -  private static final String LATEST_ENSEMBL_REST_VERSION = "6.3";
 +  private static final String LATEST_ENSEMBL_REST_VERSION = "7.0";
  
    private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
  
    protected abstract boolean useGetRequest();
  
    /**
 -   * Return the desired value for the Content-Type request header
 -   * 
 -   * @param multipleIds
 +   * Returns the desired value for the Content-Type request header. Default is
 +   * application/json, override if required to vary this.
     * 
     * @return
     * @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
     */
 -  protected abstract String getRequestMimeType(boolean multipleIds);
 +  protected String getRequestMimeType()
 +  {
 +    return "application/json";
 +  }
  
    /**
 -   * Return the desired value for the Accept request header
 +   * Return the desired value for the Accept request header. Default is
 +   * application/json, override if required to vary this.
     * 
     * @return
     * @see https://github.com/Ensembl/ensembl-rest/wiki/HTTP-Headers
     */
 -  protected abstract String getResponseMimeType();
 +  protected String getResponseMimeType()
 +  {
 +    return "application/json";
 +  }
  
    /**
     * Checks Ensembl's REST 'ping' endpoint, and returns true if response
    }
  
    /**
 -   * returns a reader to a Fasta response from the Ensembl sequence endpoint
 +   * Returns a reader to a (Json) response from the Ensembl sequence endpoint.
 +   * If the request failed the return value may be null.
     * 
     * @param ids
     * @return
     * @throws IOException
     */
 -  protected FileParse getSequenceReader(List<String> ids) throws IOException
 +  protected BufferedReader getSequenceReader(List<String> ids)
 +          throws IOException
    {
      URL url = getUrl(ids);
  
      BufferedReader reader = getHttpResponse(url, ids);
 -    if (reader == null)
 -    {
 -      // request failed
 -      return null;
 -    }
 -    FileParse fp = new FileParse(reader, url.toString(),
 -            DataSourceType.URL);
 -    return fp;
 +    return reader;
    }
  
    /**
      boolean multipleIds = ids != null && ids.size() > 1;
      connection.setRequestMethod(
              multipleIds ? HttpMethod.POST : HttpMethod.GET);
 -    connection.setRequestProperty("Content-Type",
 -            getRequestMimeType(multipleIds));
 +    connection.setRequestProperty("Content-Type", getRequestMimeType());
      connection.setRequestProperty("Accept", getResponseMimeType());
  
      connection.setDoInput(true);
      connection.setDoOutput(multipleIds);
  
-     connection.setConnectTimeout(CONNECT_TIMEOUT_MS);
-     connection.setReadTimeout(readTimeout);
+     if (!Jalview.isJS()) 
+     {
+       connection.setUseCaches(false);
+       connection.setConnectTimeout(CONNECT_TIMEOUT_MS);
+       connection.setReadTimeout(readTimeout);
+     }
  
      if (multipleIds)
      {
@@@ -540,7 -540,7 +540,7 @@@ public class Desktop extends jalview.jb
    {
      final Desktop me = this;
      // Thread off the news reader, in case there are connection problems.
 -    addDialogThread(new Runnable()
 +    new Thread(new Runnable()
      {
        @Override
        public void run()
          showNews.setVisible(true);
          Cache.log.debug("Completed news thread.");
        }
 -    });
 +    }).start();
    }
  
    public void getIdentifiersOrgData()
    {
      // Thread off the identifiers fetcher
 -    addDialogThread(new Runnable()
 +    new Thread(new Runnable()
      {
        @Override
        public void run()
                    + e.getMessage());
          }
        }
 -    });
 +    }).start();
 +    ;
    }
  
    @Override
     * Jalview project file
     */
    @Override
 -  public void saveState_actionPerformed()
 +  public void saveState_actionPerformed(boolean asCastor)
    {
 -    JalviewFileChooser chooser = new JalviewFileChooser("jvp",
 +    JalviewFileChooser chooser = new JalviewFileChooser(
 +            asCastor ? "jvp" : "jvx",
              "Jalview Project");
  
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager.getString("label.save_state"));
-     // TODO: JAL-3048 Dialog runner refactoring here
-     int value = chooser.showSaveDialog(this);
-     if (value == JalviewFileChooser.APPROVE_OPTION)
+     int option = chooser.showSaveDialog(this);
+     if (option == JalviewFileChooser.APPROVE_OPTION)
      {
-       final Desktop me = this;
-       final java.io.File choice = chooser.getSelectedFile();
+       File choice = chooser.getSelectedFile();
        setProjectFile(choice);
  
        new Thread(new Runnable()
            // TODO prevent user from messing with the Desktop whilst we're saving
            try
            {
 -            new Jalview2XML().saveState(choice);
 +            if (asCastor)
 +            {
 +              new Jalview2XML().saveState(choice);
 +            }
 +            else
 +            {
 +              new jalview.project.Jalview2XML().saveState(choice);
 +            }
            } catch (OutOfMemoryError oom)
            {
              new OOMWarning(
              Cache.log.error(
                      "Problems whilst trying to save to " + choice.getName(),
                      ex);
-             JvOptionPane.showMessageDialog(me,
+             JvOptionPane.showMessageDialog(Desktop.this,
                      MessageManager.formatMessage(
                              "label.error_whilst_saving_current_state_to",
                              new Object[]
            setProgressBar(null, choice.hashCode());
          }
        }).start();
-     }
+       }
    }
  
-   private void setProjectFile(File choice)
+   void setProjectFile(File choice)
    {
      this.projectFile = choice;
    }
     * Prompts the user to choose a file and loads in as a Jalview project file
     */
    @Override
 -  public void loadState_actionPerformed()
 +  public void loadState_actionPerformed(boolean asCastor)
    {
 +    // TODO: GET RID OF .JVX BEFORE RELEASE JIM!
 +    final String[] suffix = asCastor ? new String[] { "jvp", "jar" }
 +            : new String[]
 +            { "jvx" };
 +    final String[] desc = asCastor
 +            ? new String[]
 +            { "Jalview Project", "Jalview Project (old)" }
 +            : new String[]
 +            { "Jalview Project" };
      JalviewFileChooser chooser = new JalviewFileChooser(
 -            Cache.getProperty("LAST_DIRECTORY"), new String[]
 -            { "jvp", "jar" },
 -            new String[]
 -            { "Jalview Project", "Jalview Project (old)" },
 +            Cache.getProperty("LAST_DIRECTORY"), suffix,
 +            desc,
              "Jalview Project");
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(MessageManager.getString("label.restore_state"));
-     int value = chooser.showOpenDialog(this);
-     if (value == JalviewFileChooser.APPROVE_OPTION)
+     chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
      {
-       final File selectedFile = chooser.getSelectedFile();
-       setProjectFile(selectedFile);
-       final String choice = selectedFile.getAbsolutePath();
-       Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
-       new Thread(new Runnable()
+       @Override
+       public void run()
        {
-         @Override
-         public void run()
+         File selectedFile = chooser.getSelectedFile();
+         setProjectFile(selectedFile);
+         final String choice = selectedFile.getAbsolutePath();
+         Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
+         new Thread(new Runnable()
          {
-           setProgressBar(MessageManager.formatMessage(
-                   "label.loading_jalview_project", new Object[]
-                   { choice }), choice.hashCode());
-           try
+           @Override
+           public void run()
            {
-             if (asCastor)
-             {
-               new Jalview2XML().loadJalviewAlign(choice);
-             }
-             else
 -            setProgressBar(MessageManager.formatMessage(
 -                    "label.loading_jalview_project", new Object[]
 -                    { choice }), choice.hashCode());
 -            try
 -            {
 -              new Jalview2XML().loadJalviewAlign(choice);
++              try {
++              if (asCastor)
++              {
++                new Jalview2XML().loadJalviewAlign(choice);
++              }
++              else
++              {
++                new jalview.project.Jalview2XML().loadJalviewAlign(choice);
++              }
+             } catch (OutOfMemoryError oom)
              {
-               new jalview.project.Jalview2XML().loadJalviewAlign(choice);
-             }
-           } catch (OutOfMemoryError oom)
-           {
 -              new OOMWarning("Whilst loading project from " + choice, oom);
 +            new OOMWarning("Whilst loading project from " + choice, oom);
-           } catch (Exception ex)
-           {
+             } catch (Exception ex)
+             {
 -              Cache.log.error(
 -                      "Problems whilst loading project from " + choice, ex);
 -              JvOptionPane.showMessageDialog(Desktop.desktop,
 -                      MessageManager.formatMessage(
 -                              "label.error_whilst_loading_project_from",
 -                              new Object[]
 -                              { choice }),
 -                      MessageManager.getString("label.couldnt_load_project"),
 -                      JvOptionPane.WARNING_MESSAGE);
 +            Cache.log.error(
 +                    "Problems whilst loading project from " + choice, ex);
 +            JvOptionPane.showMessageDialog(Desktop.desktop,
 +                    MessageManager.formatMessage(
 +                            "label.error_whilst_loading_project_from",
 +                            new Object[]
 +                            { choice }),
 +                    MessageManager.getString("label.couldnt_load_project"),
 +                    JvOptionPane.WARNING_MESSAGE);
+             }
 -            setProgressBar(null, choice.hashCode());
            }
-           setProgressBar(null, choice.hashCode());
-         }
-       }).start();
-     }
+         }).start();
+       }
+     });
+     
+     chooser.showOpenDialog(this);
    }
  
    @Override
@@@ -22,7 -22,6 +22,6 @@@ package jalview.gui
  
  import jalview.api.FeatureColourI;
  import jalview.api.FeatureSettingsControllerI;
- import jalview.bin.Jalview;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.SequenceI;
  import jalview.datamodel.features.FeatureMatcher;
@@@ -33,20 -32,19 +32,20 @@@ import jalview.gui.Help.HelpId
  import jalview.gui.JalviewColourChooser.ColourChooserListener;
  import jalview.io.JalviewFileChooser;
  import jalview.io.JalviewFileView;
  import jalview.schemes.FeatureColour;
  import jalview.util.MessageManager;
  import jalview.util.Platform;
+ import jalview.util.dialogrunner.RunResponse;
  import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
 +import jalview.xml.binding.jalview.JalviewUserColours;
 +import jalview.xml.binding.jalview.JalviewUserColours.Colour;
 +import jalview.xml.binding.jalview.JalviewUserColours.Filter;
 +import jalview.xml.binding.jalview.ObjectFactory;
  
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.awt.Component;
  import java.awt.Dimension;
- import java.awt.FlowLayout;
  import java.awt.Font;
  import java.awt.Graphics;
  import java.awt.GridLayout;
@@@ -103,11 -101,6 +102,11 @@@ import javax.swing.table.AbstractTableM
  import javax.swing.table.TableCellEditor;
  import javax.swing.table.TableCellRenderer;
  import javax.swing.table.TableColumn;
 +import javax.xml.bind.JAXBContext;
 +import javax.xml.bind.JAXBElement;
 +import javax.xml.bind.Marshaller;
 +import javax.xml.stream.XMLInputFactory;
 +import javax.xml.stream.XMLStreamReader;
  
  public class FeatureSettings extends JPanel
          implements FeatureSettingsControllerI
     */
    void load()
    {
-     // TODO: JAL-3048 relies on Castor XML parsing: not needed for JS-jalview core
-     // functionalty
      JalviewFileChooser chooser = new JalviewFileChooser("fc",
              SEQUENCE_FEATURE_COLOURS);
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(
              MessageManager.getString("label.load_feature_colours"));
      chooser.setToolTipText(MessageManager.getString("action.load"));
-     int value = chooser.showOpenDialog(this);
-     if (value == JalviewFileChooser.APPROVE_OPTION)
-     {
-       File file = chooser.getSelectedFile();
-       load(file);
-     }
+     chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION){
+               @Override
+               public void run() {
+                     File file = chooser.getSelectedFile();
+                     load(file);
+               }});
+     chooser.showOpenDialog(this);
    }
  
    /**
        InputStreamReader in = new InputStreamReader(
                new FileInputStream(file), "UTF-8");
  
 -      JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
 +      JAXBContext jc = JAXBContext
 +              .newInstance("jalview.xml.binding.jalview");
 +      javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
 +      XMLStreamReader streamReader = XMLInputFactory.newInstance()
 +              .createXMLStreamReader(in);
 +      JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
 +              JalviewUserColours.class);
 +      JalviewUserColours jucs = jbe.getValue();
 +
 +      // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
  
        /*
         * load feature colours
         */
 -      for (int i = jucs.getColourCount() - 1; i >= 0; i--)
 +      for (int i = jucs.getColour().size() - 1; i >= 0; i--)
        {
 -        jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
 -        FeatureColourI colour = Jalview2XML.unmarshalColour(newcol);
 +        Colour newcol = jucs.getColour().get(i);
 +        FeatureColourI colour = jalview.project.Jalview2XML
 +                .parseColour(newcol);
          fr.setColour(newcol.getName(), colour);
 -        fr.setOrder(newcol.getName(), i / (float) jucs.getColourCount());
 +        fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
        }
  
        /*
         * load feature filters; loaded filters will replace any that are
         * currently defined, other defined filters are left unchanged 
         */
 -      for (int i = 0; i < jucs.getFilterCount(); i++)
 +      for (int i = 0; i < jucs.getFilter().size(); i++)
        {
 -        jalview.schemabinding.version2.Filter filterModel = jucs
 -                .getFilter(i);
 +        Filter filterModel = jucs.getFilter().get(i);
          String featureType = filterModel.getFeatureType();
 -        FeatureMatcherSetI filter = Jalview2XML.unmarshalFilter(featureType,
 -                filterModel.getMatcherSet());
 +        FeatureMatcherSetI filter = jalview.project.Jalview2XML
 +                .parseFilter(featureType, filterModel.getMatcherSet());
          if (!filter.isEmpty())
          {
            fr.setFeatureFilter(featureType, filter);
     */
    void save()
    {
-     // TODO: JAL-3048 not needed for Jalview-JS - save colours
      JalviewFileChooser chooser = new JalviewFileChooser("fc",
              SEQUENCE_FEATURE_COLOURS);
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(
              MessageManager.getString("label.save_feature_colours"));
      chooser.setToolTipText(MessageManager.getString("action.save"));
-     int value = chooser.showSaveDialog(this);
-     if (value == JalviewFileChooser.APPROVE_OPTION)
-     {
-       save(chooser.getSelectedFile());
-     }
+     int option = chooser.showSaveDialog(this);
+       if (option == JalviewFileChooser.APPROVE_OPTION) 
+       {
+         File file = chooser.getSelectedFile();
+         save(file);
+       }
    }
  
    /**
        for (String featureType : sortedTypes)
        {
          FeatureColourI fcol = fr.getFeatureStyle(featureType);
 -        jalview.schemabinding.version2.Colour col = Jalview2XML.marshalColour(
 -                featureType, fcol);
 -        ucs.addColour(col);
 +        Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
 +                fcol);
 +        ucs.getColour().add(col);
        }
  
        /*
          {
            Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
            FeatureMatcherI firstMatcher = iterator.next();
 -          MatcherSet ms = Jalview2XML.marshalFilter(firstMatcher, iterator,
 +          jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
 +                  .marshalFilter(firstMatcher, iterator,
                    filter.isAnded());
            Filter filterModel = new Filter();
            filterModel.setFeatureType(featureType);
            filterModel.setMatcherSet(ms);
 -          ucs.addFilter(filterModel);
 +          ucs.getFilter().add(filterModel);
          }
        }
 +      JAXBContext jaxbContext = JAXBContext
 +              .newInstance(JalviewUserColours.class);
 +      Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
 +      jaxbMarshaller.marshal(
 +              new ObjectFactory().createJalviewUserColours(ucs), out);
 +
 +      // jaxbMarshaller.marshal(object, pout);
 +      // marshaller.marshal(object);
 +      out.flush();
  
 -      ucs.marshal(out);
 +      // ucs.marshal(out);
        out.close();
      } catch (Exception ex)
      {
      JPanel buttonPanel = new JPanel();
      buttonPanel.add(ok);
      buttonPanel.add(cancel);
-     if (!Jalview.isJS())
-     {
-       /*
-        * no save/load XML in JalviewJS for now
-        */
-       buttonPanel.add(loadColours);
-       buttonPanel.add(saveColours);
-     }
+     buttonPanel.add(loadColours);
+     buttonPanel.add(saveColours);
      bigPanel.add(scrollPane, BorderLayout.CENTER);
      settingsPane.add(bigPanel, BorderLayout.CENTER);
      settingsPane.add(buttonPanel, BorderLayout.SOUTH);
@@@ -24,6 -24,8 +24,6 @@@ import jalview.bin.Cache
  import jalview.io.JalviewFileChooser;
  import jalview.io.JalviewFileView;
  import jalview.jbgui.GUserDefinedColours;
 -import jalview.schemabinding.version2.Colour;
 -import jalview.schemabinding.version2.JalviewUserColours;
  import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemeLoader;
  import jalview.schemes.ColourSchemes;
@@@ -32,9 -34,7 +32,10 @@@ import jalview.schemes.UserColourScheme
  import jalview.util.ColorUtils;
  import jalview.util.Format;
  import jalview.util.MessageManager;
+ import jalview.util.dialogrunner.RunResponse;
 +import jalview.xml.binding.jalview.JalviewUserColours;
 +import jalview.xml.binding.jalview.JalviewUserColours.Colour;
 +import jalview.xml.binding.jalview.ObjectFactory;
  
  import java.awt.Color;
  import java.awt.Font;
@@@ -52,8 -52,6 +53,8 @@@ import javax.swing.JButton
  import javax.swing.JInternalFrame;
  import javax.swing.event.ChangeEvent;
  import javax.swing.event.ChangeListener;
 +import javax.xml.bind.JAXBContext;
 +import javax.xml.bind.Marshaller;
  
  /**
   * This panel allows the user to assign colours to Amino Acid residue codes, and
@@@ -90,7 -88,7 +91,7 @@@ public class UserDefinedColours extend
     * flag is true if the colour scheme has been changed since the
     * dialog was opened, or the changes last saved to file
     */
-   boolean changed;
+   boolean changedButNotSaved;
  
    JInternalFrame frame;
  
        button.setForeground(ColorUtils.brighterThan(newColour));
      }
  
-     changed = true;
+     changedButNotSaved = true;
    }
  
    /**
    {
      // BH 2018 no warning in JavaScript TODO
      
-     if (/** @j2sNative true || */ !changed)
+     if (/** @j2sNative true || */ !changedButNotSaved)
      {
        return;
      }
                question, title, JvOptionPane.DEFAULT_OPTION,
                JvOptionPane.PLAIN_MESSAGE, null, options, options[0]);
  
        if (response == 0)
        {
          /*
-          * prompt to save changes to file
+          * prompt to save changes to file; if done,
+          * resets 'changed' flag to false
           */
-         saved = savebutton_actionPerformed();
+         savebutton_actionPerformed();
        }
  
        /*
         * if user chooses not to save (either in this dialog or in the
         * save as dialogs), treat this as a new user defined colour scheme
         */
-       if (!saved)
+       if (changedButNotSaved)
        {
          /*
           * clear scheme name and re-apply as an anonymous scheme
    {
      upperCaseButtons = new ArrayList<>();
      lowerCaseButtons = new ArrayList<>();
-     // TODO: JAL-3048 requires Castor dependency for Jalview-JS
      JalviewFileChooser chooser = new JalviewFileChooser("jc",
              "Jalview User Colours");
      chooser.setFileView(new JalviewFileView());
      chooser.setDialogTitle(
              MessageManager.getString("label.load_colour_scheme"));
      chooser.setToolTipText(MessageManager.getString("action.load"));
-     int value = chooser.showOpenDialog(this);
-     if (value != JalviewFileChooser.APPROVE_OPTION)
-     {
-       return;
-     }
-     File choice = chooser.getSelectedFile();
-     Cache.setProperty(LAST_DIRECTORY, choice.getParent());
-     UserColourScheme ucs = ColourSchemeLoader
-             .loadColourScheme(choice.getAbsolutePath());
-     Color[] colors = ucs.getColours();
-     schemeName.setText(ucs.getSchemeName());
-     if (ucs.getLowerCaseColours() != null)
-     {
-       caseSensitive.setSelected(true);
-       lcaseColour.setEnabled(true);
-       resetButtonPanel(true);
-       for (int i = 0; i < lowerCaseButtons.size(); i++)
-       {
-         JButton button = lowerCaseButtons.get(i);
-         button.setBackground(ucs.getLowerCaseColours()[i]);
-       }
-     }
-     else
-     {
-       caseSensitive.setSelected(false);
-       lcaseColour.setEnabled(false);
-       resetButtonPanel(false);
-     }
-     for (int i = 0; i < upperCaseButtons.size(); i++)
-     {
-       JButton button = upperCaseButtons.get(i);
-       button.setBackground(colors[i]);
-     }
-     addNewColourScheme(choice.getPath());
+     chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION) {
+               @Override
+               public void run() {
+                   File choice = chooser.getSelectedFile();
+                   Cache.setProperty(LAST_DIRECTORY, choice.getParent());
+                   UserColourScheme ucs = ColourSchemeLoader
+                           .loadColourScheme(choice.getAbsolutePath());
+                   Color[] colors = ucs.getColours();
+                   schemeName.setText(ucs.getSchemeName());
+                   if (ucs.getLowerCaseColours() != null)
+                   {
+                     caseSensitive.setSelected(true);
+                     lcaseColour.setEnabled(true);
+                     resetButtonPanel(true);
+                     for (int i = 0; i < lowerCaseButtons.size(); i++)
+                     {
+                       JButton button = lowerCaseButtons.get(i);
+                       button.setBackground(ucs.getLowerCaseColours()[i]);
+                     }
+                   }
+                   else
+                   {
+                     caseSensitive.setSelected(false);
+                     lcaseColour.setEnabled(false);
+                     resetButtonPanel(false);
+                   }
+                   for (int i = 0; i < upperCaseButtons.size(); i++)
+                   {
+                     JButton button = upperCaseButtons.get(i);
+                     button.setBackground(colors[i]);
+                   }
+                   addNewColourScheme(choice.getPath());
+               }});
+     
+     chooser.showOpenDialog(this);
    }
  
    /**
     * <li>Don't apply the changes if the currently selected scheme is different,
     * to allow a new scheme to be configured and saved but not applied</li>
     * </ul>
-    * Returns true if the scheme is saved to file, false if it is not
-    * 
-    * @return
+    * If the scheme is saved to file, the 'changed' flag field is reset to false.
     */
    @Override
-   protected boolean savebutton_actionPerformed()
+   protected void savebutton_actionPerformed()
    {
      String name = schemeName.getText().trim();
      if (name.length() < 1)
                        .getString("label.user_colour_scheme_must_have_name"),
                MessageManager.getString("label.no_name_colour_scheme"),
                JvOptionPane.WARNING_MESSAGE);
-       return false;
      }
  
      if (ColourSchemes.getInstance().nameExists(name))
                JvOptionPane.YES_NO_OPTION);
        if (reply != JvOptionPane.YES_OPTION)
        {
-         return false;
        }
      }
-     // TODO: JAL-3048 saveas, also requires Castor dependency for Jalview-JS
  
      JalviewFileChooser chooser = new JalviewFileChooser("jc",
              "Jalview User Colours");
      chooser.setDialogTitle(
              MessageManager.getString("label.save_colour_scheme"));
      chooser.setToolTipText(MessageManager.getString("action.save"));
-     int value = chooser.showSaveDialog(this);
-     if (value != JalviewFileChooser.APPROVE_OPTION)
-     {
-       return false;
-     }
-     File file = chooser.getSelectedFile();
-     UserColourScheme updatedScheme = addNewColourScheme(file.getPath());
-     saveToFile(file);
-     changed = false;
-     /*
-      * changes saved - apply to alignment if we are changing 
-      * the currently selected colour scheme; also make the updated
-      * colours the 'backout' scheme on Cancel
-      */
-     if (oldColourScheme != null
-             && name.equals(oldColourScheme.getSchemeName()))
-     {
-       oldColourScheme = updatedScheme;
-       applyButton_actionPerformed();
+     int option = chooser.showSaveDialog(this);
+     if (option == JalviewFileChooser.APPROVE_OPTION) 
+     {
+         File file = chooser.getSelectedFile();
+         UserColourScheme updatedScheme = addNewColourScheme(file.getPath());
+         saveToFile(file);
+         changedButNotSaved = false;
+         /*
+          * changes saved - apply to alignment if we are changing 
+          * the currently selected colour scheme; also make the updated
+          * colours the 'backout' scheme on Cancel
+          */
+         if (oldColourScheme != null
+                 && name.equals(oldColourScheme.getSchemeName()))
+         {
+           oldColourScheme = updatedScheme;
+           applyButton_actionPerformed();
+         }
      }
-     return true;
    }
  
    /**
          Colour col = new Colour();
          col.setName(button.getText());
          col.setRGB(Format.getHexString(button.getBackground()));
 -        ucs.addColour(col);
 +        ucs.getColour().add(col);
        }
 -      ucs.marshal(out);
 +      JAXBContext jaxbContext = JAXBContext
 +              .newInstance(JalviewUserColours.class);
 +      Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
 +      jaxbMarshaller.marshal(
 +              new ObjectFactory().createJalviewUserColours(ucs), out);
 +      // ucs.marshal(out);
        out.close();
      } catch (Exception ex)
      {
@@@ -264,16 -264,7 +264,16 @@@ public class GDesktop extends JFram
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        saveState_actionPerformed();
 +        saveState_actionPerformed(true);
 +      }
 +    });
 +    JMenuItem saveAsJaxb = new JMenuItem("Save Project as JAXB");
 +    saveAsJaxb.addActionListener(new ActionListener()
 +    {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
 +      {
 +        saveState_actionPerformed(false);
        }
      });
      loadState.setText(MessageManager.getString("action.load_project"));
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        loadState_actionPerformed();
 +        loadState_actionPerformed(true);
 +      }
 +    });
 +    JMenuItem loadAsJaxb = new JMenuItem("Load Project as JAXB");
 +    loadAsJaxb.addActionListener(new ActionListener()
 +    {
 +      @Override
 +      public void actionPerformed(ActionEvent e)
 +      {
 +        loadState_actionPerformed(false);
        }
      });
      inputMenu.setText(MessageManager.getString("label.input_alignment"));
      desktopMenubar.add(windowMenu);
      FileMenu.add(inputMenu);
      FileMenu.add(inputSequence);
-     if (!Jalview.isJS())
 -      FileMenu.addSeparator();
 -      FileMenu.add(saveState);
 -      FileMenu.add(loadState);
 -      FileMenu.addSeparator();
++    FileMenu.addSeparator();
++    FileMenu.add(saveAsJaxb);
++    FileMenu.add(loadAsJaxb);
++    if (!Jalview.isJS()) 
 +    {
-       FileMenu.addSeparator();
 +      FileMenu.add(saveState);
 +      FileMenu.add(loadState);
 +    }
-     FileMenu.add(saveAsJaxb);
-     FileMenu.add(loadAsJaxb);
 +    FileMenu.addSeparator();
      FileMenu.add(quit);
      HelpMenu.add(aboutMenuItem);
      HelpMenu.add(documentationMenuItem);
    {
    }
  
 -  public void saveState_actionPerformed()
 +  /**
 +   * DOCUMENT ME!
 +   * 
 +   * @param e
 +   *          DOCUMENT ME!
 +   */
 +  public void saveState_actionPerformed(boolean asCastor)
    {
    }
  
 -  public void loadState_actionPerformed()
 +  /**
 +   * DOCUMENT ME!
 +   * 
 +   * @param e
 +   *          DOCUMENT ME!
 +   */
 +  public void loadState_actionPerformed(boolean asCastor)
 +  {
 +  }
 +
 +  /**
 +   * DOCUMENT ME!
 +   * 
 +   * @param e
 +   *          DOCUMENT ME!
 +   */
 +  public void loadJalviewAlign_actionPerformed(ActionEvent e)
    {
    }