X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fviewmodel%2FAlignmentViewport.java;h=d26f0238fddce159526385e0bc08d1c7f4171033;hb=965c8af33ac58a3b5b940e52f04a7bfc16d83e98;hp=946c8e626550bb7448cc1e4b52401c000d4b8b11;hpb=b24a7070977bdbb780ec0a0e218935966af94b65;p=jalview.git diff --git a/src/jalview/viewmodel/AlignmentViewport.java b/src/jalview/viewmodel/AlignmentViewport.java index 946c8e6..d26f023 100644 --- a/src/jalview/viewmodel/AlignmentViewport.java +++ b/src/jalview/viewmodel/AlignmentViewport.java @@ -20,21 +20,39 @@ */ package jalview.viewmodel; +import java.awt.Color; +import java.beans.PropertyChangeSupport; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.Deque; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder; +import jalview.analysis.Connectivity; import jalview.analysis.Conservation; import jalview.analysis.TreeModel; import jalview.api.AlignCalcManagerI; +import jalview.api.AlignExportSettingsI; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; import jalview.api.FeaturesDisplayedI; import jalview.api.ViewStyleI; +import jalview.bin.Console; import jalview.commands.CommandI; import jalview.datamodel.AlignedCodonFrame; import jalview.datamodel.AlignmentAnnotation; +import jalview.datamodel.AlignmentExportData; import jalview.datamodel.AlignmentI; import jalview.datamodel.AlignmentView; import jalview.datamodel.Annotation; import jalview.datamodel.ColumnSelection; +import jalview.datamodel.ContactListI; +import jalview.datamodel.ContactMatrixI; import jalview.datamodel.HiddenColumns; import jalview.datamodel.HiddenSequences; import jalview.datamodel.ProfilesI; @@ -43,6 +61,8 @@ import jalview.datamodel.Sequence; import jalview.datamodel.SequenceCollectionI; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.gui.QuitHandler; +import jalview.project.Jalview2XML; import jalview.renderer.ResidueShader; import jalview.renderer.ResidueShaderI; import jalview.schemes.ColourSchemeI; @@ -57,19 +77,9 @@ import jalview.viewmodel.styles.ViewStyle; import jalview.workers.AlignCalcManager; import jalview.workers.ComplementConsensusThread; import jalview.workers.ConsensusThread; +import jalview.workers.SecondaryStructureConsensusThread; import jalview.workers.StrucConsensusThread; -import java.awt.Color; -import java.beans.PropertyChangeSupport; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.BitSet; -import java.util.Deque; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; - /** * base class holding visualization and analysis attributes and common logic for * an active alignment view displayed in the GUI @@ -97,6 +107,11 @@ public abstract class AlignmentViewport protected Deque redoList = new ArrayDeque<>(); /** + * used to determine if quit should be confirmed + */ + private boolean savedUpToDate = false; + + /** * alignment displayed in the viewport. Please use get/setter */ protected AlignmentI alignment; @@ -661,7 +676,7 @@ public abstract class AlignmentViewport * retain any colour thresholds per group while * changing choice of colour scheme (JAL-2386) */ - sg.setColourScheme(cs); + sg.setColourScheme(cs == null ? null : cs.getInstance(this, sg)); if (cs != null) { sg.getGroupColourScheme().alignmentChanged(sg, @@ -684,6 +699,8 @@ public abstract class AlignmentViewport } protected AlignmentAnnotation consensus; + + protected AlignmentAnnotation secondaryStructureConsensus; protected AlignmentAnnotation complementConsensus; @@ -696,6 +713,8 @@ public abstract class AlignmentViewport protected AlignmentAnnotation quality; protected AlignmentAnnotation[] groupConsensus; + + protected AlignmentAnnotation[] groupSSConsensus; protected AlignmentAnnotation[] groupConservation; @@ -703,17 +722,21 @@ public abstract class AlignmentViewport * results of alignment consensus analysis for visible portion of view */ protected ProfilesI hconsensus = null; + + protected ProfilesI hSSConsensus = null; + + /** * results of cDNA complement consensus visible portion of view */ - protected Hashtable[] hcomplementConsensus = null; + protected Hashtable[] hcomplementConsensus = null; /** * results of secondary structure base pair consensus for visible portion of * view */ - protected Hashtable[] hStrucConsensus = null; + protected Hashtable[] hStrucConsensus = null; protected Conservation hconservation = null; @@ -740,9 +763,16 @@ public abstract class AlignmentViewport { this.hconsensus = hconsensus; } - + @Override - public void setComplementConsensusHash(Hashtable[] hconsensus) + public void setSequenceSSConsensusHash(ProfilesI hSSConsensus) + { + this.hSSConsensus = hSSConsensus; + } + + @Override + public void setComplementConsensusHash( + Hashtable[] hconsensus) { this.hcomplementConsensus = hconsensus; } @@ -752,21 +782,28 @@ public abstract class AlignmentViewport { return hconsensus; } + + @Override + public ProfilesI getSequenceSSConsensusHash() + { + return hSSConsensus; + } @Override - public Hashtable[] getComplementConsensusHash() + public Hashtable[] getComplementConsensusHash() { return hcomplementConsensus; } @Override - public Hashtable[] getRnaStructureConsensusHash() + public Hashtable[] getRnaStructureConsensusHash() { return hStrucConsensus; } @Override - public void setRnaStructureConsensusHash(Hashtable[] hStrucConsensus) + public void setRnaStructureConsensusHash( + Hashtable[] hStrucConsensus) { this.hStrucConsensus = hStrucConsensus; @@ -790,6 +827,14 @@ public abstract class AlignmentViewport return consensus; } + + @Override + public AlignmentAnnotation getAlignmentSecondaryStructureConsensusAnnotation() + { + return secondaryStructureConsensus; + } + + @Override public AlignmentAnnotation getAlignmentGapAnnotation() { @@ -881,6 +926,26 @@ public abstract class AlignmentViewport } } } + + + + + /** + * trigger update of consensus annotation + */ + public void updateSecondaryStructureConsensus(final AlignmentViewPanel ap) + { + // see note in mantis : issue number 8585 + if (secondaryStructureConsensus == null || !autoCalculateConsensus) + { + return; + } + if (calculator + .getRegisteredWorkersOfClass(SecondaryStructureConsensusThread.class) == null) + { + calculator.registerWorker(new SecondaryStructureConsensusThread(this, ap)); + } + } // --------START Structure Conservation public void updateStrucConsensus(final AlignmentViewPanel ap) @@ -919,7 +984,8 @@ public abstract class AlignmentViewport } if (calculator.workingInvolvedWith(alignmentAnnotation)) { - // System.err.println("grey out ("+alignmentAnnotation.label+")"); + // jalview.bin.Console.errPrintln("grey out + // ("+alignmentAnnotation.label+")"); return true; } return false; @@ -943,6 +1009,7 @@ public abstract class AlignmentViewport consensus = null; complementConsensus = null; strucConsensus = null; + secondaryStructureConsensus = null; conservation = null; quality = null; groupConsensus = null; @@ -957,6 +1024,7 @@ public abstract class AlignmentViewport ranges = null; currentTree = null; selectionGroup = null; + colSel = null; setAlignment(null); } @@ -988,6 +1056,8 @@ public abstract class AlignmentViewport * should consensus profile be rendered by default */ protected boolean showSequenceLogo = false; + + protected boolean showSequenceSSLogo = false; /** * should consensus profile be rendered normalised to row height @@ -998,6 +1068,13 @@ public abstract class AlignmentViewport * should consensus histograms be rendered by default */ protected boolean showConsensusHistogram = true; + + protected boolean showSSConsensusHistogram = true; + + public void setShowSSConsensusHistogram(boolean showSSConsensusHistogram) + { + this.showSSConsensusHistogram = showSSConsensusHistogram; + } /** * @return the showConsensusProfile @@ -1007,6 +1084,12 @@ public abstract class AlignmentViewport { return showSequenceLogo; } + + @Override + public boolean isShowSequenceSSLogo() + { + return showSequenceSSLogo; + } /** * @param showSequenceLogo @@ -1025,6 +1108,18 @@ public abstract class AlignmentViewport } this.showSequenceLogo = showSequenceLogo; } + + public void setShowSequenceSSLogo(boolean showSequenceSSLogo) + { + if (showSequenceSSLogo != this.showSequenceSSLogo) + { + // TODO: decouple settings setting from calculation when refactoring + // annotation update method from alignframe to viewport + this.showSequenceSSLogo = showSequenceSSLogo; + calculator.updateAnnotationFor(SecondaryStructureConsensusThread.class); + } + this.showSequenceSSLogo = showSequenceSSLogo; + } /** * @param showConsensusHistogram @@ -1079,6 +1174,12 @@ public abstract class AlignmentViewport { return this.showConsensusHistogram; } + + @Override + public boolean isShowSSConsensusHistogram() + { + return this.showSSConsensusHistogram; + } /** * when set, updateAlignment will always ensure sequences are of equal length @@ -1191,7 +1292,7 @@ public abstract class AlignmentViewport { if (sequenceSetID != null) { - System.err.println( + jalview.bin.Console.errPrintln( "Warning - overwriting a sequenceSetId for a viewport!"); } sequenceSetID = new String(newid); @@ -1230,6 +1331,7 @@ public abstract class AlignmentViewport if (ap != null) { updateConsensus(ap); + updateSecondaryStructureConsensus(ap); if (residueShading != null) { residueShading.setThreshold(residueShading.getThreshold(), @@ -1302,7 +1404,9 @@ public abstract class AlignmentViewport protected boolean showQuality = true; - protected boolean showConsensus = true; + protected boolean showConsensus = true; + + protected boolean showSSConsensus = false; protected boolean showOccupancy = true; @@ -1360,6 +1464,12 @@ public abstract class AlignmentViewport changeSupport.firePropertyChange(prop, oldvalue, newvalue); } + @Override + public void notifyAlignmentChanged() + { + firePropertyChange("alignment", null, alignment); + } + // common hide/show column stuff public void hideSelectedColumns() @@ -1635,6 +1745,7 @@ public abstract class AlignmentViewport public void invertColumnSelection() { colSel.invertColumnSelection(0, alignment.getWidth(), alignment); + isColSelChanged(true); } @Override @@ -1740,8 +1851,12 @@ public abstract class AlignmentViewport if (alignment.getHiddenColumns() != null && alignment.getHiddenColumns().hasHiddenColumns()) { - selection = alignment.getHiddenColumns() - .getVisibleSequenceStrings(start, end, seqs); + for (i = 0; i < iSize; i++) + { + Iterator blocks = alignment.getHiddenColumns() + .getVisContigsIterator(start, end + 1, false); + selection[i] = seqs[i].getSequenceStringFromIterator(blocks); + } } else { @@ -1771,7 +1886,7 @@ public abstract class AlignmentViewport start = hidden.visibleToAbsoluteColumn(start); } - end = hidden.getHiddenBoundaryRight(start); + end = hidden.getNextHiddenBoundary(false, start); if (start == end) { end = max; @@ -1787,11 +1902,11 @@ public abstract class AlignmentViewport if (hidden != null && hidden.hasHiddenColumns()) { start = hidden.visibleToAbsoluteColumn(end); - start = hidden.getHiddenBoundaryLeft(start) + 1; + start = hidden.getNextHiddenBoundary(true, start) + 1; } } while (end < max); - int[][] startEnd = new int[regions.size()][2]; + // int[][] startEnd = new int[regions.size()][2]; return regions; } @@ -1809,13 +1924,12 @@ public abstract class AlignmentViewport AlignmentAnnotation clone = new AlignmentAnnotation(annot); if (selectedOnly && selectionGroup != null) { - alignment.getHiddenColumns().makeVisibleAnnotation( - selectionGroup.getStartRes(), selectionGroup.getEndRes(), - clone); + clone.makeVisibleAnnotation(selectionGroup.getStartRes(), + selectionGroup.getEndRes(), alignment.getHiddenColumns()); } else { - alignment.getHiddenColumns().makeVisibleAnnotation(clone); + clone.makeVisibleAnnotation(alignment.getHiddenColumns()); } ala.add(clone); } @@ -1851,6 +1965,7 @@ public abstract class AlignmentViewport if (autoCalculateConsensus) { updateConsensus(ap); + updateSecondaryStructureConsensus(ap); } if (hconsensus != null && autoCalculateConsensus) { @@ -1934,13 +2049,19 @@ public abstract class AlignmentViewport consensus = new AlignmentAnnotation("Consensus", MessageManager.getString("label.consensus_descr"), new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH); + + secondaryStructureConsensus = new AlignmentAnnotation(MessageManager.getString("label.ssconsensus_label"), + MessageManager.getString("label.ssconsensus_descr"), + new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH); + initConsensus(consensus); + initSSConsensus(secondaryStructureConsensus); initGapCounts(); - initComplementConsensus(); } } + /** * If this is a protein alignment and there are mappings to cDNA, adds the * cDNA consensus annotation and returns true, else returns false. @@ -1991,6 +2112,17 @@ public abstract class AlignmentViewport alignment.addAnnotation(aa); } } + + private void initSSConsensus(AlignmentAnnotation aa) + { + aa.hasText = true; + aa.autoCalculated = true; + + if (showSSConsensus) + { + alignment.addAnnotation(aa); + } + } // these should be extracted from the view model - style and settings for // derived annotation @@ -2080,7 +2212,7 @@ public abstract class AlignmentViewport { if (aa == null) { - System.err.println("Null annotation row: ignoring."); + jalview.bin.Console.errPrintln("Null annotation row: ignoring."); continue; } if (!aa.visible) @@ -2112,7 +2244,7 @@ public abstract class AlignmentViewport if (aa.graph > 0) { - aa.height += aa.graphHeight; + aa.height += aa.graphHeight + 20; } if (aa.height == 0) @@ -2139,14 +2271,16 @@ public abstract class AlignmentViewport boolean conv = isShowGroupConservation(); boolean cons = isShowGroupConsensus(); boolean showprf = isShowSequenceLogo(); + boolean showSSprf = isShowSequenceSSLogo(); boolean showConsHist = isShowConsensusHistogram(); + boolean showSSConsHist = isShowSSConsensusHistogram(); boolean normLogo = isNormaliseSequenceLogo(); /** * TODO reorder the annotation rows according to group/sequence ordering on * alignment */ - boolean sortg = true; + // boolean sortg = true; // remove old automatic annotation // add any new annotation @@ -2176,7 +2310,9 @@ public abstract class AlignmentViewport { // set defaults for this group's conservation/consensus sg.setshowSequenceLogo(showprf); + sg.setshowSequenceSSLogo(showSSprf); sg.setShowConsensusHistogram(showConsHist); + sg.setShowSSConsensusHistogram(showSSConsHist); sg.setNormaliseSequenceLogo(normLogo); } if (conv) @@ -2188,6 +2324,7 @@ public abstract class AlignmentViewport { updateCalcs = true; alignment.addAnnotation(sg.getConsensus(), 0); + alignment.addAnnotation(sg.getSSConsensus(), 0); } // refresh the annotation rows if (updateCalcs) @@ -2256,7 +2393,7 @@ public abstract class AlignmentViewport public void clearSequenceColours() { sequenceColours.clear(); - }; + } @Override public AlignViewportI getCodingComplement() @@ -2273,7 +2410,8 @@ public abstract class AlignmentViewport { if (this == av) { - System.err.println("Ignoring recursive setCodingComplement request"); + jalview.bin.Console + .errPrintln("Ignoring recursive setCodingComplement request"); } else { @@ -2604,6 +2742,8 @@ public abstract class AlignmentViewport { this.historyList.push(command); broadcastCommand(command, false); + setSavedUpToDate(false); + Jalview2XML.setStateSavedUpToDate(false); } } @@ -2709,6 +2849,30 @@ public abstract class AlignmentViewport viewStyle.setProteinFontAsCdna(b); } + @Override + public void setShowComplementFeatures(boolean b) + { + viewStyle.setShowComplementFeatures(b); + } + + @Override + public boolean isShowComplementFeatures() + { + return viewStyle.isShowComplementFeatures(); + } + + @Override + public void setShowComplementFeaturesOnTop(boolean b) + { + viewStyle.setShowComplementFeaturesOnTop(b); + } + + @Override + public boolean isShowComplementFeaturesOnTop() + { + return viewStyle.isShowComplementFeaturesOnTop(); + } + /** * @return true if view should scroll to show the highlighted region of a * sequence @@ -2781,7 +2945,7 @@ public abstract class AlignmentViewport int lastSeq = alignment.getHeight() - 1; List seqMappings = null; for (int seqNo = ranges - .getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++) + .getStartSeq(); seqNo <= lastSeq; seqNo++, seqOffset++) { sequence = getAlignment().getSequenceAt(seqNo); if (hiddenSequences != null && hiddenSequences.isHidden(sequence)) @@ -2897,6 +3061,19 @@ public abstract class AlignmentViewport return searchResults; } + @Override + public ContactListI getContactList(AlignmentAnnotation _aa, int column) + { + return alignment.getContactListFor(_aa, column); + } + + @Override + public ContactMatrixI getContactMatrix( + AlignmentAnnotation alignmentAnnotation) + { + return alignment.getContactMatrixFor(alignmentAnnotation); + } + /** * get the consensus sequence as displayed under the PID consensus annotation * row. @@ -2937,6 +3114,41 @@ public abstract class AlignmentViewport + ((ignoreGapsInConsensusCalculation) ? " without gaps" : "")); return sq; } + + public SequenceI getSSConsensusSeq() + { + if (secondaryStructureConsensus == null) + { + updateSecondaryStructureConsensus(null); + } + if (secondaryStructureConsensus == null) + { + return null; + } + StringBuffer seqs = new StringBuffer(); + for (int i = 0; i < secondaryStructureConsensus.annotations.length; i++) + { + Annotation annotation = secondaryStructureConsensus.annotations[i]; + if (annotation != null) + { + String description = annotation.description; + if (description != null && description.startsWith("[")) + { + // consensus is a tie - just pick the first one + seqs.append(description.charAt(1)); + } + else + { + seqs.append(annotation.displayCharacter); + } + } + } + + SequenceI sq = new Sequence("Sec Str Consensus", seqs.toString()); + sq.setDescription("Percentage Identity Sec Str Consensus " + + ((ignoreGapsInConsensusCalculation) ? " without gaps" : "")); + return sq; + } @Override public void setCurrentTree(TreeModel tree) @@ -2949,4 +3161,137 @@ public abstract class AlignmentViewport { return currentTree; } + + @Override + public AlignmentExportData getAlignExportData( + AlignExportSettingsI options) + { + AlignmentI alignmentToExport = null; + String[] omitHidden = null; + alignmentToExport = null; + + if (hasHiddenColumns() && !options.isExportHiddenColumns()) + { + omitHidden = getViewAsString(false, + options.isExportHiddenSequences()); + } + + int[] alignmentStartEnd = new int[2]; + if (hasHiddenRows() && options.isExportHiddenSequences()) + { + alignmentToExport = getAlignment().getHiddenSequences() + .getFullAlignment(); + } + else + { + alignmentToExport = getAlignment(); + } + alignmentStartEnd = getAlignment().getHiddenColumns() + .getVisibleStartAndEndIndex(alignmentToExport.getWidth()); + AlignmentExportData ed = new AlignmentExportData(alignmentToExport, + omitHidden, alignmentStartEnd); + return ed; + } + + /** + * flag set to indicate if structure views might be out of sync with sequences + * in the alignment + */ + + private boolean needToUpdateStructureViews = false; + + @Override + public boolean isUpdateStructures() + { + return needToUpdateStructureViews; + } + + @Override + public void setUpdateStructures(boolean update) + { + needToUpdateStructureViews = update; + } + + @Override + public boolean needToUpdateStructureViews() + { + boolean update = needToUpdateStructureViews; + needToUpdateStructureViews = false; + return update; + } + + @Override + public void addSequenceGroup(SequenceGroup sequenceGroup) + { + alignment.addGroup(sequenceGroup); + + Color col = sequenceGroup.idColour; + if (col != null) + { + col = col.brighter(); + + for (SequenceI sq : sequenceGroup.getSequences()) + { + setSequenceColour(sq, col); + } + } + + if (codingComplement != null) + { + SequenceGroup mappedGroup = MappingUtils + .mapSequenceGroup(sequenceGroup, this, codingComplement); + if (mappedGroup.getSequences().size() > 0) + { + codingComplement.getAlignment().addGroup(mappedGroup); + + if (col != null) + { + for (SequenceI seq : mappedGroup.getSequences()) + { + codingComplement.setSequenceColour(seq, col); + } + } + } + // propagate the structure view update flag according to our own setting + codingComplement.setUpdateStructures(needToUpdateStructureViews); + } + } + + @Override + public Iterator getViewAsVisibleContigs(boolean selectedRegionOnly) + { + int start = 0; + int end = 0; + if (selectedRegionOnly && selectionGroup != null) + { + start = selectionGroup.getStartRes(); + end = selectionGroup.getEndRes() + 1; + } + else + { + end = alignment.getWidth(); + } + return (alignment.getHiddenColumns().getVisContigsIterator(start, end, + false)); + } + + public void setSavedUpToDate(boolean s) + { + setSavedUpToDate(s, QuitHandler.Message.UNSAVED_CHANGES); + } + + public void setSavedUpToDate(boolean s, QuitHandler.Message m) + { + Console.debug( + "Setting " + this.getViewId() + " setSavedUpToDate to " + s); + savedUpToDate = s; + QuitHandler.setMessage(m); + } + + public boolean savedUpToDate() + { + Console.debug("Returning " + this.getViewId() + " savedUpToDate value: " + + savedUpToDate); + return savedUpToDate; + } }