Merge branch 'bug/JAL-3490findSpanHiddenGaps' into patch/Release_2_11_1_Branch_patch_...
[jalview.git] / src / jalview / gui / SplitFrame.java
index 5889489..f7c93db 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);
@@ -161,26 +180,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
@@ -763,6 +777,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 +845,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