Merge branch 'bug/JAL-3536getCrossrefTwice' into develop
authorJim Procter <jprocter@issues.jalview.org>
Fri, 21 Feb 2020 17:18:34 +0000 (17:18 +0000)
committerJim Procter <jprocter@issues.jalview.org>
Fri, 21 Feb 2020 17:18:34 +0000 (17:18 +0000)
14 files changed:
build.gradle
help/help/html/releases.html
resources/lang/Messages.properties
src/jalview/api/AlignViewControllerGuiI.java
src/jalview/api/SplitContainerI.java
src/jalview/appletgui/AlignFrame.java
src/jalview/controller/FeatureSettingsControllerGuiI.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/Preferences.java
src/jalview/gui/SplitFrame.java
src/jalview/util/MessageManager.java

index ba884a1..427d4a3 100644 (file)
@@ -1185,33 +1185,47 @@ task sourceDist (type: Tar) {
   
   into project.name
 
-  def EXCLUDE_FILES=["build/*","bin/*","test-output/","test-reports","tests","clover*/*"
-  ,".*"
-  ,"benchmarking/*"
-  ,"**/.*"
-  ,"*.class"
-  ,"**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales"
-  ,"*locales/**",
-  ,"utils/InstallAnywhere"] 
-  def PROCESS_FILES=[   "AUTHORS",
-  "CITATION",
-  "FEATURETODO",
-  "JAVA-11-README",
-  "FEATURETODO",
-  "LICENSE",
-  "**/README",
-  "RELEASE",
-  "THIRDPARTYLIBS","TESTNG",
-  "build.gradle",
-  "gradle.properties",
-  "**/*.java",
-  "**/*.html",
-  "**/*.xml",
-  "**/*.gradle",
-  "**/*.groovy",
-  "**/*.properties",
-  "**/*.perl",
-  "**/*.sh"]
+  def EXCLUDE_FILES=[
+    "build/*",
+    "bin/*",
+    "test-output/",
+    "test-reports",
+    "tests",
+    "clover*/*",
+    ".*",
+    "benchmarking/*",
+    "**/.*",
+    "*.class",
+    "**/*.class","$j11modDir/**/*.jar","appletlib","**/*locales",
+    "*locales/**",
+    "utils/InstallAnywhere",
+    "**/*.log",
+  ] 
+  def PROCESS_FILES=[
+    "AUTHORS",
+    "CITATION",
+    "FEATURETODO",
+    "JAVA-11-README",
+    "FEATURETODO",
+    "LICENSE",
+    "**/README",
+    "RELEASE",
+    "THIRDPARTYLIBS",
+    "TESTNG",
+    "build.gradle",
+    "gradle.properties",
+    "**/*.java",
+    "**/*.html",
+    "**/*.xml",
+    "**/*.gradle",
+    "**/*.groovy",
+    "**/*.properties",
+    "**/*.perl",
+    "**/*.sh",
+  ]
+  def INCLUDE_FILES=[
+    ".settings/org.eclipse.jdt.core.jalview.prefs",
+  ]
 
   from(jalviewDir) {
     exclude (EXCLUDE_FILES)
@@ -1221,17 +1235,20 @@ task sourceDist (type: Tar) {
   from(jalviewDir) {
     exclude (EXCLUDE_FILES)
     exclude (PROCESS_FILES)
-  exclude ("appletlib")
-  exclude ("**/*locales")
-  exclude ("*locales/**")
-  exclude ("utils/InstallAnywhere")
+    exclude ("appletlib")
+    exclude ("**/*locales")
+    exclude ("*locales/**")
+    exclude ("utils/InstallAnywhere")
 
     exclude (getdown_files_dir)
-  exclude (getdown_website_dir)
+    exclude (getdown_website_dir)
 
-  // exluding these as not using jars as modules yet
-  exclude ("$j11modDir/**/*.jar")
-}
+    // exluding these as not using jars as modules yet
+    exclude ("$j11modDir/**/*.jar")
+  }
+  from(jalviewDir) {
+    include(INCLUDE_FILES)
+  }
 //  from (jalviewDir) {
 //    // explicit includes for stuff that seemed to not get included
 //    include(fileTree("test/**/*."))
index bb4b386..2fa241c 100755 (executable)
@@ -58,17 +58,23 @@ li:before {
     <tr>
       <td width="60" align="center" nowrap><strong><a
           name="Jalview.2.11.1">2.11.1</a><a name="Jalview.2.11.1.0">.0</a><br />
-          <em>16/2/2020</em></strong></td>
+          <em>25/2/2020</em></strong></td>
       <td align="left" valign="top">
         <ul>
+          <li><!-- JAL-3121 -->Feature attributes from VCF files can be exported and re-imported as GFF3 files
+          </li>
           <li>
-            <!-- JAL-3376 -->Record &quot;fixed column&quot; values POS, ID, QUAL, FILTER from VCF as Feature Attributes
+            <!-- JAL-3376 -->Record &quot;fixed column&quot; values POS,
+            ID, QUAL, FILTER from VCF as Feature Attributes
           </li>
           <li>
-            <!-- JAL-3375 -->More robust VCF numeric data field validation
-            while parsing (e.g. AF* attributes)
+            <!-- JAL-3375 -->More robust VCF numeric data field
+            validation while parsing (e.g. AF* attributes)
+          </li>
+          <li>
+            <!-- JAL-3538 -->Font anti-aliasing in alignment views
+            enabled by default
           </li>
-          
           <li>
           <!-- JAL -->
           </li>
index fdd15cd..a1d32e6 100644 (file)
@@ -132,6 +132,8 @@ tooltip.select_highlighted_columns = Press B to mark highlighted columns, Ctrl-(
 action.deselect_all = Deselect all
 action.invert_selection = Invert selection
 action.using_jmol = Using Jmol
+action.undo_changes_to_feature_settings = Undo all unapplied changes to feature settings
+action.undo_changes_to_feature_settings_and_close_the_dialog = Undo all pending changes and close the feature settings dialog
 action.link = Link
 action.group_link = Group Link
 action.show_chain = Show Chain
@@ -228,6 +230,7 @@ label.nucleotide = Nucleotide
 label.protein = Protein
 label.nucleotides = Nucleotides
 label.proteins = Proteins
+label.CDS = CDS
 label.to_new_alignment = To New Alignment
 label.to_this_alignment = Add To This Alignment
 label.apply_colour_to_all_groups = Apply Colour To All Groups
@@ -765,6 +768,9 @@ label.generating_features_for_params = Generating features for - {0}
 label.generating_annotations_for_params = Generating annotations for - {0}
 label.varna_params = VARNA - {0}
 label.sequence_feature_settings = Sequence Feature Settings
+label.sequence_feature_settings_for = Sequence Feature Settings for {0}
+label.sequence_feature_settings_for_view = Sequence Feature Settings for view "{0}"
+label.sequence_feature_settings_for_CDS_and_Protein = Sequence Feature Settings for CDS and Protein
 label.pairwise_aligned_sequences = Pairwise Aligned Sequences
 label.original_data_for_params = Original Data for {0}
 label.points_for_params = Points for {0}
@@ -1401,6 +1407,7 @@ label.create_image_of = Create {0} image of {1}
 label.click_to_edit = Click to edit, right-click for menu
 label.by_annotation_tooltip = Annotation Colour is configured from the main Colour menu
 label.show_linked_features = Show {0} features
+label.show_linked_feature_settings = Open {0} settings
 label.on_top = on top
 label.include_linked_features = Include {0} features
 label.include_linked_tooltip = Include visible {0} features<br>converted to local sequence coordinates
\ No newline at end of file
index 86e61e7..6549d64 100644 (file)
@@ -23,6 +23,8 @@ package jalview.api;
 import jalview.commands.CommandI;
 import jalview.schemes.ColourSchemeI;
 
+import java.awt.Rectangle;
+
 /**
  * Interface implemented by gui implementations managing a Jalview Alignment
  * View
@@ -62,4 +64,25 @@ public interface AlignViewControllerGuiI
    * @return
    */
   FeatureSettingsControllerI getFeatureSettingsUI();
+
+  /**
+   * displays the Feature Settigns control panel for the alignment view - if one
+   * exists it is closed and re-opened.
+   * 
+   * @return the current feature settings controller
+   */
+  FeatureSettingsControllerI showFeatureSettingsUI();
+
+  /**
+   * record the last position of a feature settings dialog before it was closed
+   * 
+   * @param bounds
+   */
+  void setFeatureSettingsGeometry(Rectangle bounds);
+
+  /**
+   * 
+   * @return last position of feature settings for this alignment view GUI
+   */
+  Rectangle getFeatureSettingsGeometry();
 }
index 46f5f44..6b037f5 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.api;
 
+import jalview.controller.FeatureSettingsControllerGuiI;
 import jalview.datamodel.AlignmentI;
 
 /**
@@ -55,4 +56,41 @@ public interface SplitContainerI
    */
   String getComplementTitle(Object af);
 
+  /**
+   * get the 'other' alignFrame in the SplitFrame
+   * 
+   * @param alignFrame
+   * @return the complement alignFrame - or null if alignFrame wasn't held by this
+   *         frame
+   */
+  AlignViewControllerGuiI getComplementAlignFrame(
+          AlignViewControllerGuiI alignFrame);
+
+  /**
+   * add the given UI to the splitframe's feature settings UI holder
+   * 
+   * @param featureSettings
+   * @return
+   */
+  void addFeatureSettingsUI(
+          FeatureSettingsControllerGuiI featureSettings);
+
+  /**
+   * Request to close all feature settings originating from a particular panel.
+   * 
+   * @param featureSettings
+   * @param closeContainingFrame
+   *                               - if false then the tab containing the feature
+   *                               settings will be 'reset' ready for a new
+   *                               feature settings
+   */
+  void closeFeatureSettings(FeatureSettingsControllerI featureSettings,
+          boolean closeContainingFrame);
+
+  /**
+   * 
+   * @return true if a feature settings panel is currently open
+   */
+  boolean isFeatureSettingsOpen();
+
 }
index 3bb5fe8..0bc45e2 100644 (file)
@@ -95,6 +95,7 @@ import java.awt.Menu;
 import java.awt.MenuBar;
 import java.awt.MenuItem;
 import java.awt.Panel;
+import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.FocusEvent;
@@ -1203,7 +1204,7 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     }
     else if (source == featureSettings)
     {
-      new FeatureSettings(alignPanel);
+      showFeatureSettingsUI();
     }
     else if (source == alProperties)
     {
@@ -4338,4 +4339,24 @@ public class AlignFrame extends EmbmenuFrame implements ActionListener,
     return alignPanel.av.featureSettings;
   }
 
+  @Override
+  public FeatureSettingsControllerI showFeatureSettingsUI()
+  {
+    return new FeatureSettings(alignPanel);
+  }
+
+  private Rectangle fs_bounds = null;
+
+  @Override
+  public void setFeatureSettingsGeometry(Rectangle bounds)
+  {
+    fs_bounds = bounds;
+  }
+
+  @Override
+  public Rectangle getFeatureSettingsGeometry()
+  {
+    return fs_bounds;
+  }
+
 }
index 728612e..92571bc 100644 (file)
  */
 package jalview.controller;
 
+import jalview.api.AlignViewControllerGuiI;
+
 public interface FeatureSettingsControllerGuiI
 {
 
+  AlignViewControllerGuiI getAlignframe();
+
+  void featureSettings_isClosed();
+
+  /**
+   * undo any changes made to feature settings whilst the dialog has been visible,
+   * since the last 'apply'
+   */
+  void revert();
+
 }
index fcb6572..b7d8b3a 100644 (file)
@@ -1479,9 +1479,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           closeView(alignPanel);
         }
       }
-
       if (closeAllTabs)
       {
+        if (featureSettings != null && featureSettings.isOpen())
+        {
+          featureSettings.close();
+          featureSettings = null;
+        }
         /*
          * this will raise an INTERNAL_FRAME_CLOSED event and this method will
          * be called recursively, with the frame now in 'closed' state
@@ -3187,9 +3191,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void featureSettings_actionPerformed(ActionEvent e)
   {
+    showFeatureSettingsUI();
+  }
+
+  @Override
+  public FeatureSettingsControllerI showFeatureSettingsUI()
+  {
     if (featureSettings != null)
     {
-      featureSettings.close();
+      featureSettings.closeOldSettings();
       featureSettings = null;
     }
     if (!showSeqFeatures.isSelected())
@@ -3199,6 +3209,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       showSeqFeatures_actionPerformed(null);
     }
     featureSettings = new FeatureSettings(this);
+    return featureSettings;
   }
 
   /**
@@ -4683,7 +4694,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           {
             if (parseFeaturesFile(file, sourceType))
             {
-              alignPanel.paintAlignment(true, true);
+              SplitFrame splitFrame = (SplitFrame) getSplitViewContainer();
+              if (splitFrame != null)
+              {
+                splitFrame.repaint();
+              }
+              else
+              {
+                alignPanel.paintAlignment(true, true);
+              }
             }
           }
           else
@@ -4739,6 +4758,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       viewport = alignPanel.av;
       avc.setViewportAndAlignmentPanel(viewport, alignPanel);
       setMenusFromViewport(viewport);
+      if (featureSettings != null && featureSettings.isOpen()
+              && featureSettings.fr.getViewport() != viewport)
+      {
+        if (viewport.isShowSequenceFeatures())
+        {
+          // refresh the featureSettings to reflect UI change
+          showFeatureSettingsUI();
+        }
+        else
+        {
+          // close feature settings for this view.
+          featureSettings.close();
+        }
+      }
+
     }
 
     /*
@@ -5658,6 +5692,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
 
   }
+
+  private Rectangle lastFeatureSettingsBounds = null;
+  @Override
+  public void setFeatureSettingsGeometry(Rectangle bounds)
+  {
+    lastFeatureSettingsBounds = bounds;
+  }
+
+  @Override
+  public Rectangle getFeatureSettingsGeometry()
+  {
+    return lastFeatureSettingsBounds;
+  }
 }
 
 class PrintThread extends Thread
index 61b0d1b..888ffcd 100644 (file)
@@ -79,9 +79,9 @@ public class AlignViewport extends AlignmentViewport
 
   boolean antiAlias = false;
 
-  private Rectangle explodedGeometry;
+  private Rectangle explodedGeometry = null;
 
-  private String viewName;
+  private String viewName = null;
 
   /*
    * Flag set true on the view that should 'gather' multiple views of the same
@@ -208,7 +208,7 @@ public class AlignViewport extends AlignmentViewport
    */
   private void applyViewProperties()
   {
-    antiAlias = Cache.getDefault("ANTI_ALIAS", false);
+    antiAlias = Cache.getDefault("ANTI_ALIAS", true);
 
     viewStyle.setShowJVSuffix(Cache.getDefault("SHOW_JVSUFFIX", true));
     setShowAnnotation(Cache.getDefault("SHOW_ANNOTATIONS", true));
index 1ec6939..1b8dda7 100644 (file)
@@ -1923,11 +1923,28 @@ public class Desktop extends jalview.jbgui.GDesktop
       return;
     }
 
+    // FIXME: ideally should use UI interface API
+    FeatureSettings viewFeatureSettings = (af.featureSettings != null
+            && af.featureSettings.isOpen())
+            ? af.featureSettings
+            : null;
+    Rectangle fsBounds = af.getFeatureSettingsGeometry();
     for (int i = 0; i < size; i++)
     {
       AlignmentPanel ap = af.alignPanels.get(i);
+
       AlignFrame newaf = new AlignFrame(ap);
 
+      // transfer reference for existing feature settings to new alignFrame
+      if (ap == af.alignPanel)
+      {
+        if (viewFeatureSettings != null && viewFeatureSettings.fr.ap == ap)
+        {
+          newaf.featureSettings = viewFeatureSettings;
+        }
+        newaf.setFeatureSettingsGeometry(fsBounds);
+      }
+
       /*
        * Restore the view's last exploded frame geometry if known. Multiple
        * views from one exploded frame share and restore the same (frame)
@@ -1943,8 +1960,17 @@ public class Desktop extends jalview.jbgui.GDesktop
 
       addInternalFrame(newaf, af.getTitle(), AlignFrame.DEFAULT_WIDTH,
               AlignFrame.DEFAULT_HEIGHT);
+      // and materialise a new feature settings dialog instance for the new alignframe
+      // (closes the old as if 'OK' was pressed)
+      if (ap == af.alignPanel && newaf.featureSettings != null
+              && newaf.featureSettings.isOpen()
+              && af.alignPanel.getAlignViewport().isShowSequenceFeatures())
+      {
+        newaf.showFeatureSettingsUI();
+      }
     }
 
+    af.featureSettings = null;
     af.alignPanels.clear();
     af.closeMenuItem_actionPerformed(true);
 
@@ -1964,7 +1990,6 @@ public class Desktop extends jalview.jbgui.GDesktop
     source.viewport.setExplodedGeometry(source.getBounds());
     JInternalFrame[] frames = desktop.getAllFrames();
     String viewId = source.viewport.getSequenceSetId();
-
     for (int t = 0; t < frames.length; t++)
     {
       if (frames[t] instanceof AlignFrame && frames[t] != source)
@@ -1985,11 +2010,32 @@ public class Desktop extends jalview.jbgui.GDesktop
 
         if (gatherThis)
         {
+          if (af.featureSettings != null && af.featureSettings.isOpen())
+          {
+            if (source.featureSettings == null)
+            {
+              // preserve the feature settings geometry for this frame
+              source.featureSettings = af.featureSettings;
+              source.setFeatureSettingsGeometry(
+                      af.getFeatureSettingsGeometry());
+            }
+            else
+            {
+              // close it and forget
+              af.featureSettings.close();
+            }
+          }
           af.alignPanels.clear();
           af.closeMenuItem_actionPerformed(true);
         }
       }
     }
+    // refresh the feature setting UI for the source frame if it exists
+    if (source.featureSettings != null
+            && source.featureSettings.isOpen())
+    {
+      source.showFeatureSettingsUI();
+    }
 
   }
 
index 11d5e39..3efc63e 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewportI;
 import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
+import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
+import jalview.controller.FeatureSettingsControllerGuiI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.features.FeatureMatcher;
@@ -79,6 +82,7 @@ import java.util.Map;
 import java.util.Set;
 
 import javax.help.HelpSetException;
+import javax.swing.AbstractButton;
 import javax.swing.AbstractCellEditor;
 import javax.swing.BorderFactory;
 import javax.swing.Icon;
@@ -112,7 +116,7 @@ import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamReader;
 
 public class FeatureSettings extends JPanel
-        implements FeatureSettingsControllerI
+        implements FeatureSettingsControllerI, FeatureSettingsControllerGuiI
 {
   private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
           .getString("label.sequence_feature_colours");
@@ -180,6 +184,26 @@ public class FeatureSettings extends JPanel
    */
   Map<String, float[]> typeWidth = null;
 
+  private void storeOriginalSettings()
+  {
+    // save transparency for restore on Cancel
+    originalTransparency = fr.getTransparency();
+
+    updateTransparencySliderFromFR();
+
+    originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
+    originalViewStyle = new ViewStyle(af.viewport.getViewStyle());
+  }
+
+  private void updateTransparencySliderFromFR()
+  {
+    boolean incon = inConstruction;
+    inConstruction = true;
+
+    int transparencyAsPercent = (int) (fr.getTransparency() * 100);
+    transparency.setValue(100 - transparencyAsPercent);
+    inConstruction = incon;
+  }
   /**
    * Constructor
    * 
@@ -190,13 +214,7 @@ public class FeatureSettings extends JPanel
     this.af = alignFrame;
     fr = af.getFeatureRenderer();
 
-    // save transparency for restore on Cancel
-    originalTransparency = fr.getTransparency();
-    int originalTransparencyAsPercent = (int) (originalTransparency * 100);
-    transparency.setMaximum(100 - originalTransparencyAsPercent);
-
-    originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
-    originalViewStyle = new ViewStyle(af.viewport.getViewStyle());
+    storeOriginalSettings();
 
     try
     {
@@ -356,7 +374,6 @@ public class FeatureSettings extends JPanel
     }
 
     discoverAllFeatureData();
-    final PropertyChangeListener change;
     final FeatureSettings fs = this;
     fr.addPropertyChangeListener(change = new PropertyChangeListener()
     {
@@ -373,37 +390,90 @@ public class FeatureSettings extends JPanel
       }
 
     });
-
-    frame = new JInternalFrame();
-    frame.setContentPane(this);
-    if (Platform.isAMac())
+    SplitContainerI splitframe = af.getSplitViewContainer();
+    if (splitframe != null)
     {
-      Desktop.addInternalFrame(frame,
-              MessageManager.getString("label.sequence_feature_settings"),
-              600, 480);
+      frame = null; // keeps eclipse happy
+      splitframe.addFeatureSettingsUI(this);
     }
     else
     {
-      Desktop.addInternalFrame(frame,
-              MessageManager.getString("label.sequence_feature_settings"),
-              600, 450);
-    }
-    frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
+      frame = new JInternalFrame();
+      frame.setContentPane(this);
+      Rectangle bounds = af.getFeatureSettingsGeometry();
+      String title;
+      if (af.getAlignPanels().size() > 1 || Desktop.getAlignmentPanels(
+              af.alignPanel.av.getSequenceSetId()).length > 1)
+      {
+        title = MessageManager.formatMessage(
+                "label.sequence_feature_settings_for_view",
+                af.alignPanel.getViewName());
+      }
+      else
+      {
+        title = MessageManager.getString("label.sequence_feature_settings");
+      }
+      if (bounds == null)
+      {
+        if (Platform.isAMac())
+        {
+          Desktop.addInternalFrame(frame, title, 600, 480);
+        }
+        else
+        {
+          Desktop.addInternalFrame(frame, title, 600, 450);
+        }
+      }
+      else
+      {
+        Desktop.addInternalFrame(frame, title,
+                false, bounds.width, bounds.height);
+        frame.setBounds(bounds);
+        frame.setVisible(true);
+      }
+      frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
 
-    frame.addInternalFrameListener(
-            new javax.swing.event.InternalFrameAdapter()
-            {
-              @Override
-              public void internalFrameClosed(
-                      javax.swing.event.InternalFrameEvent evt)
+      frame.addInternalFrameListener(
+              new javax.swing.event.InternalFrameAdapter()
               {
-                fr.removePropertyChangeListener(change);
-              };
-            });
-    frame.setLayer(JLayeredPane.PALETTE_LAYER);
+                @Override
+                public void internalFrameClosed(
+                        javax.swing.event.InternalFrameEvent evt)
+                {
+                  featureSettings_isClosed();
+                };
+              });
+      frame.setLayer(JLayeredPane.PALETTE_LAYER);
+    }
     inConstruction = false;
   }
 
+  PropertyChangeListener change;
+
+  private JCheckBox showComplementOnTop;
+
+  private AbstractButton showComplement;
+
+  private void updateComplementButtons()
+  {
+    showComplement.setSelected(af.getViewport().isShowComplementFeatures());
+    showComplementOnTop
+            .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
+  }
+
+  @Override
+  public AlignViewControllerGuiI getAlignframe()
+  {
+    return af;
+  }
+
+  @Override
+  public void featureSettings_isClosed()
+  {
+    fr.removePropertyChangeListener(change);
+    change = null;
+  }
+
   protected void popupSort(final int rowSelected, final String type,
           final Object typeCol, final Map<String, float[][]> minmax, int x,
           int y)
@@ -1079,11 +1149,38 @@ public class FeatureSettings extends JPanel
     table.repaint();
   }
 
+  /**
+   * close ourselves but leave any existing UI handlers (e.g a CDS/Protein tabbed
+   * feature settings dialog) intact
+   */
+  public void closeOldSettings()
+  {
+    closeDialog(false);
+  }
+
+  /**
+   * close the feature settings dialog (and any containing frame)
+   */
   public void close()
   {
+    closeDialog(true);
+  }
+
+  private void closeDialog(boolean closeContainingFrame)
+  {
     try
     {
-      frame.setClosed(true);
+      if (frame != null)
+      {
+        af.setFeatureSettingsGeometry(frame.getBounds());
+        frame.setClosed(true);
+      }
+      else
+      {
+        SplitContainerI sc = af.getSplitViewContainer();
+        sc.closeFeatureSettings(this, closeContainingFrame);
+        af.featureSettings = null;
+      }
     } catch (Exception exe)
     {
     }
@@ -1134,6 +1231,9 @@ public class FeatureSettings extends JPanel
   {
     this.setLayout(new BorderLayout());
 
+    final boolean hasComplement = af.getViewport()
+            .getCodingComplement() != null;
+
     JPanel settingsPane = new JPanel();
     settingsPane.setLayout(new BorderLayout());
 
@@ -1206,30 +1306,48 @@ public class FeatureSettings extends JPanel
         }
       }
     });
-
-    JButton cancel = new JButton(MessageManager.getString("action.cancel"));
+    // Cancel for a SplitFrame should just revert changes to the currently displayed
+    // settings. May want to do this for either or both - so need a splitview
+    // feature settings cancel/OK.
+    JButton cancel = new JButton(MessageManager
+            .getString(hasComplement ? "action.revert" : "action.cancel"));
+    cancel.setToolTipText(MessageManager.getString(hasComplement
+            ? "action.undo_changes_to_feature_settings"
+            : "action.undo_changes_to_feature_settings_and_close_the_dialog"));
     cancel.setFont(JvSwingUtils.getLabelFont());
+    // TODO: disable cancel (and apply!) until current settings are different
     cancel.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        fr.setTransparency(originalTransparency);
-        fr.setFeatureFilters(originalFilters);
-        updateFeatureRenderer(originalData);
-        af.getViewport().setViewStyle(originalViewStyle);
-        close();
+        revert();
+        refreshDisplay();
+        if (!hasComplement)
+        {
+          close();
+        }
       }
     });
-
-    JButton ok = new JButton(MessageManager.getString("action.ok"));
+    // Cancel for the whole dialog should cancel both CDS and Protein.
+    // OK for an individual feature settings just applies changes, but dialog
+    // remains open
+    JButton ok = new JButton(MessageManager
+            .getString(hasComplement ? "action.apply" : "action.ok"));
     ok.setFont(JvSwingUtils.getLabelFont());
     ok.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        close();
+        if (!hasComplement)
+        {
+          close();
+        }
+        else
+        {
+          storeOriginalSettings();
+        }
       }
     });
 
@@ -1283,8 +1401,7 @@ public class FeatureSettings extends JPanel
                     ? MessageManager.getString("label.protein")
                             .toLowerCase()
                     : "CDS");
-    JCheckBox showComplement = new JCheckBox(text);
-    showComplement.setSelected(af.getViewport().isShowComplementFeatures());
+    showComplement = new JCheckBox(text);
     showComplement.addActionListener(new ActionListener()
     {
       @Override
@@ -1296,10 +1413,8 @@ public class FeatureSettings extends JPanel
       }
     });
 
-    JCheckBox showComplementOnTop = new JCheckBox(
+    showComplementOnTop = new JCheckBox(
             MessageManager.getString("label.on_top"));
-    showComplementOnTop
-            .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
     showComplementOnTop.addActionListener(new ActionListener()
     {
       @Override
@@ -1310,7 +1425,38 @@ public class FeatureSettings extends JPanel
         refreshDisplay();
       }
     });
-
+    // JButton viewComplementSettings = new JButton(MessageManager
+    // .formatMessage("label.show_linked_feature_settings",
+    // nucleotide
+    // ? MessageManager.getString("label.protein")
+    // .toLowerCase()
+    // : "CDS"));
+    // viewComplementSettings.addActionListener(new ActionListener()
+    // {
+    //
+    // @Override
+    // public void actionPerformed(ActionEvent e)
+    // {
+    // AlignViewControllerGuiI complAf = af.getSplitViewContainer()
+    // .getComplementAlignFrame(af);
+    // FeatureSettings complFeatureSettings = (FeatureSettings) complAf
+    // .getFeatureSettingsUI();
+    // if (complFeatureSettings != null)
+    // {
+    // complFeatureSettings.frame.setVisible(true);
+    // try
+    // {
+    // complFeatureSettings.frame.setSelected(true);
+    // return;
+    // } catch (Exception q)
+    // {
+    // }
+    // }
+    // {
+    // complAf.showFeatureSettingsUI();
+    // }
+    // }
+    // });
     JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
     bigPanel.add(lowerPanel, BorderLayout.SOUTH);
 
@@ -1321,9 +1467,8 @@ public class FeatureSettings extends JPanel
     transbuttons.add(sortByDens);
     transbuttons.add(help);
 
-    boolean hasComplement = af.getViewport().getCodingComplement() != null;
     JPanel transPanelLeft = new JPanel(
-            new GridLayout(hasComplement ? 3 : 2, 1));
+            new GridLayout(hasComplement ? 4 : 2, 1));
     transPanelLeft.add(new JLabel(" Colour transparency" + ":"));
     transPanelLeft.add(transparency);
     if (hasComplement)
@@ -1903,6 +2048,27 @@ public class FeatureSettings extends JPanel
       return button;
     }
   }
+
+  public boolean isOpen()
+  {
+    if (af.getSplitViewContainer() != null)
+    {
+      return af.getSplitViewContainer().isFeatureSettingsOpen();
+    }
+    return frame != null && !frame.isClosed();
+  }
+
+  @Override
+  public void revert()
+  {
+    fr.setTransparency(originalTransparency);
+    fr.setFeatureFilters(originalFilters);
+    updateFeatureRenderer(originalData);
+    af.getViewport().setViewStyle(originalViewStyle);
+    updateTransparencySliderFromFR();
+    updateComplementButtons();
+    refreshDisplay();
+  }
 }
 
 class FeatureIcon implements Icon
index 9754e0d..0d7d1b4 100755 (executable)
@@ -253,7 +253,7 @@ public class Preferences extends GPreferences
     fontStyleCB.setSelectedItem(
             Cache.getDefault("FONT_STYLE", Font.PLAIN + ""));
 
-    smoothFont.setSelected(Cache.getDefault("ANTI_ALIAS", false));
+    smoothFont.setSelected(Cache.getDefault("ANTI_ALIAS", true));
     scaleProteinToCdna
             .setSelected(Cache.getDefault(SCALE_PROTEIN_TO_CDNA, false));
 
@@ -401,7 +401,7 @@ public class Preferences extends GPreferences
     doReset.addActionListener(onReset);
 
     // filter to display only custom urls
-    final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<TableModel, Object>()
+    final RowFilter<TableModel, Object> customUrlFilter = new RowFilter<>()
     {
       @Override
       public boolean include(
index 25dedc5..1fad9ae 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.AlignViewControllerGuiI;
+import jalview.api.FeatureSettingsControllerI;
 import jalview.api.SplitContainerI;
+import jalview.controller.FeatureSettingsControllerGuiI;
 import jalview.datamodel.AlignmentI;
 import jalview.jbgui.GAlignFrame;
 import jalview.jbgui.GSplitFrame;
 import jalview.structure.StructureSelectionManager;
+import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
 
+import java.awt.BorderLayout;
 import java.awt.Component;
+import java.awt.Dimension;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyAdapter;
@@ -41,11 +47,17 @@ import java.util.Map.Entry;
 
 import javax.swing.AbstractAction;
 import javax.swing.InputMap;
+import javax.swing.JButton;
 import javax.swing.JComponent;
 import javax.swing.JDesktopPane;
 import javax.swing.JInternalFrame;
+import javax.swing.JLayeredPane;
 import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JTabbedPane;
 import javax.swing.KeyStroke;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 import javax.swing.event.InternalFrameAdapter;
 import javax.swing.event.InternalFrameEvent;
 
@@ -75,6 +87,13 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
 
   private static final long serialVersionUID = 1L;
 
+  /**
+   * geometry for Feature Settings Holder
+   */
+  private static final int FS_MIN_WIDTH = 400;
+
+  private static final int FS_MIN_HEIGHT = 400;
+
   public SplitFrame(GAlignFrame top, GAlignFrame bottom)
   {
     super(top, bottom);
@@ -763,6 +782,22 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
             { (AlignFrame) getTopFrame(), (AlignFrame) getBottomFrame() });
   }
 
+  @Override
+  public AlignFrame getComplementAlignFrame(
+          AlignViewControllerGuiI alignFrame)
+  {
+    if (getTopFrame() == alignFrame)
+    {
+      return (AlignFrame) getBottomFrame();
+    }
+    if (getBottomFrame() == alignFrame)
+    {
+      return (AlignFrame) getTopFrame();
+    }
+    // we didn't know anything about this frame...
+    return null;
+  }
+
   /**
    * Replace Cmd-F Find action with our version. This is necessary because the
    * 'default' Finder searches in the first AlignFrame it finds. We need it to
@@ -815,4 +850,259 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     }
     super.setSelected(selected);
   }
-}
+
+  /**
+   * holds the frame for feature settings, so Protein and DNA tabs can be managed
+   */
+  JInternalFrame featureSettingsUI;
+
+  JTabbedPane featureSettingsPanels;
+
+  @Override
+  public void addFeatureSettingsUI(
+          FeatureSettingsControllerGuiI featureSettings)
+  {
+    boolean showInternalFrame = false;
+    if (featureSettingsUI == null || featureSettingsPanels == null)
+    {
+      showInternalFrame = true;
+      featureSettingsPanels = new JTabbedPane();
+      featureSettingsPanels.addChangeListener(new ChangeListener()
+      {
+
+        @Override
+        public void stateChanged(ChangeEvent e)
+        {
+          if (e.getSource() != featureSettingsPanels
+                  || featureSettingsUI == null
+                  || featureSettingsUI.isClosed()
+                  || !featureSettingsUI.isVisible())
+          {
+            // not our tabbed pane
+            return;
+          }
+          int tab = featureSettingsPanels.getSelectedIndex();
+          if (tab < 0 || featureSettingsPanels
+                  .getSelectedComponent() instanceof FeatureSettingsControllerGuiI)
+          {
+            // no tab selected or already showing a feature settings GUI
+            return;
+          }
+          getAlignFrames().get(tab).showFeatureSettingsUI();
+        }
+      });
+      featureSettingsUI = new JInternalFrame(MessageManager.getString(
+              "label.sequence_feature_settings_for_CDS_and_Protein"));
+      featureSettingsPanels.setOpaque(true);
+
+      JPanel dialog = new JPanel();
+      dialog.setOpaque(true);
+      dialog.setLayout(new BorderLayout());
+      dialog.add(featureSettingsPanels, BorderLayout.CENTER);
+      JPanel buttons = new JPanel();
+      JButton ok = new JButton(MessageManager.getString("action.ok"));
+      ok.addActionListener(new ActionListener()
+      {
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          try
+          {
+            featureSettingsUI.setClosed(true);
+          } catch (PropertyVetoException pv)
+          {
+            pv.printStackTrace();
+          }
+        }
+      });
+      JButton cancel = new JButton(
+              MessageManager.getString("action.cancel"));
+      cancel.addActionListener(new ActionListener()
+      {
+
+        @Override
+        public void actionPerformed(ActionEvent e)
+        {
+          try
+          {
+            for (Component fspanel : featureSettingsPanels.getComponents())
+            {
+              if (fspanel instanceof FeatureSettingsControllerGuiI)
+              {
+                ((FeatureSettingsControllerGuiI) fspanel).revert();
+              }
+            }
+            featureSettingsUI.setClosed(true);
+          } catch (Exception pv)
+          {
+            pv.printStackTrace();
+          }
+        }
+      });
+      buttons.add(ok);
+      buttons.add(cancel);
+      dialog.add(buttons, BorderLayout.SOUTH);
+      featureSettingsUI.setContentPane(dialog);
+      createDummyTabs();
+    }
+    if (featureSettingsPanels
+            .indexOfTabComponent((Component) featureSettings) > -1)
+    {
+      // just show the feature settings !
+      featureSettingsPanels
+              .setSelectedComponent((Component) featureSettings);
+      return;
+    }
+    // otherwise replace the dummy tab with the given feature settings
+    int pos = getAlignFrames().indexOf(featureSettings.getAlignframe());
+    // if pos==-1 then alignFrame isn't managed by this splitframe
+    if (pos == 0)
+    {
+      featureSettingsPanels.removeTabAt(0);
+      featureSettingsPanels.insertTab(tabName[0], null,
+              (Component) featureSettings,
+              MessageManager.formatMessage(
+                      "label.sequence_feature_settings_for", tabName[0]),
+              0);
+    }
+    if (pos == 1)
+    {
+      featureSettingsPanels.removeTabAt(1);
+      featureSettingsPanels.insertTab(tabName[1], null,
+              (Component) featureSettings,
+              MessageManager.formatMessage(
+                      "label.sequence_feature_settings_for", tabName[1]),
+              1);
+    }
+    featureSettingsPanels.setSelectedComponent((Component) featureSettings);
+
+    // TODO: JAL-3535 - construct a feature settings title including names of
+    // currently selected CDS and Protein names
+
+    if (showInternalFrame)
+    {
+      if (Platform.isAMac())
+      {
+        Desktop.addInternalFrame(featureSettingsUI,
+                MessageManager.getString(
+                        "label.sequence_feature_settings_for_CDS_and_Protein"),
+                600, 480);
+      }
+      else
+      {
+        Desktop.addInternalFrame(featureSettingsUI,
+                MessageManager.getString(
+                        "label.sequence_feature_settings_for_CDS_and_Protein"),
+                600, 450);
+      }
+      featureSettingsUI
+              .setMinimumSize(new Dimension(FS_MIN_WIDTH, FS_MIN_HEIGHT));
+
+      featureSettingsUI.addInternalFrameListener(
+              new javax.swing.event.InternalFrameAdapter()
+              {
+                @Override
+                public void internalFrameClosed(
+                        javax.swing.event.InternalFrameEvent evt)
+                {
+                  for (int tab = 0; tab < featureSettingsPanels
+                          .getTabCount();)
+                  {
+                    FeatureSettingsControllerGuiI fsettings = (FeatureSettingsControllerGuiI) featureSettingsPanels
+                            .getTabComponentAt(tab);
+                    if (fsettings != null)
+                    {
+                      featureSettingsPanels.removeTabAt(tab);
+                      fsettings.featureSettings_isClosed();
+                    }
+                    else
+                    {
+                      tab++;
+                    }
+                  }
+                  featureSettingsPanels = null;
+                  featureSettingsUI = null;
+                };
+              });
+      featureSettingsUI.setLayer(JLayeredPane.PALETTE_LAYER);
+    }
+  }
+
+  /**
+   * tab names for feature settings
+   */
+  private String[] tabName = new String[] {
+      MessageManager.getString("label.CDS"),
+      MessageManager.getString("label.protein") };
+
+  /**
+   * create placeholder tabs which materialise the feature settings for a given
+   * view. Also reinitialises any tabs containing stale feature settings
+   */
+  private void createDummyTabs()
+  {
+    for (int tabIndex = 0; tabIndex < 2; tabIndex++)
+    {
+      JPanel dummyTab = new JPanel();
+      featureSettingsPanels.addTab(tabName[tabIndex], dummyTab);
+    }
+  }
+
+  private void replaceWithDummyTab(FeatureSettingsControllerI toClose)
+  {
+    Component dummyTab = null;
+    for (int tabIndex = 0; tabIndex < 2; tabIndex++)
+    {
+      if (featureSettingsPanels.getTabCount() > tabIndex)
+      {
+        dummyTab = featureSettingsPanels.getTabComponentAt(tabIndex);
+        if (dummyTab instanceof FeatureSettingsControllerGuiI
+                && !dummyTab.isVisible())
+        {
+          featureSettingsPanels.removeTabAt(tabIndex);
+          // close the feature Settings tab
+          ((FeatureSettingsControllerGuiI) dummyTab)
+                  .featureSettings_isClosed();
+          // create a dummy tab in its place
+          dummyTab = new JPanel();
+          featureSettingsPanels.insertTab(tabName[tabIndex], null, dummyTab,
+                  MessageManager.formatMessage(
+                          "label.sequence_feature_settings_for",
+                          tabName[tabIndex]),
+                  tabIndex);
+        }
+      }
+    }
+  }
+
+  @Override
+  public void closeFeatureSettings(
+          FeatureSettingsControllerI featureSettings,
+          boolean closeContainingFrame)
+  {
+    if (featureSettingsUI != null)
+    {
+      if (closeContainingFrame)
+      {
+        try
+        {
+          featureSettingsUI.setClosed(true);
+        } catch (Exception x)
+        {
+        }
+        featureSettingsUI = null;
+      }
+      else
+      {
+        replaceWithDummyTab(featureSettings);
+      }
+    }
+  }
+
+  @Override
+  public boolean isFeatureSettingsOpen()
+  {
+    return featureSettingsUI != null && !featureSettingsUI.isClosed();
+  }
+}
\ No newline at end of file
index 3494181..25e10c3 100644 (file)
@@ -92,12 +92,26 @@ public class MessageManager
 
   public static String formatMessage(String key, Object... params)
   {
-    return MessageFormat.format(rb.getString(key), params);
+    try
+    {
+      return MessageFormat.format(rb.getString(key), params);
+    } catch (Exception e)
+    {
+      log.warning("I18N missing: " + loc + "\t" + key);
+      // e.printStackTrace();
+
+    }
+    String value = "[missing key] " + key + "";
+    for (Object p : params)
+    {
+      value += " '" + p.toString() + "'";
+    }
+    return value;
   }
 
   public static String formatMessage(String key, String[] params)
   {
-    return MessageFormat.format(rb.getString(key), (Object[]) params);
+    return formatMessage(key, (Object[]) params);
   }
 
   /**