/* * 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.appletgui; import java.util.*; import java.awt.*; import jalview.analysis.*; import jalview.bin.*; import jalview.datamodel.*; import jalview.schemes.*; public class AlignViewport { int startRes; int endRes; int startSeq; int endSeq; boolean cursorMode = false; 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 showConsensus = true; boolean upperCasebold = false; boolean colourAppliesToAllGroups = true; ColourSchemeI globalColourScheme = null; boolean conservationColourSelected = false; boolean abovePIDThreshold = false; SequenceGroup selectionGroup; int charHeight; int charWidth; int wrappedWidth; Font font = new Font("SansSerif", Font.PLAIN, 10); boolean validCharWidth = true; AlignmentI alignment; ColumnSelection colSel = new ColumnSelection(); int threshold; int increment; NJTree currentTree = null; boolean scaleAboveWrapped = true; boolean scaleLeftWrapped = true; boolean scaleRightWrapped = true; // The following vector holds the features which are // currently visible, in the correct order or rendering public Hashtable featuresDisplayed; boolean hasHiddenColumns = false; boolean hasHiddenRows = false; boolean showHiddenMarkers = true; public Hashtable [] hconsensus; AlignmentAnnotation consensus; AlignmentAnnotation conservation; AlignmentAnnotation quality; boolean autocalculateConsensus = true; public int ConsPercGaps = 25; // JBPNote : This should be a scalable property! private java.beans.PropertyChangeSupport changeSupport = new java.beans.PropertyChangeSupport(this); boolean ignoreGapsInConsensusCalculation = false; jalview.bin.JalviewLite applet; Hashtable sequenceColours; boolean MAC = false; Stack historyList = new Stack(); Stack redoList = new Stack(); String sequenceSetID; Hashtable hiddenRepSequences; public AlignViewport(AlignmentI al, JalviewLite applet) { this.applet = applet; setAlignment(al); this.startRes = 0; this.endRes = al.getWidth() - 1; this.startSeq = 0; this.endSeq = al.getHeight() - 1; setFont(font); if(System.getProperty("os.name").startsWith("Mac")) MAC = true; if (applet != null) { String param = applet.getParameter("showFullId"); if (param != null) { showJVSuffix = Boolean.valueOf(param).booleanValue(); } param = applet.getParameter("showAnnotation"); if (param != null) { showAnnotation = Boolean.valueOf(param).booleanValue(); } param = applet.getParameter("showConservation"); if (param != null) { showConservation = Boolean.valueOf(param).booleanValue(); } param = applet.getParameter("showQuality"); if (param != null) { showQuality = Boolean.valueOf(param).booleanValue(); } param = applet.getParameter("showConsensus"); if (param != null) { showConsensus = Boolean.valueOf(param).booleanValue(); } param = applet.getParameter("upperCase"); if (param != null) { if(param.equalsIgnoreCase("bold")) upperCasebold = true; } } if (applet != null) { String colour = applet.getParameter("defaultColour"); if(colour == null) { colour = applet.getParameter("userDefinedColour"); if(colour !=null) colour = "User Defined"; } if(colour != null) { globalColourScheme = ColourSchemeProperty.getColour(alignment, colour); if (globalColourScheme != null) { globalColourScheme.setConsensus(hconsensus); } } if(applet.getParameter("userDefinedColour")!=null) { ((UserColourScheme)globalColourScheme).parseAppletParameter( applet.getParameter("userDefinedColour")); } if(hconsensus==null) { 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 (showConsensus) { alignment.addAnnotation(consensus); } } } } public void showSequenceFeatures(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 { updatingConservation = true; while (UPDATING_CONSERVATION) { try { if (ap != null) { ap.repaint(); } Thread.sleep(200); } catch (Exception ex) { ex.printStackTrace(); } } UPDATING_CONSERVATION = true; 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(); } char [] 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[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.elementAt(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) { System.out.println("Out of memory calculating conservation!!"); conservation = null; quality = null; System.gc(); } UPDATING_CONSERVATION = false; updatingConservation = false; if(ap!=null) { ap.repaint(); } } } ConservationThread conservationThread; ConsensusThread consensusThread; boolean consUpdateNeeded = false; static boolean UPDATING_CONSENSUS = false; static boolean UPDATING_CONSERVATION = false; boolean updatingConsensus = false; boolean updatingConservation = false; /** * DOCUMENT ME! */ public void updateConservation(final AlignmentPanel ap) { if (alignment.isNucleotide() || conservation==null) return; conservationThread = new ConservationThread(ap); conservationThread.start(); } /** * DOCUMENT ME! */ public void updateConsensus(final AlignmentPanel ap) { consensusThread = new ConsensusThread(ap); consensusThread.start(); } class ConsensusThread extends Thread { AlignmentPanel ap; public ConsensusThread(AlignmentPanel ap) { this.ap = ap; } public void run() { updatingConsensus = true; while (UPDATING_CONSENSUS) { try { if (ap != null) { ap.repaint(); } Thread.sleep(200); } catch (Exception ex) { ex.printStackTrace(); } } UPDATING_CONSENSUS = true; 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) { alignment.deleteAnnotation(consensus); consensus = null; hconsensus = null; System.out.println("Out of memory calculating consensus!!"); System.gc(); } UPDATING_CONSENSUS = false; updatingConsensus = false; if (ap != null) { ap.repaint(); } } } /** * get the consensus sequence as displayed under the PID consensus annotation row. * @return consensus sequence as a new sequence object */ /** * 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) 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; } public void setEndSeq(int seq) { if (seq > alignment.getHeight()) { seq = alignment.getHeight(); } if (seq < 0) { seq = 0; } this.endSeq = seq; } public int getEndSeq() { return endSeq; } java.awt.Frame nullFrame; public void setFont(Font f) { font = f; if(nullFrame == null) { nullFrame = new java.awt.Frame(); nullFrame.addNotify(); } java.awt.FontMetrics fm = nullFrame.getGraphics().getFontMetrics(font); setCharHeight(fm.getHeight()); charWidth = fm.charWidth('M'); if(upperCasebold) { Font f2 = new Font(f.getName(), Font.BOLD, f.getSize()); fm = nullFrame.getGraphics().getFontMetrics(f2); charWidth = fm.stringWidth("MMMMMMMMMMM") / 10; } } public Font getFont() { return font; } public int getCharWidth() { return charWidth; } public void setCharHeight(int h) { this.charHeight = h; } public int getCharHeight() { return charHeight; } public void setWrappedWidth(int w) { this.wrappedWidth = w; } public int getwrappedWidth() { return wrappedWidth; } public AlignmentI getAlignment() { return alignment; } public void setAlignment(AlignmentI align) { this.alignment = align; } public void setWrapAlignment(boolean state) { wrapAlignment = state; } public void setShowText(boolean state) { showText = state; } public void setRenderGaps(boolean state) { renderGaps = state; } public boolean getColourText() { return showColourText; } public void setColourText(boolean state) { showColourText = state; } public void setShowBoxes(boolean state) { showBoxes = state; } public boolean getWrapAlignment() { return wrapAlignment; } public boolean getShowText() { return showText; } public boolean getShowBoxes() { return showBoxes; } public char getGapCharacter() { return getAlignment().getGapCharacter(); } public void setGapCharacter(char gap) { if (getAlignment() != null) { getAlignment().setGapCharacter(gap); } } public void setThreshold(int thresh) { threshold = thresh; } public int getThreshold() { return threshold; } public void setIncrement(int inc) { increment = inc; } public int getIncrement() { return increment; } public void setHiddenColumns(ColumnSelection colsel) { this.colSel = colsel; if(colSel.getHiddenColumns()!=null) hasHiddenColumns = true; } public ColumnSelection getColumnSelection() { return colSel; } public void resetSeqLimits(int height) { setEndSeq(height / getCharHeight()); } public void setCurrentTree(NJTree tree) { currentTree = tree; } public NJTree getCurrentTree() { return currentTree; } public void setColourAppliesToAllGroups(boolean b) { colourAppliesToAllGroups = b; } public boolean getColourAppliesToAllGroups() { return colourAppliesToAllGroups; } public boolean getShowJVSuffix() { return showJVSuffix; } public void setShowJVSuffix(boolean b) { showJVSuffix = b; } public boolean getShowAnnotation() { return showAnnotation; } public void setShowAnnotation(boolean b) { showAnnotation = b; } public boolean getScaleAboveWrapped() { return scaleAboveWrapped; } public boolean getScaleLeftWrapped() { return scaleLeftWrapped; } public boolean getScaleRightWrapped() { return scaleRightWrapped; } public void setScaleAboveWrapped(boolean b) { scaleAboveWrapped = b; } public void setScaleLeftWrapped(boolean b) { scaleLeftWrapped = b; } public void setScaleRightWrapped(boolean b) { scaleRightWrapped = b; } public void setIgnoreGapsConsensus(boolean b) { ignoreGapsInConsensusCalculation = b; updateConsensus(null); if (globalColourScheme!=null) { globalColourScheme.setThreshold(globalColourScheme.getThreshold(), ignoreGapsInConsensusCalculation); } } /** * 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 boolean getIgnoreGapsConsensus() { return ignoreGapsInConsensusCalculation; } public void hideSelectedColumns() { if (colSel.size() < 1) return; colSel.hideSelectedColumns(); setSelectionGroup(null); hasHiddenColumns = true; } public void invertColumnSelection() { for (int i = 0; i < alignment.getWidth(); i++) { if (colSel.contains(i)) colSel.removeElement(i); else { if (!hasHiddenColumns || colSel.isVisible(i)) { colSel.addElement(i); } } } } public void hideColumns(int start, int end) { if(start==end) colSel.hideColumns(start); else colSel.hideColumns(start, end); hasHiddenColumns = true; } public void hideRepSequences(SequenceI repSequence, SequenceGroup sg) { int sSize = sg.getSize(); if(sSize < 2) return; if(hiddenRepSequences==null) hiddenRepSequences = new Hashtable(); hiddenRepSequences.put(repSequence, sg); //Hide all sequences except the repSequence SequenceI [] seqs = new SequenceI[sSize-1]; int index = 0; for(int i=0; i0) { if(selectionGroup==null) { selectionGroup = new SequenceGroup(); selectionGroup.setEndRes(alignment.getWidth()-1); } Vector tmp = alignment.getHiddenSequences().showAll(hiddenRepSequences); for(int t=0; t