Merge branch 'alpha/JAL-3362_Jalview_212_alpha' into alpha/merge_212_JalviewJS_2112
[jalview.git] / src / jalview / gui / SplitFrame.java
index 6d5bd34..81f0134 100644 (file)
@@ -20,6 +20,7 @@
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.api.SplitContainerI;
@@ -32,12 +33,11 @@ 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.FocusEvent;
-import java.awt.event.FocusListener;
 import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
@@ -48,6 +48,7 @@ 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;
@@ -56,6 +57,8 @@ 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;
 
@@ -115,9 +118,9 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
      * estimate width and height of SplitFrame; this.getInsets() doesn't seem to
      * give the full additional size (a few pixels short)
      */
-    int widthFudge = Platform.isAMac() ? MAC_INSETS_WIDTH
+    int widthFudge = Platform.isAMacAndNotJS() ? MAC_INSETS_WIDTH
             : WINDOWS_INSETS_WIDTH;
-    int heightFudge = Platform.isAMac() ? MAC_INSETS_HEIGHT
+    int heightFudge = Platform.isAMacAndNotJS() ? MAC_INSETS_HEIGHT
             : WINDOWS_INSETS_HEIGHT;
     int width = ((AlignFrame) getTopFrame()).getWidth() + widthFudge;
     int height = ((AlignFrame) getTopFrame()).getHeight()
@@ -178,26 +181,21 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
    */
   public void adjustLayout()
   {
+    final AlignViewport topViewport = ((AlignFrame) getTopFrame()).viewport;
+    final AlignViewport bottomViewport = ((AlignFrame) getBottomFrame()).viewport;
+
     /*
      * Ensure sequence ids are the same width so sequences line up
      */
-    int w1 = ((AlignFrame) getTopFrame()).getViewport().getIdWidth();
-    int w2 = ((AlignFrame) getBottomFrame()).getViewport().getIdWidth();
+    int w1 = topViewport.getIdWidth();
+    int w2 = bottomViewport.getIdWidth();
     int w3 = Math.max(w1, w2);
-    if (w1 != w3)
-    {
-      ((AlignFrame) getTopFrame()).getViewport().setIdWidth(w3);
-    }
-    if (w2 != w3)
-    {
-      ((AlignFrame) getBottomFrame()).getViewport().setIdWidth(w3);
-    }
+    topViewport.setIdWidth(w3);
+    bottomViewport.setIdWidth(w3);
 
     /*
      * Scale protein to either 1 or 3 times character width of dna
      */
-    final AlignViewport topViewport = ((AlignFrame) getTopFrame()).viewport;
-    final AlignViewport bottomViewport = ((AlignFrame) getBottomFrame()).viewport;
     final AlignmentI topAlignment = topViewport.getAlignment();
     final AlignmentI bottomAlignment = bottomViewport.getAlignment();
     AlignmentViewport cdna = topAlignment.isNucleotide() ? topViewport
@@ -233,8 +231,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     topFrame.alignPanel.adjustAnnotationHeight();
     bottomFrame.alignPanel.adjustAnnotationHeight();
 
-    final AlignViewport topViewport = topFrame.viewport;
-    final AlignViewport bottomViewport = bottomFrame.viewport;
+    final AlignViewportI topViewport = topFrame.viewport;
+    final AlignViewportI bottomViewport = bottomFrame.viewport;
     final AlignmentI topAlignment = topViewport.getAlignment();
     final AlignmentI bottomAlignment = bottomViewport.getAlignment();
     boolean topAnnotations = topViewport.isShowAnnotation();
@@ -271,7 +269,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     /*
      * estimate ratio of (topFrameContent / bottomFrameContent)
      */
-    int insets = Platform.isAMac() ? MAC_INSETS_HEIGHT
+    int insets = Platform.isAMacAndNotJS() ? MAC_INSETS_HEIGHT
             : WINDOWS_INSETS_HEIGHT;
     // allow 3 'rows' for scale, scrollbar, status bar
     int topHeight = insets + (3 + topCount) * topCharHeight
@@ -861,37 +859,88 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
           FeatureSettingsControllerGuiI featureSettings)
   {
     boolean showInternalFrame = false;
-    if (featureSettingsUI == null)
+    if (featureSettingsUI == null || featureSettingsPanels == null)
     {
       showInternalFrame = true;
       featureSettingsPanels = new JTabbedPane();
-      featureSettingsUI = new JInternalFrame(
-              "Feature Settings for CDS and Protein Views");
-      featureSettingsPanels.setOpaque(true);
-      featureSettingsUI.setContentPane(featureSettingsPanels);
-      JPanel dummyDNA = new JPanel(),dummyProtein=new JPanel();
-      FocusListener fl1 = new FocusListener()
+      featureSettingsPanels.addChangeListener(new ChangeListener()
       {
 
         @Override
-        public void focusLost(FocusEvent e)
+        public void stateChanged(ChangeEvent e)
         {
-          // TODO Auto-generated method stub
+          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 focusGained(FocusEvent e)
+        public void actionPerformed(ActionEvent e)
         {
-          int tab = featureSettingsPanels.getSelectedIndex();
-          getAlignFrames().get(tab).showFeatureSettingsUI();
+          try
+          {
+            for (Component fspanel : featureSettingsPanels.getComponents())
+            {
+              if (fspanel instanceof FeatureSettingsControllerGuiI)
+              {
+                ((FeatureSettingsControllerGuiI) fspanel).revert();
+              }
+            }
+            featureSettingsUI.setClosed(true);
+          } catch (Exception pv)
+          {
+            pv.printStackTrace();
+          }
         }
-      };
-      dummyDNA.addFocusListener(fl1);
-      dummyProtein.addFocusListener(fl1);
-      
-      featureSettingsPanels.addTab("CDS", dummyDNA);
-      featureSettingsPanels.addTab("Protein", dummyProtein);
+      });
+      buttons.add(ok);
+      buttons.add(cancel);
+      dialog.add(buttons, BorderLayout.SOUTH);
+      featureSettingsUI.setContentPane(dialog);
+      createDummyTabs();
     }
     if (featureSettingsPanels
             .indexOfTabComponent((Component) featureSettings) > -1)
@@ -907,32 +956,40 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     if (pos == 0)
     {
       featureSettingsPanels.removeTabAt(0);
-      featureSettingsPanels.insertTab("CDS", null,
-              (Component) featureSettings, "Feature Settings for DNA CDS",
+      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("Protein", null,
-              (Component) featureSettings, "Feature Settings for Protein",
+      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())
+      if (Platform.isAMacAndNotJS())
       {
         Desktop.addInternalFrame(featureSettingsUI,
                 MessageManager.getString(
-                        "Feature Settings for CDS and Protein Views"),
+                        "label.sequence_feature_settings_for_CDS_and_Protein"),
                 600, 480);
       }
       else
       {
         Desktop.addInternalFrame(featureSettingsUI,
                 MessageManager.getString(
-                        "Feature Settings for CDS and Protein Views"),
+                        "label.sequence_feature_settings_for_CDS_and_Protein"),
                 600, 450);
       }
       featureSettingsUI
@@ -953,7 +1010,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
                     if (fsettings != null)
                     {
                       featureSettingsPanels.removeTabAt(tab);
-                      fsettings.closeFeatureSettings();
+                      fsettings.featureSettings_isClosed();
                     }
                     else
                     {
@@ -961,25 +1018,87 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
                     }
                   }
                   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)
+          FeatureSettingsControllerI featureSettings,
+          boolean closeContainingFrame)
   {
     if (featureSettingsUI != null)
     {
-      try
+      if (closeContainingFrame)
       {
-        featureSettingsUI.setClosed(true);
-      } catch (Exception x)
+        try
+        {
+          featureSettingsUI.setClosed(true);
+        } catch (Exception x)
+        {
+        }
+        featureSettingsUI = null;
+      }
+      else
       {
+        replaceWithDummyTab(featureSettings);
       }
-      featureSettingsUI = null;
     }
   }
-}
\ No newline at end of file
+
+  @Override
+  public boolean isFeatureSettingsOpen()
+  {
+    return featureSettingsUI != null && !featureSettingsUI.isClosed();
+  }
+}