JAL-3116 parse EMBL XML with JAXB (todo: update unit tests)
[jalview.git] / src / jalview / gui / FontChooser.java
index b6116d9..92cc4c6 100755 (executable)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
  */
 package jalview.gui;
 
-import java.awt.*;
-import java.awt.event.*;
-import javax.swing.*;
-
-import jalview.bin.*;
-import jalview.jbgui.*;
+import jalview.bin.Cache;
+import jalview.jbgui.GFontChooser;
 import jalview.util.MessageManager;
 
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.geom.Rectangle2D;
+
+import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
+
 /**
  * DOCUMENT ME!
  * 
@@ -40,38 +43,69 @@ public class FontChooser extends GFontChooser
 
   TreePanel tp;
 
+  /*
+   * The font on opening the dialog (to be restored on Cancel)
+   */
   Font oldFont;
 
+  /*
+   * The font on opening the dialog (to be restored on Cancel)
+   * on the other half of a split frame (if applicable)
+   */
+  Font oldComplementFont;
+
+  /*
+   * the state of 'scale protein as cDNA' on opening the dialog
+   */
+  boolean oldProteinScale;
+
+  /*
+   * the state of 'same font for protein and cDNA' on opening the dialog
+   */
+  boolean oldMirrorFont;
+
   boolean init = true;
 
   JInternalFrame frame;
 
+  /*
+   * The last font settings selected in the dialog
+   */
+  private Font lastSelected = null;
+
+  private boolean lastSelMono = false;
+
+  private boolean oldSmoothFont;
+
+  private boolean oldComplementSmooth;
+
   /**
-   * Creates a new FontChooser object.
+   * Creates a new FontChooser for a tree panel
    * 
-   * @param ap
-   *          DOCUMENT ME!
+   * @param treePanel
    */
-  public FontChooser(TreePanel tp)
+  public FontChooser(TreePanel treePanel)
   {
-    this.tp = tp;
-    ap = tp.treeCanvas.ap;
-    oldFont = tp.getTreeFont();
+    this.tp = treePanel;
+    ap = treePanel.getTreeCanvas().getAssociatedPanel();
+    oldFont = treePanel.getTreeFont();
     defaultButton.setVisible(false);
     smoothFont.setEnabled(false);
     init();
   }
 
   /**
-   * Creates a new FontChooser object.
+   * Creates a new FontChooser for an alignment panel
    * 
-   * @param ap
-   *          DOCUMENT ME!
+   * @param alignPanel
    */
-  public FontChooser(AlignmentPanel ap)
+  public FontChooser(AlignmentPanel alignPanel)
   {
-    oldFont = ap.av.getFont();
-    this.ap = ap;
+    oldFont = alignPanel.av.getFont();
+    oldProteinScale = alignPanel.av.isScaleProteinAsCdna();
+    oldMirrorFont = alignPanel.av.isProteinFontAsCdna();
+    oldSmoothFont = alignPanel.av.antiAlias;
+    this.ap = alignPanel;
     init();
   }
 
@@ -82,16 +116,34 @@ public class FontChooser extends GFontChooser
 
     smoothFont.setSelected(ap.av.antiAlias);
 
-    if (tp != null)
+    /*
+     * Enable 'scale protein as cDNA' in a SplitFrame view. The selection is
+     * stored in the ViewStyle of both dna and protein Viewport. Also enable
+     * checkbox for copy font changes to other half of split frame.
+     */
+    boolean inSplitFrame = ap.av.getCodingComplement() != null;
+    if (inSplitFrame)
+    {
+      oldComplementFont = ((AlignViewport) ap.av.getCodingComplement())
+              .getFont();
+      oldComplementSmooth = ((AlignViewport) ap.av
+              .getCodingComplement()).antiAlias;
+      scaleAsCdna.setVisible(true);
+      scaleAsCdna.setSelected(ap.av.isScaleProteinAsCdna());
+      fontAsCdna.setVisible(true);
+      fontAsCdna.setSelected(ap.av.isProteinFontAsCdna());
+    }
+
+    if (isTreeFont())
     {
       Desktop.addInternalFrame(frame,
               MessageManager.getString("action.change_font_tree_panel"),
-              340, 170, false);
+              400, 200, false);
     }
     else
     {
       Desktop.addInternalFrame(frame,
-              MessageManager.getString("action.change_font"), 340, 170,
+              MessageManager.getString("action.change_font"), 380, 220,
               false);
     }
 
@@ -107,7 +159,7 @@ public class FontChooser extends GFontChooser
 
     for (int i = 1; i < 51; i++)
     {
-      fontSize.addItem(i + "");
+      fontSize.addItem(i);
     }
 
     fontStyle.addItem("plain");
@@ -115,22 +167,32 @@ public class FontChooser extends GFontChooser
     fontStyle.addItem("italic");
 
     fontName.setSelectedItem(oldFont.getName());
-    fontSize.setSelectedItem(oldFont.getSize() + "");
+    fontSize.setSelectedItem(oldFont.getSize());
     fontStyle.setSelectedIndex(oldFont.getStyle());
 
     FontMetrics fm = getGraphics().getFontMetrics(oldFont);
-    monospaced.setSelected(fm.getStringBounds("M", getGraphics())
-            .getWidth() == fm.getStringBounds("|", getGraphics())
-            .getWidth());
+    monospaced.setSelected(
+            fm.getStringBounds("M", getGraphics()).getWidth() == fm
+                    .getStringBounds("|", getGraphics()).getWidth());
 
     init = false;
   }
 
-  public void smoothFont_actionPerformed(ActionEvent e)
+  @Override
+  protected void smoothFont_actionPerformed()
   {
     ap.av.antiAlias = smoothFont.isSelected();
-    ap.annotationPanel.image = null;
-    ap.paintAlignment(true);
+    ap.getAnnotationPanel().image = null;
+    ap.paintAlignment(true, false);
+    if (ap.av.getCodingComplement() != null && ap.av.isProteinFontAsCdna())
+    {
+      ((AlignViewport) ap.av
+              .getCodingComplement()).antiAlias = ap.av.antiAlias;
+      SplitFrame sv = (SplitFrame) ap.alignFrame.getSplitViewContainer();
+      sv.adjustLayout();
+      sv.repaint();
+    }
+
   }
 
   /**
@@ -139,7 +201,8 @@ public class FontChooser extends GFontChooser
    * @param e
    *          DOCUMENT ME!
    */
-  protected void ok_actionPerformed(ActionEvent e)
+  @Override
+  protected void ok_actionPerformed()
   {
     try
     {
@@ -163,20 +226,34 @@ public class FontChooser extends GFontChooser
    * @param e
    *          DOCUMENT ME!
    */
-  protected void cancel_actionPerformed(ActionEvent e)
+  @Override
+  protected void cancel_actionPerformed()
   {
-    if (ap != null)
+    if (isTreeFont())
     {
-      ap.av.setFont(oldFont);
-      ap.paintAlignment(true);
+      tp.setTreeFont(oldFont);
     }
-    else if (tp != null)
+    else if (ap != null)
     {
-      tp.setTreeFont(oldFont);
+      ap.av.setFont(oldFont, true);
+      ap.av.setScaleProteinAsCdna(oldProteinScale);
+      ap.av.setProteinFontAsCdna(oldMirrorFont);
+      ap.av.antiAlias = oldSmoothFont;
+      ap.fontChanged();
+
+      if (scaleAsCdna.isVisible() && scaleAsCdna.isEnabled())
+      {
+        ap.av.getCodingComplement().setScaleProteinAsCdna(oldProteinScale);
+        ap.av.getCodingComplement().setProteinFontAsCdna(oldMirrorFont);
+        ((AlignViewport) ap.av
+                .getCodingComplement()).antiAlias = oldComplementSmooth;
+        ap.av.getCodingComplement().setFont(oldComplementFont, true);
+        SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+                .getSplitViewContainer();
+        splitFrame.adjustLayout();
+        splitFrame.repaint();
+      }
     }
-    fontName.setSelectedItem(oldFont.getName());
-    fontSize.setSelectedItem(oldFont.getSize() + "");
-    fontStyle.setSelectedIndex(oldFont.getStyle());
 
     try
     {
@@ -186,13 +263,10 @@ public class FontChooser extends GFontChooser
     }
   }
 
-  private Font lastSelected = null;
-
-  private int lastSelStyle = 0;
-
-  private int lastSelSize = 0;
-
-  private boolean lastSelMono = false;
+  private boolean isTreeFont()
+  {
+    return tp != null;
+  }
 
   /**
    * DOCUMENT ME!
@@ -203,55 +277,93 @@ public class FontChooser extends GFontChooser
     {
       // initialise with original font
       lastSelected = oldFont;
-      lastSelSize = oldFont.getSize();
-      lastSelStyle = oldFont.getStyle();
       FontMetrics fm = getGraphics().getFontMetrics(oldFont);
-      double mw = fm.getStringBounds("M", getGraphics()).getWidth(), iw = fm
-              .getStringBounds("I", getGraphics()).getWidth();
-      lastSelMono = mw == iw;
+      double mw = fm.getStringBounds("M", getGraphics()).getWidth();
+      double iw = fm.getStringBounds("I", getGraphics()).getWidth();
+      lastSelMono = (mw == iw); // == on double - flaky?
     }
 
     Font newFont = new Font(fontName.getSelectedItem().toString(),
-            fontStyle.getSelectedIndex(), Integer.parseInt(fontSize
-                    .getSelectedItem().toString()));
+            fontStyle.getSelectedIndex(),
+            (Integer) fontSize.getSelectedItem());
     FontMetrics fm = getGraphics().getFontMetrics(newFont);
-    double mw = fm.getStringBounds("M", getGraphics()).getWidth(), iw = fm
-            .getStringBounds("I", getGraphics()).getWidth();
+    double mw = fm.getStringBounds("M", getGraphics()).getWidth();
+    final Rectangle2D iBounds = fm.getStringBounds("I", getGraphics());
+    double iw = iBounds.getWidth();
     if (mw < 1 || iw < 1)
     {
-      fontName.setSelectedItem(lastSelected.getName());
-      fontStyle.setSelectedIndex(lastSelStyle);
-      fontSize.setSelectedItem("" + lastSelSize);
-      monospaced.setSelected(lastSelMono);
-      JOptionPane
-              .showInternalMessageDialog(
-                      this,
-                      MessageManager.getString("label.font_doesnt_have_letters_defined"),
-                      MessageManager.getString("label.invalid_font"), JOptionPane.WARNING_MESSAGE);
+      String message = iBounds.getHeight() < 1
+              ? MessageManager
+                      .getString("label.font_doesnt_have_letters_defined")
+              : MessageManager.getString("label.font_too_small");
+      JvOptionPane.showInternalMessageDialog(this, message,
+              MessageManager.getString("label.invalid_font"),
+              JvOptionPane.WARNING_MESSAGE);
+      /*
+       * Restore the changed value - note this will reinvoke this method via the
+       * ActionListener, but now validation should pass
+       */
+      if (lastSelected.getSize() != (Integer) fontSize.getSelectedItem()) // autoboxing
+      {
+        fontSize.setSelectedItem(lastSelected.getSize());
+      }
+      if (!lastSelected.getName()
+              .equals(fontName.getSelectedItem().toString()))
+      {
+        fontName.setSelectedItem(lastSelected.getName());
+      }
+      if (lastSelected.getStyle() != fontStyle.getSelectedIndex())
+      {
+        fontStyle.setSelectedIndex(lastSelected.getStyle());
+      }
+      if (lastSelMono != monospaced.isSelected())
+      {
+        monospaced.setSelected(lastSelMono);
+      }
       return;
     }
-    if (tp != null)
+    if (isTreeFont())
     {
       tp.setTreeFont(newFont);
     }
     else if (ap != null)
     {
-      ap.av.setFont(newFont);
+      ap.av.setFont(newFont, true);
       ap.fontChanged();
+
+      /*
+       * adjust other half of split frame if present, whether or not same font or
+       * scale to cDNA is selected, because a font change may affect character
+       * width, and this is kept the same in both panels
+       */
+      if (fontAsCdna.isVisible())
+      {
+        if (fontAsCdna.isSelected())
+        {
+          ap.av.getCodingComplement().setFont(newFont, true);
+        }
+
+        SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+                .getSplitViewContainer();
+        splitFrame.adjustLayout();
+        splitFrame.repaint();
+      }
     }
 
     monospaced.setSelected(mw == iw);
-    // remember last selected
+
+    /*
+     * Remember latest valid selection, so it can be restored if followed by an
+     * invalid one
+     */
     lastSelected = newFont;
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Updates on change of selected font name
    */
-  protected void fontName_actionPerformed(ActionEvent e)
+  @Override
+  protected void fontName_actionPerformed()
   {
     if (init)
     {
@@ -262,12 +374,10 @@ public class FontChooser extends GFontChooser
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Updates on change of selected font size
    */
-  protected void fontSize_actionPerformed(ActionEvent e)
+  @Override
+  protected void fontSize_actionPerformed()
   {
     if (init)
     {
@@ -278,12 +388,10 @@ public class FontChooser extends GFontChooser
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Updates on change of selected font style
    */
-  protected void fontStyle_actionPerformed(ActionEvent e)
+  @Override
+  protected void fontStyle_actionPerformed()
   {
     if (init)
     {
@@ -294,17 +402,57 @@ public class FontChooser extends GFontChooser
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Make selected settings the defaults by storing them (via Cache class) in
+   * the .jalview_properties file (the file is only written when Jalview exits)
    */
-  public void defaultButton_actionPerformed(ActionEvent e)
+  @Override
+  public void defaultButton_actionPerformed()
   {
     Cache.setProperty("FONT_NAME", fontName.getSelectedItem().toString());
     Cache.setProperty("FONT_STYLE", fontStyle.getSelectedIndex() + "");
     Cache.setProperty("FONT_SIZE", fontSize.getSelectedItem().toString());
     Cache.setProperty("ANTI_ALIAS",
             Boolean.toString(smoothFont.isSelected()));
+    Cache.setProperty(Preferences.SCALE_PROTEIN_TO_CDNA,
+            Boolean.toString(scaleAsCdna.isSelected()));
+  }
+
+  /**
+   * Turn on/off scaling of protein characters to 3 times the width of cDNA
+   * characters
+   */
+  @Override
+  protected void scaleAsCdna_actionPerformed()
+  {
+    ap.av.setScaleProteinAsCdna(scaleAsCdna.isSelected());
+    ap.av.getCodingComplement()
+            .setScaleProteinAsCdna(scaleAsCdna.isSelected());
+    final SplitFrame splitFrame = (SplitFrame) ap.alignFrame
+            .getSplitViewContainer();
+    splitFrame.adjustLayout();
+    splitFrame.repaint();
+  }
+
+  /**
+   * Turn on/off mirroring of font across split frame. If turning on, also
+   * copies the current font across the split frame. If turning off, restores
+   * the other half of the split frame to its initial font.
+   */
+  @Override
+  protected void mirrorFonts_actionPerformed()
+  {
+    boolean selected = fontAsCdna.isSelected();
+    ap.av.setProteinFontAsCdna(selected);
+    ap.av.getCodingComplement().setProteinFontAsCdna(selected);
+
+    /*
+     * reset other half of split frame if turning option off
+     */
+    if (!selected)
+    {
+      ap.av.getCodingComplement().setFont(oldComplementFont, true);
+    }
+
+    changeFont();
   }
 }