/* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package jalview.gui; import jalview.analysis.*; import jalview.bin.*; import jalview.datamodel.*; import jalview.schemes.*; import java.awt.*; import java.util.*; /** * DOCUMENT ME! * * @author $author$ * @version $Revision$ */ public class AlignViewport { int startRes; int endRes; int startSeq; int endSeq; boolean showJVSuffix = true; boolean showText = true; boolean showColourText = false; boolean showBoxes = true; boolean wrapAlignment = false; boolean renderGaps = true; boolean showSequenceFeatures = false; boolean showAnnotation = true; boolean showConservation = true; boolean showQuality = true; boolean showIdentity = true; boolean colourAppliesToAllGroups = true; ColourSchemeI globalColourScheme = null; boolean conservationColourSelected = false; boolean abovePIDThreshold = false; SequenceGroup selectionGroup; int charHeight; int charWidth; boolean validCharWidth; int wrappedWidth; Font font; AlignmentI alignment; ColumnSelection colSel = new ColumnSelection(); int threshold; int increment; NJTree currentTree = null; boolean scaleAboveWrapped = false; boolean scaleLeftWrapped = true; boolean scaleRightWrapped = true; boolean hasHiddenColumns = false; boolean hasHiddenRows = false; boolean showHiddenMarkers = true; boolean cursorMode = false; // The following vector holds the features which are // currently visible, in the correct order or rendering Hashtable featuresDisplayed = null; /** DOCUMENT ME!! */ public Hashtable [] hconsensus; AlignmentAnnotation consensus; AlignmentAnnotation conservation; AlignmentAnnotation quality; boolean autoCalculateConsensus = true; /** DOCUMENT ME!! */ public int ConsPercGaps = 25; // JBPNote : This should be a scalable property! // JBPNote Prolly only need this in the applet version. private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(this); boolean ignoreGapsInConsensusCalculation = false; boolean isDataset = false; boolean antiAlias = false; boolean padGaps = false; Rectangle explodedPosition; String viewName; String sequenceSetID; boolean gatherViewsHere = false; public AlignViewport(AlignmentI al, boolean dataset) { isDataset = dataset; setAlignment(al); init(); } /** * Creates a new AlignViewport object. * * @param al DOCUMENT ME! */ public AlignViewport(AlignmentI al) { setAlignment(al); init(); } /** * Create a new AlignViewport with hidden regions * @param al AlignmentI * @param hiddenColumns ColumnSelection */ public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns) { setAlignment(al); if (hiddenColumns!=null) { this.colSel = hiddenColumns; if (hiddenColumns.getHiddenColumns() != null) hasHiddenColumns = true; } init(); } void init() { this.startRes = 0; this.endRes = alignment.getWidth() - 1; this.startSeq = 0; this.endSeq = alignment.getHeight() - 1; antiAlias = Cache.getDefault("ANTI_ALIAS", false); showJVSuffix = Cache.getDefault("SHOW_JVSUFFIX", true); showAnnotation = Cache.getDefault("SHOW_ANNOTATIONS", true); showConservation = Cache.getDefault("SHOW_CONSERVATION", true); showQuality = Cache.getDefault("SHOW_QUALITY", true); showIdentity = Cache.getDefault("SHOW_IDENTITY", true); autoCalculateConsensus = Cache.getDefault("AUTO_CALC_CONSENSUS", true); padGaps = Cache.getDefault("PAD_GAPS", false); String fontName = Cache.getDefault("FONT_NAME", "SansSerif"); String fontStyle = Cache.getDefault("FONT_STYLE", Font.PLAIN + "") ; String fontSize = Cache.getDefault("FONT_SIZE", "10"); int style = 0; if (fontStyle.equals("bold")) { style = 1; } else if (fontStyle.equals("italic")) { style = 2; } setFont(new Font(fontName, style, Integer.parseInt(fontSize))); alignment.setGapCharacter( Cache.getDefault("GAP_SYMBOL", "-").charAt(0) ); // We must set conservation and consensus before setting colour, // as Blosum and Clustal require this to be done if(hconsensus==null && !isDataset) { if(!alignment.isNucleotide()) { conservation = new AlignmentAnnotation("Conservation", "Conservation of total alignment less than " + ConsPercGaps + "% gaps", new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH); conservation.hasText = true; if (showConservation) { alignment.addAnnotation(conservation); } if (showQuality) { quality = new AlignmentAnnotation("Quality", "Alignment Quality based on Blosum62 scores", new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH); quality.hasText = true; alignment.addAnnotation(quality); } } consensus = new AlignmentAnnotation("Consensus", "PID", new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH); consensus.hasText = true; if (showIdentity) { alignment.addAnnotation(consensus); } } if (jalview.bin.Cache.getProperty("DEFAULT_COLOUR") != null) { globalColourScheme = ColourSchemeProperty.getColour(alignment, jalview.bin.Cache.getProperty("DEFAULT_COLOUR")); if (globalColourScheme instanceof UserColourScheme) { globalColourScheme = UserDefinedColours.loadDefaultColours(); ((UserColourScheme)globalColourScheme).setThreshold(0, getIgnoreGapsConsensus()); } if (globalColourScheme != null) { globalColourScheme.setConsensus(hconsensus); } } } /** * DOCUMENT ME! * * @param b DOCUMENT ME! */ public void setShowSequenceFeatures(boolean b) { showSequenceFeatures = b; } public boolean getShowSequenceFeatures() { return showSequenceFeatures; } class ConservationThread extends Thread { AlignmentPanel ap; public ConservationThread(AlignmentPanel ap) { this.ap = ap; } public void run() { try { int alWidth = alignment.getWidth(); if(alWidth<0) return; Conservation cons = new jalview.analysis.Conservation("All", jalview.schemes.ResidueProperties.propHash, 3, alignment.getSequences(), 0, alWidth -1); cons.calculate(); cons.verdict(false, ConsPercGaps); if (quality!=null) { cons.findQuality(); } String sequence = cons.getConsSequence().getSequence(); float minR; float minG; float minB; float maxR; float maxG; float maxB; minR = 0.3f; minG = 0.0f; minB = 0f; maxR = 1.0f - minR; maxG = 0.9f - minG; maxB = 0f - minB; // scalable range for colouring both Conservation and Quality float min = 0f; float max = 11f; float qmin = 0f; float qmax = 0f; char c; conservation.annotations = new Annotation[alWidth]; if (quality!=null) { quality.graphMax = cons.qualityRange[1].floatValue(); quality.annotations = new Annotation[alWidth]; qmin = cons.qualityRange[0].floatValue(); qmax = cons.qualityRange[1].floatValue(); } for (int i = 0; i < alWidth; i++) { float value = 0; c = sequence.charAt(i); if (Character.isDigit(c)) value = (int) (c - '0'); else if (c == '*') value = 11; else if (c == '+') value = 10; float vprop = value - min; vprop /= max; conservation.annotations[i] = new Annotation(String.valueOf(c), String.valueOf(value), ' ', value, new Color(minR + (maxR * vprop), minG + (maxG * vprop), minB + (maxB * vprop))); // Quality calc if (quality!=null) { value = ( (Double) cons.quality.get(i)).floatValue(); vprop = value - qmin; vprop /= qmax; quality.annotations[i] = new Annotation(" ", String.valueOf(value), ' ', value, new Color(minR + (maxR * vprop), minG + (maxG * vprop), minB + (maxB * vprop))); } } } catch (OutOfMemoryError error) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop, "Out of memory calculating conservation!!" + "\nSee help files for increasing Java Virtual Machine memory." , "Out of memory", javax.swing.JOptionPane.WARNING_MESSAGE); } }); conservation = null; quality = null; System.out.println("Conservation calculation: " + error); System.gc(); } if(ap!=null) { ap.repaint(); } updatingConservation = false; } } ConservationThread conservationThread; ConsensusThread consensusThread; boolean consUpdateNeeded = false; boolean updatingConsensus = false; boolean updatingConservation = false; /** * DOCUMENT ME! */ public void updateConservation(AlignmentPanel ap) { if (alignment.isNucleotide()) return; updatingConservation = true; if (conservationThread == null || !conservationThread.isAlive()) { conservationThread = new ConservationThread(ap); conservationThread.start(); } else { consUpdateNeeded = true; System.out.println("come back later"); } } /** * DOCUMENT ME! */ public void updateConsensus(AlignmentPanel ap) { updatingConsensus = true; if (consensusThread == null || !consensusThread.isAlive()) { consensusThread = new ConsensusThread(ap); consensusThread.start(); } else { consUpdateNeeded = true; System.out.println("come back later"); } } class ConsensusThread extends Thread { AlignmentPanel ap; public ConsensusThread(AlignmentPanel ap) { this.ap = ap; } public void run() { try { int aWidth = alignment.getWidth(); if(aWidth<0) return; consensus.annotations = null; consensus.annotations = new Annotation[aWidth]; hconsensus = new Hashtable[aWidth]; AAFrequency.calculate(alignment.getSequencesArray(), 0, alignment.getWidth(), hconsensus); for (int i = 0; i < aWidth; i++) { float value = 0; if (ignoreGapsInConsensusCalculation) value = ( (Float) hconsensus[i].get(AAFrequency.PID_NOGAPS)). floatValue(); else value = ( (Float) hconsensus[i].get(AAFrequency.PID_GAPS)). floatValue(); String maxRes = hconsensus[i].get(AAFrequency.MAXRESIDUE).toString(); String mouseOver = hconsensus[i].get(AAFrequency.MAXRESIDUE) + " "; if (maxRes.length() > 1) { mouseOver = "[" + maxRes + "] "; maxRes = "+"; } mouseOver += ( (int) value + "%"); consensus.annotations[i] = new Annotation(maxRes, mouseOver, ' ', value); } if (globalColourScheme != null) globalColourScheme.setConsensus(hconsensus); } catch (OutOfMemoryError error) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { javax.swing.JOptionPane.showInternalMessageDialog(Desktop.desktop, "Out of memory calculating consensus!!" + "\nSee help files for increasing Java Virtual Machine memory." , "Out of memory", javax.swing.JOptionPane.WARNING_MESSAGE); } }); System.out.println("Consensus calculation: " + error); System.gc(); } if (ap != null) { ap.repaint(); } updatingConsensus = false; } } /** * get the consensus sequence as displayed under the PID consensus annotation row. * @return consensus sequence as a new sequence object */ public SequenceI getConsensusSeq() { if (consensus==null) updateConsensus(null); if (consensus==null) return null; StringBuffer seqs=new StringBuffer(); for (int i=0; i (alignment.getWidth() - 1)) { // log.System.out.println(" Corrected res from " + res + " to maximum " + (alignment.getWidth()-1)); res = alignment.getWidth() - 1; } if (res < 0) { res = 0; } this.endRes = res; } /** * DOCUMENT ME! * * @param seq DOCUMENT ME! */ public void setEndSeq(int seq) { if (seq > alignment.getHeight()) { seq = alignment.getHeight(); } if (seq < 0) { seq = 0; } this.endSeq = seq; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getEndSeq() { return endSeq; } /** * DOCUMENT ME! * * @param f DOCUMENT ME! */ public void setFont(Font f) { font = f; Container c = new Container(); java.awt.FontMetrics fm = c.getFontMetrics(font); setCharHeight(fm.getHeight()); setCharWidth(fm.charWidth('M')); validCharWidth = true; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public Font getFont() { return font; } /** * DOCUMENT ME! * * @param w DOCUMENT ME! */ public void setCharWidth(int w) { this.charWidth = w; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getCharWidth() { return charWidth; } /** * DOCUMENT ME! * * @param h DOCUMENT ME! */ public void setCharHeight(int h) { this.charHeight = h; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getCharHeight() { return charHeight; } /** * DOCUMENT ME! * * @param w DOCUMENT ME! */ public void setWrappedWidth(int w) { this.wrappedWidth = w; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getWrappedWidth() { return wrappedWidth; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public AlignmentI getAlignment() { return alignment; } /** * DOCUMENT ME! * * @param align DOCUMENT ME! */ public void setAlignment(AlignmentI align) { this.alignment = align; } /** * DOCUMENT ME! * * @param state DOCUMENT ME! */ public void setWrapAlignment(boolean state) { wrapAlignment = state; } /** * DOCUMENT ME! * * @param state DOCUMENT ME! */ public void setShowText(boolean state) { showText = state; } /** * DOCUMENT ME! * * @param state DOCUMENT ME! */ public void setRenderGaps(boolean state) { renderGaps = state; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getColourText() { return showColourText; } /** * DOCUMENT ME! * * @param state DOCUMENT ME! */ public void setColourText(boolean state) { showColourText = state; } /** * DOCUMENT ME! * * @param state DOCUMENT ME! */ public void setShowBoxes(boolean state) { showBoxes = state; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getWrapAlignment() { return wrapAlignment; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getShowText() { return showText; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getShowBoxes() { return showBoxes; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public char getGapCharacter() { return getAlignment().getGapCharacter(); } /** * DOCUMENT ME! * * @param gap DOCUMENT ME! */ public void setGapCharacter(char gap) { if (getAlignment() != null) { getAlignment().setGapCharacter(gap); } } /** * DOCUMENT ME! * * @param thresh DOCUMENT ME! */ public void setThreshold(int thresh) { threshold = thresh; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getThreshold() { return threshold; } /** * DOCUMENT ME! * * @param inc DOCUMENT ME! */ public void setIncrement(int inc) { increment = inc; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getIncrement() { return increment; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public ColumnSelection getColumnSelection() { return colSel; } /** * DOCUMENT ME! * * @param tree DOCUMENT ME! */ public void setCurrentTree(NJTree tree) { currentTree = tree; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public NJTree getCurrentTree() { return currentTree; } /** * DOCUMENT ME! * * @param b DOCUMENT ME! */ public void setColourAppliesToAllGroups(boolean b) { colourAppliesToAllGroups = b; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getColourAppliesToAllGroups() { return colourAppliesToAllGroups; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getShowJVSuffix() { return showJVSuffix; } /** * DOCUMENT ME! * * @param b DOCUMENT ME! */ public void setShowJVSuffix(boolean b) { showJVSuffix = b; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getShowAnnotation() { return showAnnotation; } /** * DOCUMENT ME! * * @param b DOCUMENT ME! */ public void setShowAnnotation(boolean b) { showAnnotation = b; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getScaleAboveWrapped() { return scaleAboveWrapped; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getScaleLeftWrapped() { return scaleLeftWrapped; } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public boolean getScaleRightWrapped() { return scaleRightWrapped; } /** * DOCUMENT ME! * * @param b DOCUMENT ME! */ public void setScaleAboveWrapped(boolean b) { scaleAboveWrapped = b; } /** * DOCUMENT ME! * * @param b DOCUMENT ME! */ public void setScaleLeftWrapped(boolean b) { scaleLeftWrapped = b; } /** * DOCUMENT ME! * * @param b DOCUMENT ME! */ public void setScaleRightWrapped(boolean b) { scaleRightWrapped = b; } /** * Property change listener for changes in alignment * * @param listener DOCUMENT ME! */ public void addPropertyChangeListener( java.beans.PropertyChangeListener listener) { changeSupport.addPropertyChangeListener(listener); } /** * DOCUMENT ME! * * @param listener DOCUMENT ME! */ public void removePropertyChangeListener( java.beans.PropertyChangeListener listener) { changeSupport.removePropertyChangeListener(listener); } /** * Property change listener for changes in alignment * * @param prop DOCUMENT ME! * @param oldvalue DOCUMENT ME! * @param newvalue DOCUMENT ME! */ public void firePropertyChange(String prop, Object oldvalue, Object newvalue) { changeSupport.firePropertyChange(prop, oldvalue, newvalue); } public void setIgnoreGapsConsensus(boolean b, AlignmentPanel ap) { ignoreGapsInConsensusCalculation = b; updateConsensus(ap); if(globalColourScheme!=null) { globalColourScheme.setThreshold(globalColourScheme.getThreshold(), ignoreGapsInConsensusCalculation); } } public boolean getIgnoreGapsConsensus() { return ignoreGapsInConsensusCalculation; } public void setDataset(boolean b) { isDataset = b; } public boolean isDataset() { return isDataset; } public void hideSelectedColumns() { if (colSel.size() < 1) return; colSel.hideSelectedColumns(); setSelectionGroup(null); hasHiddenColumns = true; } public void hideColumns(int start, int end) { if(start==end) colSel.hideColumns(start); else colSel.hideColumns(start, end); hasHiddenColumns = true; } public void hideAllSelectedSeqs() { if (selectionGroup == null) return; SequenceI[] seqs = selectionGroup.getSequencesInOrder(alignment); hideSequence(seqs); setSelectionGroup(null); } public void hideSequence(SequenceI [] seq) { if(seq!=null) { for (int i = 0; i < seq.length; i++) alignment.getHiddenSequences().hideSequence(seq[i]); hasHiddenRows = true; firePropertyChange("alignment", null, alignment.getSequences()); } } public void showSequence(int index) { Vector tmp = alignment.getHiddenSequences().showSequence(index); if(tmp.size()>0) { if(selectionGroup==null) { selectionGroup = new SequenceGroup(); selectionGroup.setEndRes(alignment.getWidth()-1); } for (int t = 0; t < tmp.size(); t++) { selectionGroup.addSequence( (SequenceI) tmp.elementAt(t), false ); } firePropertyChange("alignment", null, alignment.getSequences()); } if(alignment.getHiddenSequences().getSize()<1) hasHiddenRows = false; } public void showColumn(int col) { colSel.revealHiddenColumns(col); if(colSel.getHiddenColumns()==null) hasHiddenColumns = false; } public void showAllHiddenColumns() { colSel.revealAllHiddenColumns(); hasHiddenColumns = false; } public void showAllHiddenSeqs() { if(alignment.getHiddenSequences().getSize()>0) { if(selectionGroup==null) { selectionGroup = new SequenceGroup(); selectionGroup.setEndRes(alignment.getWidth()-1); } Vector tmp = alignment.getHiddenSequences().showAll(); for(int t=0; t