JAL-3438 spotless for 2.11.2.0
[jalview.git] / src / jalview / gui / UserDefinedColours.java
index 6e9a121..1836e33 100755 (executable)
  */
 package jalview.gui;
 
-import jalview.api.structures.JalviewStructureDisplayI;
+import java.util.Locale;
+
 import jalview.bin.Cache;
-import jalview.datamodel.SequenceGroup;
 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;
@@ -36,11 +34,14 @@ import jalview.schemes.UserColourScheme;
 import jalview.util.ColorUtils;
 import jalview.util.Format;
 import jalview.util.MessageManager;
+import jalview.util.Platform;
+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;
 import java.awt.Insets;
-import java.awt.event.ActionEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.io.File;
@@ -54,6 +55,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
@@ -62,11 +65,11 @@ import javax.swing.event.ChangeListener;
  * @author Andrew Waterhouse
  * @author Mungo Carstairs
  */
-public class UserDefinedColours extends GUserDefinedColours implements
-        ChangeListener
+public class UserDefinedColours extends GUserDefinedColours
+        implements ChangeListener
 {
-  private static final Font VERDANA_BOLD_10 = new Font("Verdana",
-          Font.BOLD, 10);
+  private static final Font VERDANA_BOLD_10 = new Font("Verdana", Font.BOLD,
+          10);
 
   public static final String USER_DEFINED_COLOURS = "USER_DEFINED_COLOURS";
 
@@ -80,48 +83,44 @@ public class UserDefinedColours extends GUserDefinedColours implements
 
   AlignmentPanel ap;
 
-  SequenceGroup seqGroup;
-
-  List<JButton> selectedButtons;
-
+  /*
+   * the colour scheme when the dialog was opened, or
+   * the scheme last saved to file
+   */
   ColourSchemeI oldColourScheme;
 
-  JInternalFrame frame;
+  /*
+   * flag is true if the colour scheme has been changed since the
+   * dialog was opened, or the changes last saved to file
+   */
+  boolean changedButNotSaved;
 
-  JalviewStructureDisplayI structureViewer;
+  JInternalFrame frame;
 
   List<JButton> upperCaseButtons;
 
   List<JButton> lowerCaseButtons;
 
   /**
-   * Creates a new UserDefinedColours object.
+   * Creates and displays a new UserDefinedColours panel
    * 
-   * @param ap
-   * @param sg
+   * @param alignPanel
    */
-  public UserDefinedColours(AlignmentPanel ap, SequenceGroup sg)
+  public UserDefinedColours(AlignmentPanel alignPanel)
   {
     this();
 
     lcaseColour.setEnabled(false);
 
-    this.ap = ap;
-    seqGroup = sg;
+    this.ap = alignPanel;
 
-    if (seqGroup != null)
-    {
-      oldColourScheme = seqGroup.getColourScheme();
-    }
-    else
-    {
-      oldColourScheme = ap.av.getGlobalColourScheme();
-    }
+    oldColourScheme = alignPanel.av.getGlobalColourScheme();
 
     if (oldColourScheme instanceof UserColourScheme)
     {
       schemeName.setText(oldColourScheme.getSchemeName());
-      if (((UserColourScheme) oldColourScheme).getLowerCaseColours() != null)
+      if (((UserColourScheme) oldColourScheme)
+              .getLowerCaseColours() != null)
       {
         caseSensitive.setSelected(true);
         lcaseColour.setEnabled(true);
@@ -140,32 +139,10 @@ public class UserDefinedColours extends GUserDefinedColours implements
     showFrame();
   }
 
-  public UserDefinedColours(JalviewStructureDisplayI viewer,
-          ColourSchemeI oldcs)
-  {
-    this();
-    this.structureViewer = viewer;
-
-    colorChooser.getSelectionModel().addChangeListener(this);
-
-    oldColourScheme = oldcs;
-
-    if (oldColourScheme instanceof UserColourScheme)
-    {
-      schemeName.setText(((UserColourScheme) oldColourScheme)
-              .getSchemeName());
-    }
-
-    resetButtonPanel(false);
-
-    showFrame();
-
-  }
-
-  public UserDefinedColours()
+  UserDefinedColours()
   {
     super();
-    selectedButtons = new ArrayList<JButton>();
+    selectedButtons = new ArrayList<>();
   }
 
   void showFrame()
@@ -176,11 +153,6 @@ public class UserDefinedColours extends GUserDefinedColours implements
     Desktop.addInternalFrame(frame,
             MessageManager.getString("label.user_defined_colours"),
             MY_FRAME_WIDTH, MY_FRAME_HEIGHT, true);
-
-    if (seqGroup != null)
-    {
-      frame.setTitle(frame.getTitle() + " (" + seqGroup.getName() + ")");
-    }
   }
 
   /**
@@ -197,7 +169,7 @@ public class UserDefinedColours extends GUserDefinedColours implements
 
     if (upperCaseButtons == null)
     {
-      upperCaseButtons = new ArrayList<JButton>();
+      upperCaseButtons = new ArrayList<>();
     }
 
     for (int i = 0; i < 20; i++)
@@ -228,15 +200,17 @@ public class UserDefinedColours extends GUserDefinedColours implements
 
       if (lowerCaseButtons == null)
       {
-        lowerCaseButtons = new ArrayList<JButton>();
+        lowerCaseButtons = new ArrayList<>();
       }
 
       for (int i = 0; i < 20; i++)
       {
         int row = i / cols + 1;
         int index = (row * cols) + i;
-        JButton button = makeButton(ResidueProperties.aa[i].toLowerCase(),
-                ResidueProperties.aa[i].toLowerCase(), lowerCaseButtons, i);
+        JButton button = makeButton(
+                ResidueProperties.aa[i].toLowerCase(Locale.ROOT),
+                ResidueProperties.aa[i].toLowerCase(Locale.ROOT),
+                lowerCaseButtons, i);
 
         buttonPanel.add(button, index);
       }
@@ -284,7 +258,8 @@ public class UserDefinedColours extends GUserDefinedColours implements
       {
         button = lowerCaseButtons.get(i);
         button.setBackground(newColour);
-        button.setForeground(ColorUtils.brighterThan(button.getBackground()));
+        button.setForeground(
+                ColorUtils.brighterThan(button.getBackground()));
       }
     }
     for (int i = 0; i < selectedButtons.size(); i++)
@@ -293,6 +268,8 @@ public class UserDefinedColours extends GUserDefinedColours implements
       button.setBackground(newColour);
       button.setForeground(ColorUtils.brighterThan(newColour));
     }
+
+    changedButNotSaved = true;
   }
 
   /**
@@ -354,8 +331,8 @@ public class UserDefinedColours extends GUserDefinedColours implements
         JButton button = (JButton) buttonPanel.getComponent(b);
         if (!selectedButtons.contains(button))
         {
-          button.setForeground(ColorUtils.brighterThan(button
-                  .getBackground()));
+          button.setForeground(
+                  ColorUtils.brighterThan(button.getBackground()));
           selectedButtons.add(button);
         }
       }
@@ -368,7 +345,8 @@ public class UserDefinedColours extends GUserDefinedColours implements
         button.setForeground(ColorUtils.darkerThan(button.getBackground()));
       }
       selectedButtons.clear();
-      pressed.setForeground(ColorUtils.brighterThan(pressed.getBackground()));
+      pressed.setForeground(
+              ColorUtils.brighterThan(pressed.getBackground()));
       selectedButtons.add(pressed);
 
     }
@@ -376,13 +354,14 @@ public class UserDefinedColours extends GUserDefinedColours implements
     {
       if (selectedButtons.contains(pressed))
       {
-        pressed.setForeground(ColorUtils.darkerThan(pressed.getBackground()));
+        pressed.setForeground(
+                ColorUtils.darkerThan(pressed.getBackground()));
         selectedButtons.remove(pressed);
       }
       else
       {
-        pressed.setForeground(ColorUtils.brighterThan(pressed
-                .getBackground()));
+        pressed.setForeground(
+                ColorUtils.brighterThan(pressed.getBackground()));
         selectedButtons.add(pressed);
       }
     }
@@ -473,15 +452,25 @@ public class UserDefinedColours extends GUserDefinedColours implements
   {
     if (isNoSelectionMade())
     {
-      JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager
-              .getString("label.no_colour_selection_in_scheme"),
+      JvOptionPane.showMessageDialog(Desktop.desktop,
+              MessageManager
+                      .getString("label.no_colour_selection_in_scheme"),
               MessageManager.getString("label.no_colour_selection_warn"),
               JvOptionPane.WARNING_MESSAGE);
     }
     else
     {
+      /*
+       * OK is treated as 'apply colours and close'
+       */
       applyButton_actionPerformed();
 
+      /*
+       * If editing a named colour scheme, warn if changes
+       * have not been saved
+       */
+      warnIfUnsavedChanges();
+
       try
       {
         frame.setClosed(true);
@@ -492,6 +481,62 @@ public class UserDefinedColours extends GUserDefinedColours implements
   }
 
   /**
+   * If we have made changes to an existing user defined colour scheme but not
+   * saved them, show a dialog with the option to save. If the user chooses to
+   * save, do so, else clear the colour scheme name to indicate a new colour
+   * scheme.
+   */
+  protected void warnIfUnsavedChanges()
+  {
+    // BH 2018 no warning in JavaScript TODO
+
+    if (!Platform.isJS() && changedButNotSaved)
+    /**
+     * Java only
+     * 
+     * @j2sIgnore
+     */
+    {
+      String name = schemeName.getText().trim();
+      if (oldColourScheme != null && !"".equals(name)
+              && name.equals(oldColourScheme.getSchemeName()))
+      {
+        String message = MessageManager
+                .formatMessage("label.scheme_changed", name);
+        String title = MessageManager.getString("label.save_changes");
+        String[] options = new String[] { title,
+            MessageManager.getString("label.dont_save_changes"), };
+        final String question = JvSwingUtils.wrapTooltip(true, message);
+        int response = JvOptionPane.showOptionDialog(Desktop.desktop,
+                question, title, JvOptionPane.DEFAULT_OPTION,
+                JvOptionPane.PLAIN_MESSAGE, null, options, options[0]);
+
+        if (response == 0)
+        {
+          /*
+           * prompt to save changes to file; if done,
+           * resets 'changed' flag to false
+           */
+          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 (changedButNotSaved)
+        {
+          /*
+           * clear scheme name and re-apply as an anonymous scheme
+           */
+          schemeName.setText("");
+          applyButton_actionPerformed();
+        }
+      }
+    }
+  }
+
+  /**
    * Returns true if the user has not made any colour selection (including if
    * 'case-sensitive' selected and no lower-case colour chosen).
    * 
@@ -509,37 +554,31 @@ public class UserDefinedColours extends GUserDefinedColours implements
   }
 
   /**
-   * Applies the current colour scheme to the alignment, sequence group or
-   * structure view.
+   * Applies the current colour scheme to the alignment or sequence group
    */
   @Override
   protected void applyButton_actionPerformed()
   {
     if (isNoSelectionMade())
     {
-      JvOptionPane.showMessageDialog(Desktop.desktop, MessageManager
-              .getString("label.no_colour_selection_in_scheme"),
+      JvOptionPane.showMessageDialog(Desktop.desktop,
+              MessageManager
+                      .getString("label.no_colour_selection_in_scheme"),
               MessageManager.getString("label.no_colour_selection_warn"),
               JvOptionPane.WARNING_MESSAGE);
 
     }
     UserColourScheme ucs = getSchemeFromButtons();
 
-    if (seqGroup != null)
-    {
-      seqGroup.setColourScheme(ucs);
-      ap.paintAlignment(true);
-    }
-    else if (ap != null)
-    {
-      ap.alignFrame.changeColour(ucs);
-    }
-    else if (structureViewer != null)
-    {
-      structureViewer.setJalviewColourScheme(ucs);
-    }
+    ap.alignFrame.changeColour(ucs);
   }
 
+  /**
+   * Constructs an instance of UserColourScheme with the residue colours
+   * currently set on the buttons on the panel
+   * 
+   * @return
+   */
   UserColourScheme getSchemeFromButtons()
   {
 
@@ -591,72 +630,70 @@ public class UserDefinedColours extends GUserDefinedColours implements
       ucs.setLowerCaseColours(newColours);
     }
 
-    // if (ap != null)
-    // {
-    // ucs.setThreshold(0, ap.av.isIgnoreGapsConsensus());
-    // }
-
     return ucs;
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Action on clicking Load scheme button.
+   * <ul>
+   * <li>Open a file chooser to browse for files with extension .jc</li>
+   * <li>Load in the colour scheme and transfer it to this panel's buttons</li>
+   * <li>Register the loaded colour scheme</li>
+   * </ul>
    */
   @Override
-  protected void loadbutton_actionPerformed(ActionEvent e)
+  protected void loadbutton_actionPerformed()
   {
-    upperCaseButtons = new ArrayList<JButton>();
-    lowerCaseButtons = new ArrayList<JButton>();
-
+    upperCaseButtons = new ArrayList<>();
+    lowerCaseButtons = new ArrayList<>();
     JalviewFileChooser chooser = new JalviewFileChooser("jc",
             "Jalview User Colours");
     chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle(MessageManager
-            .getString("label.load_colour_scheme"));
+    chooser.setDialogTitle(
+            MessageManager.getString("label.load_colour_scheme"));
     chooser.setToolTipText(MessageManager.getString("action.load"));
+    chooser.setResponseHandler(0, new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        File choice = chooser.getSelectedFile();
+        Cache.setProperty(LAST_DIRECTORY, choice.getParent());
 
-    int value = chooser.showOpenDialog(this);
+        UserColourScheme ucs = ColourSchemeLoader
+                .loadColourScheme(choice.getAbsolutePath());
+        Color[] colors = ucs.getColours();
+        schemeName.setText(ucs.getSchemeName());
 
-    if (value != JalviewFileChooser.APPROVE_OPTION)
-    {
-      return;
-    }
-    File choice = chooser.getSelectedFile();
-    Cache.setProperty(LAST_DIRECTORY, choice.getParent());
+        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);
+        }
 
-    UserColourScheme ucs = ColourSchemeLoader.loadColourScheme(choice
-            .getAbsolutePath());
-    Color[] colors = ucs.getColours();
-    schemeName.setText(ucs.getSchemeName());
+        for (int i = 0; i < upperCaseButtons.size(); i++)
+        {
+          JButton button = upperCaseButtons.get(i);
+          button.setBackground(colors[i]);
+        }
 
-    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]);
+        addNewColourScheme(choice.getPath());
       }
-    }
-    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);
   }
 
   /**
@@ -688,54 +725,81 @@ public class UserDefinedColours extends GUserDefinedColours implements
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Action on pressing the Save button.
+   * <ul>
+   * <li>Check a name has been entered</li>
+   * <li>Warn if the name already exists, remove any existing scheme of the same
+   * name if overwriting</li>
+   * <li>Do the standard file chooser thing to write with extension .jc</li>
+   * <li>If saving changes (possibly not yet applied) to the currently selected
+   * colour scheme, then apply the changes, as it is too late to back out
+   * now</li>
+   * <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>
+   * If the scheme is saved to file, the 'changed' flag field is reset to false.
    */
   @Override
-  protected void savebutton_actionPerformed(ActionEvent e)
+  protected void savebutton_actionPerformed()
   {
     String name = schemeName.getText().trim();
     if (name.length() < 1)
     {
-      JvOptionPane.showInternalMessageDialog(Desktop.desktop, MessageManager
-              .getString("label.user_colour_scheme_must_have_name"),
+      JvOptionPane.showInternalMessageDialog(Desktop.desktop,
+              MessageManager
+                      .getString("label.user_colour_scheme_must_have_name"),
               MessageManager.getString("label.no_name_colour_scheme"),
               JvOptionPane.WARNING_MESSAGE);
-      return;
     }
 
-    if (ColourSchemes.getInstance().nameExists(name))
+    if (!Platform.isJS() && ColourSchemes.getInstance().nameExists(name))
     {
-      int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
-              MessageManager.formatMessage(
-                      "label.colour_scheme_exists_overwrite", new Object[] {
-                          name, name }),
-              MessageManager.getString("label.duplicate_scheme_name"),
-              JvOptionPane.YES_NO_OPTION);
-      if (reply != JvOptionPane.YES_OPTION)
+      /**
+       * java only
+       * 
+       * @j2sIgnore
+       */
       {
-        return;
+        int reply = JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
+                MessageManager.formatMessage(
+                        "label.colour_scheme_exists_overwrite", new Object[]
+                        { name, name }),
+                MessageManager.getString("label.duplicate_scheme_name"),
+                JvOptionPane.YES_NO_OPTION);
+        if (reply != JvOptionPane.YES_OPTION)
+        {
+          return;
+        }
       }
-      ColourSchemes.getInstance().removeColourScheme(name);
     }
+
     JalviewFileChooser chooser = new JalviewFileChooser("jc",
             "Jalview User Colours");
 
     JalviewFileView fileView = new JalviewFileView();
     chooser.setFileView(fileView);
-    chooser.setDialogTitle(MessageManager
-            .getString("label.save_colour_scheme"));
+    chooser.setDialogTitle(
+            MessageManager.getString("label.save_colour_scheme"));
     chooser.setToolTipText(MessageManager.getString("action.save"));
-
-    int value = chooser.showSaveDialog(this);
-
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+    int option = chooser.showSaveDialog(this);
+    if (option == JalviewFileChooser.APPROVE_OPTION)
     {
       File file = chooser.getSelectedFile();
-      addNewColourScheme(file.getPath());
+      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();
+      }
     }
   }
 
@@ -746,15 +810,16 @@ public class UserDefinedColours extends GUserDefinedColours implements
    * the colour scheme.
    * 
    * @param filePath
+   * @return
    */
-  protected void addNewColourScheme(String filePath)
+  protected UserColourScheme addNewColourScheme(String filePath)
   {
     /*
      * update the delimited list of user defined colour files in
      * Jalview property USER_DEFINED_COLOURS
      */
-    String defaultColours = Cache
-            .getDefault(USER_DEFINED_COLOURS, filePath);
+    String defaultColours = Cache.getDefault(USER_DEFINED_COLOURS,
+            filePath);
     if (defaultColours.indexOf(filePath) == -1)
     {
       if (defaultColours.length() > 0)
@@ -778,6 +843,8 @@ public class UserDefinedColours extends GUserDefinedColours implements
     {
       ap.alignFrame.buildColourMenu();
     }
+
+    return ucs;
   }
 
   /**
@@ -792,7 +859,8 @@ public class UserDefinedColours extends GUserDefinedColours implements
      * marshal to file
      */
     JalviewUserColours ucs = new JalviewUserColours();
-    ucs.setSchemeName(schemeName.getText());
+    String name = schemeName.getText();
+    ucs.setSchemeName(name);
     try
     {
       PrintWriter out = new PrintWriter(new OutputStreamWriter(
@@ -804,9 +872,14 @@ public class UserDefinedColours extends GUserDefinedColours implements
         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)
     {
@@ -815,30 +888,14 @@ public class UserDefinedColours extends GUserDefinedColours implements
   }
 
   /**
-   * On cancel, restores the colour scheme before the dialogue was opened
-   * 
-   * @param e
+   * On cancel, restores the colour scheme that was selected before the dialogue
+   * was opened
    */
   @Override
-  protected void cancelButton_actionPerformed(ActionEvent e)
+  protected void cancelButton_actionPerformed()
   {
-    if (ap != null)
-    {
-      if (seqGroup != null)
-      {
-        seqGroup.setColourScheme(oldColourScheme);
-      }
-      else
-      {
-        ap.alignFrame.changeColour(oldColourScheme);
-      }
-      ap.paintAlignment(true);
-    }
-
-    if (structureViewer != null)
-    {
-      structureViewer.setJalviewColourScheme(oldColourScheme);
-    }
+    ap.alignFrame.changeColour(oldColourScheme);
+    ap.paintAlignment(true, true);
 
     try
     {
@@ -848,8 +905,14 @@ public class UserDefinedColours extends GUserDefinedColours implements
     }
   }
 
+  /**
+   * Action on selecting or deselecting the Case Sensitive option. When
+   * selected, separate buttons are shown for lower case residues, and the panel
+   * is resized to accommodate them. Also, the checkbox for 'apply colour to all
+   * lower case' is enabled.
+   */
   @Override
-  public void caseSensitive_actionPerformed(ActionEvent e)
+  public void caseSensitive_actionPerformed()
   {
     boolean selected = caseSensitive.isSelected();
     resetButtonPanel(selected);