From 9c6f9bb69f694cb37db088c8fca6582169efcb05 Mon Sep 17 00:00:00 2001 From: gmungoc Date: Fri, 19 Feb 2016 16:58:45 +0000 Subject: [PATCH] JAL-1705 refactor show products, set initial split frame divider --- resources/lang/Messages.properties | 2 + src/jalview/analysis/CrossRef.java | 45 +++++----- src/jalview/gui/AlignFrame.java | 174 ++++++++++++++++++------------------ src/jalview/gui/SplitFrame.java | 51 ++++++++++- 4 files changed, 161 insertions(+), 111 deletions(-) diff --git a/resources/lang/Messages.properties b/resources/lang/Messages.properties index 5ce5f46..4ab8732 100644 --- a/resources/lang/Messages.properties +++ b/resources/lang/Messages.properties @@ -218,6 +218,8 @@ label.above_identity_threshold = Above Identity Threshold label.show_sequence_features = Show Sequence Features label.nucleotide = Nucleotide label.protein = Protein +label.nucleotides = Nucleotides +label.proteins = Proteins label.to_new_alignment = To New Alignment label.to_this_alignment = Add To This Alignment label.apply_colour_to_all_groups = Apply Colour To All Groups diff --git a/src/jalview/analysis/CrossRef.java b/src/jalview/analysis/CrossRef.java index d45750e..2f6076a 100644 --- a/src/jalview/analysis/CrossRef.java +++ b/src/jalview/analysis/CrossRef.java @@ -219,30 +219,23 @@ public class CrossRef /** * - * @param dna - * @param seqs - * @return - */ - public static Alignment findXrefSequences(SequenceI[] seqs, boolean dna, - String source) - { - return findXrefSequences(seqs, dna, source, null); - } - - /** - * * @param seqs * sequences whose xrefs are being retrieved * @param dna * true if sequences are nucleotide * @param source - * @param dataset - * alignment to search for product sequences. + * @param al + * alignment to search for cross-referenced sequences (and possibly + * add to) + * @param addedPeers + * a list of sequences to add to if 'peers' to the original sequences + * are found e.g. alternative protein products for a protein's gene * @return products (as dataset sequences) */ public static Alignment findXrefSequences(SequenceI[] seqs, boolean dna, - String source, AlignmentI dataset) + String source, AlignmentI al, List addedPeers) { + AlignmentI dataset = al.getDataset() == null ? al : al.getDataset(); List rseqs = new ArrayList(); AlignedCodonFrame cf = new AlignedCodonFrame(); for (SequenceI seq : seqs) @@ -389,10 +382,12 @@ public class CrossRef int sf = map.getMap().getToLowest(); int st = map.getMap().getToHighest(); SequenceI mappedrg = ms.getSubSequence(sf, st); - SequenceI loc = dss.getSubSequence(sf, st); + // SequenceI loc = dss.getSubSequence(sf, st); if (mappedrg.getLength() > 0 - && mappedrg.getSequenceAsString().equals( - loc.getSequenceAsString())) + && ms.getSequenceAsString().equals( + dss.getSequenceAsString())) + // && mappedrg.getSequenceAsString().equals( + // loc.getSequenceAsString())) { String msg = "Mapping updated from " + ms.getName() @@ -414,8 +409,8 @@ public class CrossRef for (SequenceFeature feat : sfs) { /* - * we override the equality test here (but not - * elsewhere) to ignore Parent attribute + * we override SequenceFeature.equals here (but + * not elsewhere) to ignore Parent attribute * TODO not quite working yet! */ if (!copiedFeatures @@ -430,6 +425,12 @@ public class CrossRef cf.addMap(retrieved[rs].getDatasetSequence(), dss, map.getMap()); } + else + { + addedPeers.add(map.getTo()); + cf.addMap(retrieved[rs].getDatasetSequence(), + map.getTo(), map.getMap()); + } } catch (Exception e) { System.err @@ -452,9 +453,7 @@ public class CrossRef Alignment ral = null; if (rseqs.size() > 0) { - SequenceI[] rsqs = new SequenceI[rseqs.size()]; - rseqs.toArray(rsqs); - ral = new Alignment(rsqs); + ral = new Alignment(rseqs.toArray(new SequenceI[rseqs.size()])); if (cf != null && !cf.isEmpty()) { ral.addCodonFrame(cf); diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 85f7d19..c93b84b 100644 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -904,7 +904,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, rnahelicesColour.setEnabled(av.getAlignment().hasRNAStructure()); rnahelicesColour .setSelected(av.getGlobalColourScheme() instanceof jalview.schemes.RNAHelicesColour); - setShowProductsEnabled(); + + showProducts.setEnabled(canShowProducts()); + updateEditMenuBar(); } @@ -4652,67 +4654,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } } - /* - * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser - * chooser = new JalviewFileChooser(jalview.bin.Cache. - * getProperty("LAST_DIRECTORY")); - * - * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export - * to Vamsas file"); chooser.setToolTipText("Export"); - * - * int value = chooser.showSaveDialog(this); - * - * if (value == JalviewFileChooser.APPROVE_OPTION) { - * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport); - * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview( - * chooser.getSelectedFile().getAbsolutePath(), this); } } - */ /** - * prototype of an automatically enabled/disabled analysis function + * Searches selected sequences for xRef products and builds the Show + * Cross-References menu (formerly called Show Products) * + * @return true if Show Cross-references menu should be enabled. */ - protected void setShowProductsEnabled() + public boolean canShowProducts() { SequenceI[] selection = viewport.getSequenceSelection(); - if (canShowProducts(selection, viewport.getSelectionGroup() != null, - viewport.getAlignment().getDataset())) - { - showProducts.setEnabled(true); - - } - else - { - showProducts.setEnabled(false); - } - } - - /** - * search selection for sequence xRef products and build the show products - * menu. - * - * @param selection - * @param dataset - * @return true if showProducts menu should be enabled. - */ - public boolean canShowProducts(SequenceI[] selection, - boolean isRegionSelection, Alignment dataset) - { + AlignmentI dataset = viewport.getAlignment().getDataset(); boolean showp = false; try { showProducts.removeAll(); final boolean dna = viewport.getAlignment().isNucleotide(); - final Alignment ds = dataset; String[] ptypes = (selection == null || selection.length == 0) ? null : CrossRef.findSequenceXrefTypes(dna, selection, dataset); - // Object[] prods = - // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(), - // selection, dataset, true); - final SequenceI[] sel = selection; + for (int t = 0; ptypes != null && t < ptypes.length; t++) { showp = true; - final boolean isRegSel = isRegionSelection; final AlignFrame af = this; final String source = ptypes[t]; JMenuItem xtype = new JMenuItem(ptypes[t]); @@ -4722,9 +4684,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, @Override public void actionPerformed(ActionEvent e) { - // TODO: new thread for this call with vis-delay - af.showProductsFor(af.viewport.getSequenceSelection(), - isRegSel, dna, source); + showProductsFor(af.viewport.getSequenceSelection(), dna, source); } }); @@ -4735,15 +4695,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, } catch (Exception e) { jalview.bin.Cache.log - .warn("canTranslate threw an exception - please report to help@jalview.org", + .warn("canShowProducts threw an exception - please report to help@jalview.org", e); return false; } return showp; } - protected void showProductsFor(final SequenceI[] sel, - final boolean isRegSel, final boolean dna, final String source) + protected void showProductsFor(final SequenceI[] sel, final boolean dna, + final String source) { Runnable foo = new Runnable() { @@ -4757,27 +4717,18 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, new Object[] { source }), sttime); try { - // update our local dataset reference - Alignment ds = AlignFrame.this.getViewport().getAlignment() - .getDataset(); - Alignment prods = CrossRef - .findXrefSequences(sel, dna, source, ds); - if (prods != null) + /* + * 'peer' sequences are any to add to this alignment, for example + * alternative protein products for my protein's gene + */ + List addedPeers = new ArrayList(); + AlignmentI alignment = AlignFrame.this.getViewport().getAlignment(); + Alignment xrefs = CrossRef.findXrefSequences(sel, dna, source, + alignment, addedPeers); + if (xrefs != null) { - SequenceI[] sprods = new SequenceI[prods.getHeight()]; - for (int s = 0; s < sprods.length; s++) - { - sprods[s] = (prods.getSequenceAt(s)).deriveSequence(); - if (ds.getSequences() == null - || !ds.getSequences().contains( - sprods[s].getDatasetSequence())) - { - ds.addSequence(sprods[s].getDatasetSequence()); - } - sprods[s].updatePDBIds(); - } - Alignment al = new Alignment(sprods); - al.setDataset(ds); + Alignment al = makeCrossReferencesAlignment( + alignment.getDataset(), xrefs); /* * Copy dna-to-protein mappings to new alignment @@ -4785,16 +4736,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, // TODO 1: no mappings are set up for EMBL product // TODO 2: if they were, should add them to protein alignment, not // dna - List cf = prods.getCodonFrames(); - for (AlignedCodonFrame acf : cf) - { - al.addCodonFrame(acf); - } + // List cf = xrefs.getCodonFrames(); + // for (AlignedCodonFrame acf : cf) + // { + // al.addCodonFrame(acf); + // } AlignFrame newFrame = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT); - String newtitle = "" + (dna ? "Proteins" : "Nucleotides") - + " for " + (isRegSel ? "selected region of " : "") - + getTitle(); + String newtitle = String.format("%s %s %s", + MessageManager.getString(dna ? "label.proteins" + : "label.nucleotides"), MessageManager + .getString("label.for"), getTitle()); newFrame.setTitle(newtitle); boolean asSplitFrame = Cache.getDefault( @@ -4808,25 +4760,50 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, AlignmentI copyAlignment = null; final SequenceI[] sequenceSelection = AlignFrame.this.viewport .getSequenceSelection(); + List cf = xrefs.getCodonFrames(); if (dna) { copyAlignment = AlignmentUtils.makeCdsAlignment( sequenceSelection, cf); al.getCodonFrames().clear(); al.getCodonFrames().addAll(cf); - final StructureSelectionManager ssm = StructureSelectionManager - .getStructureSelectionManager(Desktop.instance); - ssm.registerMappings(cf); } else { copyAlignment = new Alignment(new Alignment( sequenceSelection)); + copyAlignment.getCodonFrames().addAll(cf); } + StructureSelectionManager ssm = StructureSelectionManager + .getStructureSelectionManager(Desktop.instance); + ssm.registerMappings(cf); + + /* + * add in any extra 'peer' sequences discovered + * (e.g. alternative protein products) + */ + for (SequenceI peer : addedPeers) + { + copyAlignment.addSequence(peer); + } + + /* + * align protein to dna + */ + // TODO needs debugging + // if (dna) + // { + // al.alignAs(copyAlignment); + // } + // else + // { + // copyAlignment.alignAs(al); + // } + AlignFrame copyThis = new AlignFrame(copyAlignment, AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT); copyThis.setTitle(AlignFrame.this.getTitle()); - // SplitFrame with dna above, protein below + boolean showSequenceFeatures = viewport .isShowSequenceFeatures(); newFrame.setShowSeqFeatures(showSequenceFeatures); @@ -4849,6 +4826,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, String linkedTitle = MessageManager .getString("label.linked_view_title"); Desktop.addInternalFrame(sf, linkedTitle, -1, -1); + sf.adjustDivider(); } else { @@ -4878,6 +4856,32 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener, new Object[] { source }), sttime); } + /** + * @param alignment + * @param prods + * @return + */ + protected Alignment makeCrossReferencesAlignment( +Alignment dataset, + Alignment prods) + { + SequenceI[] sprods = new SequenceI[prods.getHeight()]; + for (int s = 0; s < sprods.length; s++) + { + sprods[s] = (prods.getSequenceAt(s)).deriveSequence(); + if (dataset.getSequences() == null + || !dataset.getSequences().contains( + sprods[s].getDatasetSequence())) + { + dataset.addSequence(sprods[s].getDatasetSequence()); + } + sprods[s].updatePDBIds(); + } + Alignment al = new Alignment(sprods); + al.setDataset(dataset); + return al; + } + }; Thread frunner = new Thread(foo); frunner.start(); diff --git a/src/jalview/gui/SplitFrame.java b/src/jalview/gui/SplitFrame.java index 083c7ec..617224f 100644 --- a/src/jalview/gui/SplitFrame.java +++ b/src/jalview/gui/SplitFrame.java @@ -61,6 +61,14 @@ import javax.swing.event.InternalFrameEvent; */ 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) @@ -86,8 +94,10 @@ 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() ? 28 : 28; // Windows tbc - int heightFudge = Platform.isAMac() ? 50 : 50; // tbc + 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() + DIVIDER_SIZE @@ -118,7 +128,8 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI { // allow about 65 pixels for Desktop decorators on Windows - int newHeight = Math.min(height, Desktop.instance.getHeight() - 65); + int newHeight = Math.min(height, Desktop.instance.getHeight() + - DESKTOP_DECORATORS_HEIGHT); if (newHeight != height) { int oldDividerLocation = getDividerLocation(); @@ -182,6 +193,40 @@ public class SplitFrame extends GSplitFrame implements SplitContainerI } /** + * 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(); + 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); + + setRelativeDividerLocation(ratio); + } + + /** * Add a listener to tidy up when the frame is closed. */ protected void addCloseFrameListener() -- 1.7.10.2