/*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
- * Copyright (C) 2015 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 jalview.api.SplitContainerI;
-import jalview.api.ViewStyleI;
import jalview.datamodel.AlignmentI;
import jalview.jbgui.GAlignFrame;
import jalview.jbgui.GSplitFrame;
import jalview.structure.StructureSelectionManager;
+import jalview.util.Platform;
import jalview.viewmodel.AlignmentViewport;
import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.beans.PropertyVetoException;
+import java.util.Arrays;
+import java.util.List;
import java.util.Map.Entry;
import javax.swing.AbstractAction;
*/
public class SplitFrame extends GSplitFrame implements SplitContainerI
{
+ private static final int WINDOWS_INSETS_WIDTH = 28; // tbc
+
+ private static final int MAC_INSETS_WIDTH = 28;
+
+ private static final int WINDOWS_INSETS_HEIGHT = 50; // tbc
+
+ private static final int MAC_INSETS_HEIGHT = 50;
+
+ private static final int DESKTOP_DECORATORS_HEIGHT = 65;
+
private static final long serialVersionUID = 1L;
public SplitFrame(GAlignFrame top, GAlignFrame bottom)
((AlignFrame) getTopFrame()).getViewport().setCodingComplement(
((AlignFrame) getBottomFrame()).getViewport());
- int width = ((AlignFrame) getTopFrame()).getWidth();
- // about 50 pixels for the SplitFrame's title bar etc
+ /*
+ * 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
+ : WINDOWS_INSETS_WIDTH;
+ int heightFudge = Platform.isAMac() ? MAC_INSETS_HEIGHT
+ : WINDOWS_INSETS_HEIGHT;
+ int width = ((AlignFrame) getTopFrame()).getWidth() + widthFudge;
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);
+ + ((AlignFrame) getBottomFrame()).getHeight() + DIVIDER_SIZE
+ + heightFudge;
+ height = fitHeightToDesktop(height);
setSize(width, height);
adjustLayout();
}
/**
+ * 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() - DESKTOP_DECORATORS_HEIGHT);
+ 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).
*/
: (!bottomAlignment.isNucleotide() ? bottomViewport : null);
if (protein != null && cdna != null)
{
- ViewStyleI vs = protein.getViewStyle();
- int scale = vs.isScaleProteinAsCdna() ? 3 : 1;
- vs.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
- protein.setViewStyle(vs);
+ int scale = protein.isScaleProteinAsCdna() ? 3 : 1;
+ protein.setCharWidth(scale * cdna.getViewStyle().getCharWidth());
}
}
/**
+ * Adjusts the divider for a sensible split of the real estate (for example,
+ * when many transcripts are shown with a single protein). This should only be
+ * called after the split pane has been laid out (made visible) so it has a
+ * height. The aim is to avoid unnecessary vertical scroll bars, while
+ * ensuring that at least 2 sequences are visible in each panel.
+ * <p>
+ * Once laid out, the user may choose to customise as they wish, so this
+ * method is not called again after the initial layout.
+ */
+ protected void adjustInitialLayout()
+ {
+ AlignFrame topFrame = (AlignFrame) getTopFrame();
+ AlignFrame bottomFrame = (AlignFrame) getBottomFrame();
+
+ /*
+ * recompute layout of top and bottom panels to reflect their
+ * actual (rather than requested) height
+ */
+ topFrame.alignPanel.adjustAnnotationHeight();
+ bottomFrame.alignPanel.adjustAnnotationHeight();
+
+ final AlignViewport topViewport = topFrame.viewport;
+ final AlignViewport bottomViewport = bottomFrame.viewport;
+ final AlignmentI topAlignment = topViewport.getAlignment();
+ final AlignmentI bottomAlignment = bottomViewport.getAlignment();
+ boolean topAnnotations = topViewport.isShowAnnotation();
+ boolean bottomAnnotations = bottomViewport.isShowAnnotation();
+ // TODO need number of visible sequences here, not #sequences - how?
+ int topCount = topAlignment.getHeight();
+ int bottomCount = bottomAlignment.getHeight();
+ int topCharHeight = topViewport.getViewStyle().getCharHeight();
+ int bottomCharHeight = bottomViewport.getViewStyle().getCharHeight();
+
+ /*
+ * calculate the minimum ratio that leaves at least the height
+ * of two sequences (after rounding) visible in the top panel
+ */
+ int topPanelHeight = topFrame.getHeight();
+ int bottomPanelHeight = bottomFrame.getHeight();
+ int topSequencesHeight = topFrame.alignPanel.getSeqPanel().seqCanvas
+ .getHeight();
+ int topPanelMinHeight = topPanelHeight
+ - Math.max(0, topSequencesHeight - 3 * topCharHeight);
+ double totalHeight = (double) topPanelHeight + bottomPanelHeight;
+ double minRatio = topPanelMinHeight / totalHeight;
+
+ /*
+ * calculate the maximum ratio that leaves at least the height
+ * of two sequences (after rounding) visible in the bottom panel
+ */
+ int bottomSequencesHeight = bottomFrame.alignPanel.getSeqPanel().seqCanvas
+ .getHeight();
+ int bottomPanelMinHeight = bottomPanelHeight
+ - Math.max(0, bottomSequencesHeight - 3 * bottomCharHeight);
+ double maxRatio = (totalHeight - bottomPanelMinHeight) / totalHeight;
+
+ /*
+ * estimate ratio of (topFrameContent / bottomFrameContent)
+ */
+ int insets = Platform.isAMac() ? MAC_INSETS_HEIGHT
+ : WINDOWS_INSETS_HEIGHT;
+ // allow 3 'rows' for scale, scrollbar, status bar
+ int topHeight = insets + (3 + topCount) * topCharHeight
+ + (topAnnotations ? topViewport.calcPanelHeight() : 0);
+ int bottomHeight = insets + (3 + bottomCount) * bottomCharHeight
+ + (bottomAnnotations ? bottomViewport.calcPanelHeight() : 0);
+ double ratio = ((double) topHeight)
+ / (double) (topHeight + bottomHeight);
+
+ /*
+ * limit ratio to avoid concealing all sequences
+ */
+ ratio = Math.min(ratio, maxRatio);
+ ratio = Math.max(ratio, minRatio);
+ setRelativeDividerLocation(ratio);
+ }
+
+ /**
* Add a listener to tidy up when the frame is closed.
*/
protected void addCloseFrameListener()
actioned = true;
e.consume();
}
+ break;
default:
}
return actioned;
/*
* Ctrl-W / Cmd-W - close view or window
*/
- KeyStroke key_cmdW = KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit
- .getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ KeyStroke key_cmdW = KeyStroke.getKeyStroke(KeyEvent.VK_W,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
action = new AbstractAction()
{
@Override
/*
* Ctrl-T / Cmd-T open new view
*/
- KeyStroke key_cmdT = KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit
- .getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ KeyStroke key_cmdT = KeyStroke.getKeyStroke(KeyEvent.VK_T,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
AbstractAction action = new AbstractAction()
{
@Override
Component c = getFrameAtMouse();
if (c != null && c instanceof AlignFrame)
{
- for (ActionListener a : ((AlignFrame) c).getAccelerators()
- .get(ks).getActionListeners())
+ for (ActionListener a : ((AlignFrame) c).getAccelerators().get(ks)
+ .getActionListeners())
{
a.actionPerformed(null);
}
}
/**
+ * return the AlignFrames held by this container
+ *
+ * @return { Top alignFrame (Usually CDS), Bottom AlignFrame (Usually
+ * Protein)}
+ */
+ public List<AlignFrame> getAlignFrames()
+ {
+ return Arrays
+ .asList(new AlignFrame[]
+ { (AlignFrame) getTopFrame(), (AlignFrame) getBottomFrame() });
+ }
+
+ /**
* 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
* search in the half of the SplitFrame that has the mouse.
/*
* Ctrl-F / Cmd-F open Finder dialog, 'focused' on the right alignment
*/
- KeyStroke key_cmdF = KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit
- .getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ KeyStroke key_cmdF = KeyStroke.getKeyStroke(KeyEvent.VK_F,
+ Toolkit.getDefaultToolkit().getMenuShortcutKeyMask(), false);
AbstractAction action = new AbstractAction()
{
@Override