X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FSplitFrame.java;h=6c849c3750e101fcec52b03292a9021758d326d6;hb=37de9310bec3501cbc6381e0c3dcb282fcaad812;hp=5c4e4d24085a2652912ad8ee0732504e3ffe7669;hpb=be32c14cd8e48fe0a207cd7030cb9cd46f894678;p=jalview.git diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index 5c4e4d2..6c849c3 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -1,5 +1,34 @@ +/* + * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) + * Copyright (C) $$Year-Rel$$ The Jalview Authors + * + * This file is part of Jalview. + * + * Jalview is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 + * of the License, or (at your option) any later version. + * + * Jalview is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Jalview. If not, see . + * The Jalview Authors are detailed in the 'AUTHORS' file. + */ 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.Toolkit; import java.awt.event.ActionEvent; @@ -8,6 +37,8 @@ import java.awt.event.KeyAdapter; 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; @@ -18,14 +49,6 @@ import javax.swing.KeyStroke; import javax.swing.event.InternalFrameAdapter; import javax.swing.event.InternalFrameEvent; -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.viewmodel.AlignmentViewport; - /** * An internal frame on the desktop that hosts a horizontally split view of * linked DNA and Protein alignments. Additional views can be created in linked @@ -40,6 +63,16 @@ import jalview.viewmodel.AlignmentViewport; */ 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) @@ -61,18 +94,25 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI ((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; - height = Math.min(height, Desktop.instance.getHeight() - 20); - // setSize(AlignFrame.DEFAULT_WIDTH, Desktop.instance.getHeight() - 20); + + ((AlignFrame) getBottomFrame()).getHeight() + DIVIDER_SIZE + + heightFudge; + height = fitHeightToDesktop(height); setSize(width, height); adjustLayout(); addCloseFrameListener(); - + addKeyListener(); addKeyBindings(); @@ -81,6 +121,28 @@ 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() + - 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). */ @@ -100,7 +162,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI public void adjustLayout() { /* - * Ensure sequence ids are the same width for good alignment. + * Ensure sequence ids are the same width so sequences line up */ int w1 = ((AlignFrame) getTopFrame()).getViewport().getIdWidth(); int w2 = ((AlignFrame) getBottomFrame()).getViewport().getIdWidth(); @@ -115,30 +177,66 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI } /* - * Set the character width for protein to 3 times that for dna. + * Scale protein to either 1 or 3 times character width of dna */ - boolean scaleThreeToOne = true; // TODO a new Preference option? - if (scaleThreeToOne) + 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 + : (bottomAlignment.isNucleotide() ? bottomViewport : null); + AlignmentViewport protein = !topAlignment.isNucleotide() ? topViewport + : (!bottomAlignment.isNucleotide() ? bottomViewport : null); + if (protein != null && cdna != null) { - 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 - : (bottomAlignment.isNucleotide() ? bottomViewport : null); - AlignmentViewport protein = !topAlignment.isNucleotide() ? topViewport - : (!bottomAlignment.isNucleotide() ? bottomViewport : null); - if (protein != null && cdna != null) - { - ViewStyleI vs = cdna.getViewStyle(); - ViewStyleI vs2 = protein.getViewStyle(); - vs2.setCharWidth(3 * vs.getCharWidth()); - protein.setViewStyle(vs2); - } + ViewStyleI vs = protein.getViewStyle(); + int scale = vs.isScaleProteinAsCdna() ? 3 : 1; + vs.setCharWidth(scale * cdna.getViewStyle().getCharWidth()); + protein.setViewStyle(vs); } } /** + * Adjust 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. + */ + protected void adjustDivider() + { + final AlignViewport topViewport = ((AlignFrame) getTopFrame()).viewport; + final AlignViewport bottomViewport = ((AlignFrame) getBottomFrame()).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(); + + /* + * 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) / (topHeight + bottomHeight); + + /* + * limit to 0.2 <= ratio <= 0.8 to avoid concealing all sequences + */ + ratio = Math.min(ratio, 0.8d); + ratio = Math.max(ratio, 0.2d); + setRelativeDividerLocation(ratio); + } + + /** * Add a listener to tidy up when the frame is closed. */ protected void addCloseFrameListener() @@ -148,16 +246,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI @Override public void internalFrameClosed(InternalFrameEvent evt) { - if (getTopFrame() instanceof AlignFrame) - { - ((AlignFrame) getTopFrame()) - .closeMenuItem_actionPerformed(true); - } - if (getBottomFrame() instanceof AlignFrame) - { - ((AlignFrame) getBottomFrame()) - .closeMenuItem_actionPerformed(true); - } + close(); }; }); } @@ -168,7 +257,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI */ protected void addKeyListener() { - addKeyListener(new KeyAdapter() { + addKeyListener(new KeyAdapter() + { @Override public void keyPressed(KeyEvent e) @@ -202,7 +292,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI } } } - + }); } @@ -248,6 +338,7 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI actioned = true; e.consume(); } + break; default: } return actioned; @@ -396,6 +487,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI { AlignFrame topFrame = (AlignFrame) getTopFrame(); AlignFrame bottomFrame = (AlignFrame) getBottomFrame(); + final boolean scaleProteinAsCdna = topFrame.viewport + .isScaleProteinAsCdna(); AlignmentPanel newTopPanel = topFrame.newView(null, true); AlignmentPanel newBottomPanel = bottomFrame.newView(null, true); @@ -414,6 +507,19 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI newBottomPanel.av.viewName = newTopPanel.av.viewName; newTopPanel.av.setCodingComplement(newBottomPanel.av); + /* + * These lines can be removed once scaleProteinAsCdna is added to element + * Viewport in jalview.xsd, as Jalview2XML.copyAlignPanel will then take + * care of it + */ + newTopPanel.av.setScaleProteinAsCdna(scaleProteinAsCdna); + newBottomPanel.av.setScaleProteinAsCdna(scaleProteinAsCdna); + + /* + * Line up id labels etc + */ + adjustLayout(); + final StructureSelectionManager ssm = StructureSelectionManager .getStructureSelectionManager(Desktop.instance); ssm.addCommandListener(newTopPanel.av); @@ -609,6 +715,18 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI } /** + * return the AlignFrames held by this container + * + * @return { Top alignFrame (Usually CDS), Bottom AlignFrame (Usually + * Protein)} + */ + public List 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. @@ -636,4 +754,3 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI overrideKeyBinding(key_cmdF, action); } } -