JAL-1815 restore split frame geometry correctly including position
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 25 Sep 2015 10:46:11 +0000 (11:46 +0100)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 25 Sep 2015 10:46:11 +0000 (11:46 +0100)
src/jalview/gui/Desktop.java
src/jalview/gui/Jalview2XML.java
src/jalview/gui/SplitFrame.java
src/jalview/jbgui/GSplitFrame.java

index 270805a..d03e3f2 100644 (file)
@@ -2933,7 +2933,11 @@ public class Desktop extends jalview.jbgui.GDesktop implements
   }
 
   /**
-   * Explode the views in the given frame into separate AlignFrame windows.
+   * Explode the views in the given SplitFrame into separate SplitFrame windows.
+   * This respects (remembers) any previous 'exploded geometry' i.e. the size
+   * and location last time the view was expanded (if any). However it does not
+   * remember the split pane divider location - this is set to match the
+   * 'exploding' frame.
    * 
    * @param sf
    */
@@ -2965,13 +2969,11 @@ public class Desktop extends jalview.jbgui.GDesktop implements
        */
       AlignmentPanel topPanel = (AlignmentPanel) topPanels.get(i);
       AlignFrame newTopFrame = new AlignFrame(topPanel);
-      newTopFrame.setSize(new Dimension(AlignFrame.DEFAULT_WIDTH,
-              AlignFrame.DEFAULT_HEIGHT));
+      newTopFrame.setSize(oldTopFrame.getSize());
       newTopFrame.setVisible(true);
       AlignmentPanel bottomPanel = (AlignmentPanel) bottomPanels.get(i);
       AlignFrame newBottomFrame = new AlignFrame(bottomPanel);
-      newBottomFrame.setSize(new Dimension(AlignFrame.DEFAULT_WIDTH,
-              AlignFrame.DEFAULT_HEIGHT));
+      newBottomFrame.setSize(oldBottomFrame.getSize());
       newBottomFrame.setVisible(true);
       topPanel.av.setGatherViewsHere(false);
       bottomPanel.av.setGatherViewsHere(false);
index a448d19..50a8167 100644 (file)
@@ -1092,15 +1092,26 @@ public class Jalview2XML
       view.setViewName(av.viewName);
       view.setGatheredViews(av.isGatherViewsHere());
 
-      Rectangle position = ap.av.getExplodedGeometry();
-      if (position == null)
+      Rectangle size = ap.av.getExplodedGeometry();
+      Rectangle position = size;
+      if (size == null)
       {
-        position = ap.alignFrame.getBounds();
+        size = ap.alignFrame.getBounds();
+        if (av.getCodingComplement() != null)
+        {
+          position = ((SplitFrame) ap.alignFrame.getSplitViewContainer())
+                  .getBounds();
+        }
+        else
+        {
+          position = size;
+        }
       }
       view.setXpos(position.x);
       view.setYpos(position.y);
-      view.setWidth(position.width);
-      view.setHeight(position.height);
+
+      view.setWidth(size.width);
+      view.setHeight(size.height);
 
       view.setStartRes(av.startRes);
       view.setStartSeq(av.startSeq);
@@ -2453,6 +2464,11 @@ public class Jalview2XML
     int width = (int) dnaFrame.getBounds().getWidth();
     int height = (int) (dnaFrame.getBounds().getHeight()
             + proteinFrame.getBounds().getHeight() + 50);
+
+    /*
+     * SplitFrame location is saved to both enclosed frames
+     */
+    splitFrame.setLocation(dnaFrame.getX(), dnaFrame.getY());
     Desktop.addInternalFrame(splitFrame, title, width, height);
 
     /*
index b790d62..9da8240 100644 (file)
@@ -85,8 +85,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
     // about 50 pixels for the SplitFrame's title bar etc
     int height = ((AlignFrame) getTopFrame()).getHeight()
             + ((AlignFrame) getBottomFrame()).getHeight() + 50;
-    // about 65 pixels for Desktop decorators on Windows
-    height = Math.min(height, Desktop.instance.getHeight() - 65);
+    height = fitHeightToDesktop(height);
     setSize(width, height);
 
     adjustLayout();
@@ -101,6 +100,27 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI
   }
 
   /**
+   * Reduce the height if too large to fit in the Desktop. Also adjust the
+   * divider location in proportion.
+   * 
+   * @param height
+   *          in pixels
+   * @return original or reduced height
+   */
+  public int fitHeightToDesktop(int height)
+  {
+    // allow about 65 pixels for Desktop decorators on Windows
+
+    int newHeight = Math.min(height, Desktop.instance.getHeight() - 65);
+    if (newHeight != height)
+    {
+      int oldDividerLocation = getDividerLocation();
+      setDividerLocation(oldDividerLocation * newHeight / height);
+    }
+    return newHeight;
+  }
+
+  /**
    * Set the top and bottom frames to listen to each others Commands (e.g. Edit,
    * Order).
    */
index 5661ab0..daad4fd 100644 (file)
@@ -33,6 +33,8 @@ import javax.swing.plaf.basic.BasicInternalFrameUI;
 
 public class GSplitFrame extends JInternalFrame
 {
+  private static final int DIVIDER_SIZE = 5;
+
   private static final long serialVersionUID = 1L;
 
   private GAlignFrame topFrame;
@@ -41,6 +43,12 @@ public class GSplitFrame extends JInternalFrame
 
   private JSplitPane splitPane;
 
+  /*
+   * proportional position of split divider; saving this allows it to be
+   * restored after hiding one half and resizing
+   */
+  private double dividerRatio;
+
   /**
    * Constructor
    * 
@@ -65,12 +73,23 @@ public class GSplitFrame extends JInternalFrame
     splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topFrame,
             bottomFrame);
     splitPane.setVisible(true);
-    final double ratio = bottomFrame.getHeight() == 0 ? 0.5d : topFrame
-            .getHeight()
-            / (double) (topFrame.getHeight() + bottomFrame.getHeight());
-    splitPane.setDividerLocation(ratio);
-    splitPane.setResizeWeight(ratio);
-    splitPane.setDividerSize(5);
+
+    /*
+     * set divider split at 50:50, or restore saved split if loading from
+     * project
+     */
+    int topFrameHeight = topFrame.getHeight();
+    splitPane.setDividerSize(DIVIDER_SIZE);
+    if (topFrameHeight == 0)
+    {
+      setRelativeDividerLocation(0.5d); // as a proportion
+    }
+    else
+    {
+      int dividerPosition = topFrameHeight + DIVIDER_SIZE / 2;
+      splitPane.setDividerLocation(dividerPosition); // absolute position
+    }
+    splitPane.setResizeWeight(0.5d);
     add(splitPane);
   }
 
@@ -139,11 +158,25 @@ public class GSplitFrame extends JInternalFrame
   }
 
   /**
-   * Make the complement of the specified split component visible or hidden,
-   * adjusting the position of the split divide.
+   * Makes the complement of the specified split component visible or hidden,
+   * restoring or saving the position of the split divide.
    */
   public void setComplementVisible(Object alignFrame, boolean show)
   {
+    /*
+     * save divider ratio on hide, restore on show
+     */
+    if (show)
+    {
+      setRelativeDividerLocation(dividerRatio);
+    }
+    else
+    {
+      this.dividerRatio = splitPane.getDividerLocation()
+              / (double) (splitPane.getHeight() - splitPane
+                      .getDividerSize());
+    }
+
     if (alignFrame == this.topFrame)
     {
       this.bottomFrame.setVisible(show);
@@ -152,12 +185,40 @@ public class GSplitFrame extends JInternalFrame
     {
       this.topFrame.setVisible(show);
     }
-    if (show)
-    {
-      // SplitPane needs nudging to restore 50-50 split
-      // TODO save/restore other ratios
-      splitPane.setDividerLocation(0.5d);
-    }
+
     validate();
   }
+
+  /**
+   * Set the divider location as a proportion (0 <= r <= 1) of the height <br>
+   * Warning: this overloads setDividerLocation(int), and getDividerLocation()
+   * returns the int (pixel count) value
+   * 
+   * @param r
+   */
+  public void setRelativeDividerLocation(double r)
+  {
+    this.dividerRatio = r;
+    splitPane.setDividerLocation(r);
+  }
+
+  /**
+   * Sets the divider location (in pixels from top)
+   * 
+   * @return
+   */
+  protected void setDividerLocation(int p)
+  {
+    splitPane.setDividerLocation(p);
+  }
+
+  /**
+   * Returns the divider location (in pixels from top)
+   * 
+   * @return
+   */
+  protected int getDividerLocation()
+  {
+    return splitPane.getDividerLocation();
+  }
 }