X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAlignmentPanel.java;h=f72379453e551b21384870118062d0e9c827d830;hb=f820a6e0b7ec599b0e040109c3361cdb3e6d9aa0;hp=769dc863494ce708ff2663fcc0f92345fc44854d;hpb=14033157f9235c071763ae61cb8d2785b07ec96f;p=jalview.git diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 769dc86..f723794 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -23,18 +23,24 @@ package jalview.gui; import jalview.analysis.AnnotationSorter; import jalview.api.AlignViewportI; import jalview.api.AlignmentViewPanel; +import jalview.api.SequenceRenderer; import jalview.bin.Cache; +import jalview.bin.Jalview; import jalview.datamodel.AlignmentI; +import jalview.datamodel.HiddenColumns; import jalview.datamodel.SearchResultsI; import jalview.datamodel.SequenceFeature; import jalview.datamodel.SequenceGroup; import jalview.datamodel.SequenceI; +import jalview.gui.ImageExporter.ImageWriterI; +import jalview.io.HTMLOutput; import jalview.jbgui.GAlignmentPanel; import jalview.math.AlignmentDimension; import jalview.schemes.ResidueProperties; import jalview.structure.StructureSelectionManager; +import jalview.util.Comparison; +import jalview.util.ImageMaker; import jalview.util.MessageManager; -import jalview.util.Platform; import jalview.viewmodel.ViewportListenerI; import jalview.viewmodel.ViewportRanges; @@ -45,7 +51,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; -import java.awt.Insets; +import java.awt.Graphics2D; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentAdapter; @@ -68,25 +74,20 @@ import javax.swing.SwingUtilities; * @author $author$ * @version $Revision: 1.161 $ */ +@SuppressWarnings("serial") public class AlignmentPanel extends GAlignmentPanel implements - AdjustmentListener, Printable, AlignmentViewPanel, - ViewportListenerI + AdjustmentListener, Printable, AlignmentViewPanel, ViewportListenerI { public AlignViewport av; - ViewportRanges vpRanges; - OverviewPanel overviewPanel; private SeqPanel seqPanel; private IdPanel idPanel; - private boolean headless; - IdwidthAdjuster idwidthAdjuster; - /** DOCUMENT ME!! */ public AlignFrame alignFrame; private ScalePanel scalePanel; @@ -95,9 +96,6 @@ public class AlignmentPanel extends GAlignmentPanel implements private AnnotationLabels alabels; - // this value is set false when selection area being dragged - boolean fastPaint = true; - private int hextent = 0; private int vextent = 0; @@ -110,6 +108,8 @@ public class AlignmentPanel extends GAlignmentPanel implements private PropertyChangeListener propertyChangeListener; + private CalculationChooser calculationDialog; + /** * Creates a new AlignmentPanel object. * @@ -118,9 +118,10 @@ public class AlignmentPanel extends GAlignmentPanel implements */ public AlignmentPanel(AlignFrame af, final AlignViewport av) { + setBackground(Color.white); // BH 2019 + setOpaque(true); alignFrame = af; this.av = av; - vpRanges = av.getRanges(); setSeqPanel(new SeqPanel(av, this)); setIdPanel(new IdPanel(av, this)); @@ -152,11 +153,12 @@ public class AlignmentPanel extends GAlignmentPanel implements // reset the viewport ranges when the alignment panel is resized // in particular, this initialises the end residue value when Jalview // is initialised + ViewportRanges ranges = av.getRanges(); if (av.getWrapAlignment()) { - int widthInRes = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - vpRanges.setViewportWidth(widthInRes); + int widthInRes = getSeqPanel().seqCanvas.getWrappedCanvasWidth( + getSeqPanel().seqCanvas.getWidth()); + ranges.setViewportWidth(widthInRes); } else { @@ -164,9 +166,9 @@ public class AlignmentPanel extends GAlignmentPanel implements / av.getCharWidth(); int heightInSeq = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); - - vpRanges.setViewportWidth(widthInRes); - vpRanges.setViewportHeight(heightInSeq); + + ranges.setViewportWidth(widthInRes); + ranges.setViewportHeight(heightInSeq); } } @@ -203,9 +205,15 @@ public class AlignmentPanel extends GAlignmentPanel implements { av.alignmentChanged(this); + if (getCalculationDialog() != null) + { + getCalculationDialog().validateCalcTypes(); + } + alignFrame.updateEditMenuBar(); - paintAlignment(true); + // no idea if we need to update structure + paintAlignment(true, true); } @@ -218,12 +226,13 @@ public class AlignmentPanel extends GAlignmentPanel implements // to prevent drawing old image FontMetrics fm = getFontMetrics(av.getFont()); - scalePanelHolder.setPreferredSize(new Dimension(10, av.getCharHeight() - + fm.getDescent())); - idSpaceFillerPanel1.setPreferredSize(new Dimension(10, av - .getCharHeight() + fm.getDescent())); - - getIdPanel().getIdCanvas().gg = null; + scalePanelHolder.setPreferredSize( + new Dimension(10, av.getCharHeight() + fm.getDescent())); + idSpaceFillerPanel1.setPreferredSize( + new Dimension(10, av.getCharHeight() + fm.getDescent())); + idwidthAdjuster.invalidate(); + scalePanelHolder.invalidate(); + // BH 2018 getIdPanel().getIdCanvas().gg = null; getSeqPanel().seqCanvas.img = null; getAnnotationPanel().adjustPanelHeight(); @@ -233,11 +242,6 @@ public class AlignmentPanel extends GAlignmentPanel implements getIdPanel().getIdCanvas().setPreferredSize(d); hscrollFillerPanel.setPreferredSize(d); - if (this.alignFrame.getSplitViewContainer() != null) - { - ((SplitFrame) this.alignFrame.getSplitViewContainer()).adjustLayout(); - } - repaint(); } @@ -281,8 +285,8 @@ public class AlignmentPanel extends GAlignmentPanel implements { Container c = new Container(); - FontMetrics fm = c.getFontMetrics(new Font(av.font.getName(), - Font.ITALIC, av.font.getSize())); + FontMetrics fm = c.getFontMetrics( + new Font(av.font.getName(), Font.ITALIC, av.font.getSize())); AlignmentI al = av.getAlignment(); int i = 0; @@ -323,29 +327,21 @@ public class AlignmentPanel extends GAlignmentPanel implements } } - return new Dimension(maxwidth < 0 ? idWidth : Math.min(maxwidth, - idWidth), 12); + return new Dimension( + maxwidth < 0 ? idWidth : Math.min(maxwidth, idWidth), 12); } /** - * Highlight the given results on the alignment. + * Highlight the given results on the alignment * */ public void highlightSearchResults(SearchResultsI results) { - scrollToPosition(results); - getSeqPanel().seqCanvas.highlightSearchResults(results); - } + boolean scrolled = scrollToPosition(results, 0, false); - /** - * Scroll the view to show the position of the highlighted region in results - * (if any) and redraw the overview - * - * @param results - */ - public boolean scrollToPosition(SearchResultsI results) - { - return scrollToPosition(results, 0, true, false); + boolean fastPaint = !(scrolled && av.getWrapAlignment()); + + getSeqPanel().seqCanvas.highlightSearchResults(results, fastPaint); } /** @@ -353,143 +349,137 @@ public class AlignmentPanel extends GAlignmentPanel implements * (if any) * * @param searchResults - * @param redrawOverview * @return */ - public boolean scrollToPosition(SearchResultsI searchResults, - boolean redrawOverview) + public boolean scrollToPosition(SearchResultsI searchResults) { - return scrollToPosition(searchResults, 0, redrawOverview, false); + return scrollToPosition(searchResults, 0, false); } /** - * Scroll the view to show the position of the highlighted region in results - * (if any) + * Scrolls the view (if necessary) to show the position of the first + * highlighted region in results (if any). Answers true if the view was + * scrolled, or false if no matched region was found, or it is already + * visible. * * @param results * @param verticalOffset * if greater than zero, allows scrolling to a position below the * first displayed sequence - * @param redrawOverview - * - when set, the overview will be recalculated (takes longer) * @param centre * if true, try to centre the search results horizontally in the view - * @return false if results were not found + * @return */ - public boolean scrollToPosition(SearchResultsI results, - int verticalOffset, boolean redrawOverview, boolean centre) + protected boolean scrollToPosition(SearchResultsI results, + int verticalOffset, boolean centre) { int startv, endv, starts, ends; - // TODO: properly locate search results in view when large numbers of hidden - // columns exist before highlighted region - // do we need to scroll the panel? - // TODO: tons of nullpointerexceptions raised here. - if (results != null && results.getSize() > 0 && av != null - && av.getAlignment() != null) - { - int seqIndex = av.getAlignment().findIndex(results); - if (seqIndex == -1) - { - return false; - } - SequenceI seq = av.getAlignment().getSequenceAt(seqIndex); + ViewportRanges ranges = av.getRanges(); - int[] r = results.getResults(seq, 0, av.getAlignment().getWidth()); - if (r == null) - { - return false; - } - int start = r[0]; - int end = r[1]; - // DEBUG - // System.err.println(this.av.viewName + " Seq : " + seqIndex - // + " Scroll to " + start + "," + end); + if (results == null || results.isEmpty() || av == null + || av.getAlignment() == null) + { + return false; + } + int seqIndex = av.getAlignment().findIndex(results); + if (seqIndex == -1) + { + return false; + } + SequenceI seq = av.getAlignment().getSequenceAt(seqIndex); - /* - * To centre results, scroll to positions half the visible width - * left/right of the start/end positions - */ - if (centre) - { - int offset = (vpRanges.getEndRes() - vpRanges.getStartRes() + 1) / 2 - 1; - start = Math.max(start - offset, 0); - end = end + offset - 1; - } - if (start < 0) - { - return false; - } - if (end == seq.getEnd()) - { - return false; - } - if (av.hasHiddenColumns()) + int[] r = results.getResults(seq, 0, av.getAlignment().getWidth()); + if (r == null) + { + return false; + } + int start = r[0]; + int end = r[1]; + + /* + * To centre results, scroll to positions half the visible width + * left/right of the start/end positions + */ + if (centre) + { + int offset = (ranges.getEndRes() - ranges.getStartRes() + 1) / 2 - 1; + start = Math.max(start - offset, 0); + end = end + offset - 1; + } + if (start < 0) + { + return false; + } + if (end == seq.getEnd()) + { + return false; + } + + if (av.hasHiddenColumns()) + { + HiddenColumns hidden = av.getAlignment().getHiddenColumns(); + start = hidden.absoluteToVisibleColumn(start); + end = hidden.absoluteToVisibleColumn(end); + if (start == end) { - start = av.getColumnSelection().findColumnPosition(start); - end = av.getColumnSelection().findColumnPosition(end); - if (start == end) + if (!hidden.isVisible(r[0])) { - if (!av.getColumnSelection().isVisible(r[0])) - { - // don't scroll - position isn't visible - return false; - } + // don't scroll - position isn't visible + return false; } } + } - /* - * allow for offset of target sequence (actually scroll to one above it) - */ - seqIndex = Math.max(0, seqIndex - verticalOffset); + /* + * allow for offset of target sequence (actually scroll to one above it) + */ + seqIndex = Math.max(0, seqIndex - verticalOffset); + boolean scrollNeeded = true; - // System.out.println("start=" + start + ", end=" + end + ", startv=" - // + av.getStartRes() + ", endv=" + av.getEndRes() + ", starts=" - // + av.getStartSeq() + ", ends=" + av.getEndSeq()); - if (!av.getWrapAlignment()) + if (!av.getWrapAlignment()) + { + if ((startv = ranges.getStartRes()) >= start) { - if ((startv = vpRanges.getStartRes()) >= start) - { - /* - * Scroll left to make start of search results visible - */ - // setScrollValues(start - 1, seqIndex); // plus one residue - setScrollValues(start, seqIndex); - } - else if ((endv = vpRanges.getEndRes()) <= end) - { - /* - * Scroll right to make end of search results visible - */ - // setScrollValues(startv + 1 + end - endv, seqIndex); // plus one - setScrollValues(startv + end - endv, seqIndex); - } - else if ((starts = vpRanges.getStartSeq()) > seqIndex) - { - /* - * Scroll up to make start of search results visible - */ - setScrollValues(vpRanges.getStartRes(), seqIndex); - } - else if ((ends = vpRanges.getEndSeq()) <= seqIndex) - { - /* - * Scroll down to make end of search results visible - */ - setScrollValues(vpRanges.getStartRes(), starts + seqIndex - ends - + 1); - } /* - * Else results are already visible - no need to scroll + * Scroll left to make start of search results visible */ + setScrollValues(start, seqIndex); } - else + else if ((endv = ranges.getEndRes()) <= end) + { + /* + * Scroll right to make end of search results visible + */ + setScrollValues(startv + end - endv, seqIndex); + } + else if ((starts = ranges.getStartSeq()) > seqIndex) + { + /* + * Scroll up to make start of search results visible + */ + setScrollValues(ranges.getStartRes(), seqIndex); + } + else if ((ends = ranges.getEndSeq()) <= seqIndex) { - vpRanges.scrollToWrappedVisible(start); + /* + * Scroll down to make end of search results visible + */ + setScrollValues(ranges.getStartRes(), starts + seqIndex - ends + + 1); } + /* + * Else results are already visible - no need to scroll + */ + scrollNeeded = false; + } + else + { + scrollNeeded = ranges.scrollToWrappedVisible(start); } - paintAlignment(redrawOverview); - return true; + paintAlignment(false, false); + + return scrollNeeded; } /** @@ -544,7 +534,9 @@ public class AlignmentPanel extends GAlignmentPanel implements } validateAnnotationDimensions(true); addNotify(); - paintAlignment(true); + // TODO: many places call this method and also paintAlignment with various + // different settings. this means multiple redraws are triggered... + paintAlignment(true, av.needToUpdateStructureViews()); } /** @@ -553,47 +545,27 @@ public class AlignmentPanel extends GAlignmentPanel implements */ protected void validateAnnotationDimensions(boolean adjustPanelHeight) { - int annotationHeight = getAnnotationPanel().adjustPanelHeight(); + // BH 2018.04.18 comment: addNotify() is not appropriate here. We + // are not changing ancestors, and keyboard action listeners do + // not need to be reset. addNotify() is a very expensive operation, + // requiring a full re-layout of all parents and children. + // Note in JComponent: + // This method is called by the toolkit internally and should + // not be called directly by programs. + // I note that addNotify() is called in several areas of Jalview. - if (adjustPanelHeight) - { - int rowHeight = av.getCharHeight(); - int alignmentHeight = rowHeight * av.getAlignment().getHeight(); - - /* - * Estimate available height in the AlignFrame for alignment + - * annotations. Deduct an estimate for title bar, menu bar, scale panel, - * hscroll, status bar (as these are not laid out we can't inspect their - * actual heights). Insets gives frame borders. - */ - int stuff = Platform.isAMac() ? 80 : 100; - Insets insets = alignFrame.getInsets(); - int availableHeight = alignFrame.getHeight() - stuff - insets.top - - insets.bottom; + int annotationHeight = getAnnotationPanel().adjustPanelHeight(); + annotationHeight = getAnnotationPanel() + .adjustForAlignFrame(adjustPanelHeight, annotationHeight); - /* - * If not enough vertical space, maximize annotation height while keeping - * at least two rows of alignment visible - */ - if (annotationHeight + alignmentHeight > availableHeight) - { - annotationHeight = Math.min(annotationHeight, availableHeight - 2 - * rowHeight); - } - } - else - { - // maintain same window layout whilst updating sliders - annotationHeight = annotationScroller.getSize().height; - } hscroll.addNotify(); - - annotationScroller.setPreferredSize(new Dimension(annotationScroller - .getWidth(), annotationHeight)); + annotationScroller.setPreferredSize( + new Dimension(annotationScroller.getWidth(), annotationHeight)); Dimension e = idPanel.getSize(); alabels.setSize(new Dimension(e.width, annotationHeight)); + annotationSpaceFillerHolder.setPreferredSize(new Dimension( annotationSpaceFillerHolder.getWidth(), annotationHeight)); annotationScroller.validate(); @@ -611,7 +583,8 @@ public class AlignmentPanel extends GAlignmentPanel implements fontChanged(); setAnnotationVisible(av.isShowAnnotation()); boolean wrap = av.getWrapAlignment(); - vpRanges.setStartSeq(0); + ViewportRanges ranges = av.getRanges(); + ranges.setStartSeq(0); scalePanelHolder.setVisible(!wrap); hscroll.setVisible(!wrap); idwidthAdjuster.setVisible(!wrap); @@ -625,23 +598,27 @@ public class AlignmentPanel extends GAlignmentPanel implements { annotationScroller.setVisible(true); annotationSpaceFillerHolder.setVisible(true); + validateAnnotationDimensions(false); } - if (wrap) - { - int widthInRes = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - vpRanges.setViewportWidth(widthInRes); - } - else - { - int widthInRes = (getSeqPanel().seqCanvas.getWidth() / av - .getCharWidth()) - 1; - int heightInSeq = (getSeqPanel().seqCanvas.getHeight() / av - .getCharHeight()) - 1; + int canvasWidth = getSeqPanel().seqCanvas.getWidth(); + if (canvasWidth > 0) + { // may not yet be laid out + if (wrap) + { + int widthInRes = getSeqPanel().seqCanvas + .getWrappedCanvasWidth(canvasWidth); + ranges.setViewportWidth(widthInRes); + } + else + { + int widthInRes = (canvasWidth / av.getCharWidth()); + int heightInSeq = (getSeqPanel().seqCanvas.getHeight() + / av.getCharHeight()); - vpRanges.setViewportWidth(widthInRes); - vpRanges.setViewportHeight(heightInSeq); + ranges.setViewportWidth(widthInRes); + ranges.setViewportHeight(heightInSeq); + } } idSpaceFillerPanel1.setVisible(!wrap); @@ -649,7 +626,6 @@ public class AlignmentPanel extends GAlignmentPanel implements repaint(); } - /** * Adjust row/column scrollers to show a visible position in the alignment. * @@ -659,8 +635,11 @@ public class AlignmentPanel extends GAlignmentPanel implements * visible row to scroll to * */ - public void setScrollValues(int x, int y) + public void setScrollValues(int xpos, int ypos) { + int x = xpos; + int y = ypos; + if (av == null || av.getAlignment() == null) { return; @@ -672,16 +651,9 @@ public class AlignmentPanel extends GAlignmentPanel implements } else { - - int width = av.getAlignment().getWidth(); + int width = av.getAlignment().getVisibleWidth(); int height = av.getAlignment().getHeight(); - if (av.hasHiddenColumns()) - { - // reset the width to exclude hidden columns - width = av.getColumnSelection().findColumnPosition(width); - } - hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); @@ -722,113 +694,129 @@ public class AlignmentPanel extends GAlignmentPanel implements } /** - * DOCUMENT ME! + * Respond to adjustment event when horizontal or vertical scrollbar is + * changed * * @param evt - * DOCUMENT ME! + * adjustment event encoding whether hscroll or vscroll changed */ @Override public void adjustmentValueChanged(AdjustmentEvent evt) { - int oldX = vpRanges.getStartRes(); - int oldwidth = vpRanges.getViewportWidth(); - int oldY = vpRanges.getStartSeq(); - int oldheight = vpRanges.getViewportHeight(); - if (av.getWrapAlignment()) { - if (evt.getSource() == hscroll) + adjustScrollingWrapped(evt); + return; + } + + ViewportRanges ranges = av.getRanges(); + + if (evt.getSource() == hscroll) + { + int oldX = ranges.getStartRes(); + int oldwidth = ranges.getViewportWidth(); + int x = hscroll.getValue(); + int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); + + // if we're scrolling to the position we're already at, stop + // this prevents infinite recursion of events when the scroll/viewport + // ranges values are the same + if ((x == oldX) && (width == oldwidth)) { - return; // no horizontal scroll when wrapped + return; } - else if (evt.getSource() == vscroll) + ranges.setViewportStartAndWidth(x, width); + } + else if (evt.getSource() == vscroll) + { + int oldY = ranges.getStartSeq(); + int oldheight = ranges.getViewportHeight(); + int y = vscroll.getValue(); + int height = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); + + // if we're scrolling to the position we're already at, stop + // this prevents infinite recursion of events when the scroll/viewport + // ranges values are the same + if ((y == oldY) && (height == oldheight)) { - int offy = vscroll.getValue(); - int rowSize = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - - // if we're scrolling to the position we're already at, stop - // this prevents infinite recursion of events when the scroll/viewport - // ranges values are the same - if ((offy * rowSize == oldX) && (oldwidth == rowSize)) - { - return; - } - else if (offy > -1) - { - vpRanges.setViewportStartAndWidth(offy * rowSize, rowSize); - } + return; } - else + ranges.setViewportStartAndHeight(y, height); + } + repaint(); + } + + /** + * Responds to a scroll change by setting the start position of the viewport. + * Does + * + * @param evt + */ + protected void adjustScrollingWrapped(AdjustmentEvent evt) + { + if (evt.getSource() == hscroll) + { + return; // no horizontal scroll when wrapped + } + final ViewportRanges ranges = av.getRanges(); + + if (evt.getSource() == vscroll) + { + int newY = vscroll.getValue(); + + /* + * if we're scrolling to the position we're already at, stop + * this prevents infinite recursion of events when the scroll/viewport + * ranges values are the same + */ + int oldX = ranges.getStartRes(); + int oldY = ranges.getWrappedScrollPosition(oldX); + if (oldY == newY) { - // This is only called if file loaded is a jar file that - // was wrapped when saved and user has wrap alignment true - // as preference setting - SwingUtilities.invokeLater(new Runnable() - { - @Override - public void run() - { - // When updating scrolling to use ViewportChange events, this code - // could not be validated and it is not clear if it is now being - // called. Log warning here in case it is called and unforeseen - // problems occur - Cache.log - .warn("Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences"); - - // scroll to start of panel - vpRanges.setStartRes(0); - vpRanges.setStartSeq(0); - } - }); + return; + } + if (newY > -1) + { + /* + * limit page up/down to one width's worth of positions + */ + int rowSize = ranges.getViewportWidth(); + int newX = newY > oldY ? oldX + rowSize : oldX - rowSize; + ranges.setViewportStartAndWidth(Math.max(0, newX), rowSize); } - repaint(); } else { - // horizontal scroll - if (evt.getSource() == hscroll) - { - int x = hscroll.getValue(); - int width = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); - - // if we're scrolling to the position we're already at, stop - // this prevents infinite recursion of events when the scroll/viewport - // ranges values are the same - if ((x == oldX) && (width == oldwidth)) - { - return; - } - vpRanges.setViewportStartAndWidth(x, width); - } - else if (evt.getSource() == vscroll) + // This is only called if file loaded is a jar file that + // was wrapped when saved and user has wrap alignment true + // as preference setting + SwingUtilities.invokeLater(new Runnable() { - int y = vscroll.getValue(); - int height = getSeqPanel().seqCanvas.getHeight() - / av.getCharHeight(); - - // if we're scrolling to the position we're already at, stop - // this prevents infinite recursion of events when the scroll/viewport - // ranges values are the same - if ((y == oldY) && (height == oldheight)) + @Override + public void run() { - return; + // When updating scrolling to use ViewportChange events, this code + // could not be validated and it is not clear if it is now being + // called. Log warning here in case it is called and unforeseen + // problems occur + Cache.log.warn( + "Unexpected path through code: Wrapped jar file opened with wrap alignment set in preferences"); + + // scroll to start of panel + ranges.setStartRes(0); + ranges.setStartSeq(0); } - vpRanges.setViewportStartAndHeight(y, height); - } - if (!fastPaint) - { - repaint(); - } + }); } + repaint(); } - /** - * Repaint the alignment including the annotations and overview panels (if - * shown). + /* (non-Javadoc) + * @see jalview.api.AlignmentViewPanel#paintAlignment(boolean) */ @Override - public void paintAlignment(boolean updateOverview) + public void paintAlignment(boolean updateOverview, + boolean updateStructures) { final AnnotationSorter sorter = new AnnotationSorter(getAlignment(), av.isShowAutocalculatedAbove()); @@ -836,10 +824,12 @@ public class AlignmentPanel extends GAlignmentPanel implements av.getSortAnnotationsBy()); repaint(); - if (updateOverview) + if (updateStructures) { - // TODO: determine if this paintAlignment changed structure colours av.getStructureSelectionManager().sequenceColoursChanged(this); + } + if (updateOverview) + { if (overviewPanel != null) { @@ -857,47 +847,42 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public void paintComponent(Graphics g) { - invalidate(); + invalidate(); // needed so that the id width adjuster works correctly Dimension d = getIdPanel().getIdCanvas().getPreferredSize(); idPanelHolder.setPreferredSize(d); hscrollFillerPanel.setPreferredSize(new Dimension(d.width, 12)); - validate(); + + validate(); // needed so that the id width adjuster works correctly /* - * set scroll bar positions + * set scroll bar positions - tried to remove but necessary for split panel to resize correctly + * though I still think this call should be elsewhere. */ - setScrollValues(vpRanges.getStartRes(), vpRanges.getStartSeq()); + ViewportRanges ranges = av.getRanges(); + setScrollValues(ranges.getStartRes(), ranges.getStartSeq()); + super.paintComponent(g); } - /* - * Set vertical scroll bar parameters for wrapped panel - * @param res - * the residue to scroll to + /** + * Set vertical scroll bar position, and number of increments, for wrapped + * panel + * + * @param topLeftColumn + * the column position at top left (0..) */ - private void setScrollingForWrappedPanel(int res) + private void setScrollingForWrappedPanel(int topLeftColumn) { - // get the width of the alignment in residues - int maxwidth = av.getAlignment().getWidth(); - if (av.hasHiddenColumns()) - { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; - } - - // get the width of the canvas in residues - int canvasWidth = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(getSeqPanel().seqCanvas.getWidth()); - if (canvasWidth > 0) - { - // position we want to scroll to is number of canvasWidth's to get there - int current = res / canvasWidth; + ViewportRanges ranges = av.getRanges(); + int scrollPosition = ranges.getWrappedScrollPosition(topLeftColumn); + int maxScroll = ranges.getWrappedMaxScroll(topLeftColumn); - // max scroll position: add one because extent is 1 and scrollbar value - // can only be set to at most max - extent - int max = maxwidth / canvasWidth + 1; - vscroll.setUnitIncrement(1); - vscroll.setValues(current, 1, 0, max); - } + /* + * a scrollbar's value can be set to at most (maximum-extent) + * so we add extent (1) to the maxScroll value + */ + vscroll.setUnitIncrement(1); + vscroll.setValues(scrollPosition, 1, 0, maxScroll + 1); } /** @@ -935,30 +920,16 @@ public class AlignmentPanel extends GAlignmentPanel implements } /** - * DOCUMENT ME! - * - * @param pg - * DOCUMENT ME! - * @param pwidth - * DOCUMENT ME! - * @param pheight - * DOCUMENT ME! - * @param pi - * DOCUMENT ME! - * - * @return DOCUMENT ME! - * - * @throws PrinterException - * DOCUMENT ME! - */ - /** * Draws the alignment image, including sequence ids, sequences, and * annotation labels and annotations if shown, on either one or two Graphics - * context. + * contexts. * * @param pageWidth + * in pixels * @param pageHeight - * @param pi + * in pixels + * @param pageIndex + * (0, 1, ...) * @param idGraphics * the graphics context for sequence ids and annotation labels * @param alignmentGraphics @@ -967,7 +938,7 @@ public class AlignmentPanel extends GAlignmentPanel implements * @return * @throws PrinterException */ - public int printUnwrapped(int pageWidth, int pageHeight, int pi, + public int printUnwrapped(int pageWidth, int pageHeight, int pageIndex, Graphics idGraphics, Graphics alignmentGraphics) throws PrinterException { @@ -977,11 +948,12 @@ public class AlignmentPanel extends GAlignmentPanel implements * Get the horizontal offset to where we draw the sequences. * This is idWidth if using a single Graphics context, else zero. */ - final int alignmentGraphicsOffset = idGraphics != alignmentGraphics ? 0 : idWidth; + final int alignmentGraphicsOffset = idGraphics != alignmentGraphics ? 0 + : idWidth; FontMetrics fm = getFontMetrics(av.getFont()); - int charHeight = av.getCharHeight(); - int scaleHeight = charHeight + fm.getDescent(); + final int charHeight = av.getCharHeight(); + final int scaleHeight = charHeight + fm.getDescent(); idGraphics.setColor(Color.white); idGraphics.fillRect(0, 0, pageWidth, pageHeight); @@ -990,32 +962,22 @@ public class AlignmentPanel extends GAlignmentPanel implements /* * How many sequences and residues can we fit on a printable page? */ - int totalRes = (pageWidth - idWidth) / av.getCharWidth(); + final int totalRes = (pageWidth - idWidth) / av.getCharWidth(); - int totalSeq = (pageHeight - scaleHeight) / charHeight - 1; + final int totalSeq = (pageHeight - scaleHeight) / charHeight - 1; - int alignmentWidth = av.getAlignment().getWidth(); + final int alignmentWidth = av.getAlignment().getVisibleWidth(); int pagesWide = (alignmentWidth / totalRes) + 1; - final int startRes = (pi % pagesWide) * totalRes; - int endRes = (startRes + totalRes) - 1; + final int startRes = (pageIndex % pagesWide) * totalRes; + final int endRes = Math.min(startRes + totalRes - 1, + alignmentWidth - 1); - if (endRes > (alignmentWidth - 1)) - { - endRes = alignmentWidth - 1; - } - - final int startSeq = (pi / pagesWide) * totalSeq; - int endSeq = startSeq + totalSeq; - - int alignmentHeight = av.getAlignment().getHeight(); - if (endSeq > alignmentHeight) - { - endSeq = alignmentHeight; - } + final int startSeq = (pageIndex / pagesWide) * totalSeq; + final int alignmentHeight = av.getAlignment().getHeight(); + final int endSeq = Math.min(startSeq + totalSeq, alignmentHeight); - int pagesHigh = ((alignmentHeight / totalSeq) + 1) - * pageHeight; + int pagesHigh = ((alignmentHeight / totalSeq) + 1) * pageHeight; if (av.isShowAnnotation()) { @@ -1024,12 +986,11 @@ public class AlignmentPanel extends GAlignmentPanel implements pagesHigh /= pageHeight; - if (pi >= (pagesWide * pagesHigh)) + if (pageIndex >= (pagesWide * pagesHigh)) { return Printable.NO_SUCH_PAGE; } - final int alignmentDrawnHeight = (endSeq - startSeq) * charHeight - + 3; + final int alignmentDrawnHeight = (endSeq - startSeq) * charHeight + 3; /* * draw the Scale at horizontal offset, then reset to top left (0, 0) @@ -1044,49 +1005,12 @@ public class AlignmentPanel extends GAlignmentPanel implements * then reset to top left (0, 0) */ idGraphics.translate(0, scaleHeight); - idGraphics.setFont(getIdPanel().getIdCanvas().getIdfont()); - Color currentColor = null; - Color currentTextColor = null; + IdCanvas idCanvas = getIdPanel().getIdCanvas(); + List selection = av.getSelectionGroup() == null ? null + : av.getSelectionGroup().getSequences(null); + idCanvas.drawIds((Graphics2D) idGraphics, av, startSeq, endSeq - 1, + selection); - SequenceI seq; - for (int i = startSeq; i < endSeq; i++) - { - seq = av.getAlignment().getSequenceAt(i); - if ((av.getSelectionGroup() != null) - && av.getSelectionGroup().getSequences(null).contains(seq)) - { - /* - * gray out ids of sequences in selection group (if any) - */ - currentColor = Color.gray; - currentTextColor = Color.black; - } - else - { - currentColor = av.getSequenceColour(seq); - currentTextColor = Color.black; - } - - idGraphics.setColor(currentColor); - idGraphics.fillRect(0, (i - startSeq) * charHeight, idWidth, - charHeight); - - idGraphics.setColor(currentTextColor); - - int xPos = 0; - String displayId = seq.getDisplayId(av.getShowJVSuffix()); - if (av.isRightAlignIds()) - { - fm = idGraphics.getFontMetrics(); - xPos = idWidth - - fm.stringWidth(displayId) - - 4; - } - - idGraphics.drawString(displayId, xPos, - (((i - startSeq) * charHeight) + charHeight) - - (charHeight / 5)); - } idGraphics.setFont(av.getFont()); idGraphics.translate(0, -scaleHeight); @@ -1095,8 +1019,8 @@ public class AlignmentPanel extends GAlignmentPanel implements * single graphics context), then reset to (0, scale height) */ alignmentGraphics.translate(alignmentGraphicsOffset, scaleHeight); - getSeqPanel().seqCanvas.drawPanel(alignmentGraphics, startRes, endRes, - startSeq, endSeq, 0); + getSeqPanel().seqCanvas.drawPanelForPrinting(alignmentGraphics, startRes, + endRes, startSeq, endSeq - 1); alignmentGraphics.translate(-alignmentGraphicsOffset, 0); if (av.isShowAnnotation() && (endSeq == alignmentHeight)) @@ -1116,7 +1040,8 @@ public class AlignmentPanel extends GAlignmentPanel implements * draw the annotations starting at * (idOffset, alignmentHeight) from (0, scaleHeight) */ - alignmentGraphics.translate(alignmentGraphicsOffset, alignmentDrawnHeight); + alignmentGraphics.translate(alignmentGraphicsOffset, + alignmentDrawnHeight); getAnnotationPanel().renderer.drawComponent(getAnnotationPanel(), av, alignmentGraphics, -1, startRes, endRes + 1); } @@ -1125,31 +1050,27 @@ public class AlignmentPanel extends GAlignmentPanel implements } /** - * DOCUMENT ME! + * Prints one page of an alignment in wrapped mode. Returns + * Printable.PAGE_EXISTS (0) if a page was drawn, or Printable.NO_SUCH_PAGE if + * no page could be drawn (page number out of range). * - * @param pg - * DOCUMENT ME! - * @param pwidth - * DOCUMENT ME! - * @param pheight - * DOCUMENT ME! - * @param pi - * DOCUMENT ME! + * @param pageWidth + * @param pageHeight + * @param pageNumber + * (0, 1, ...) + * @param g * - * @return DOCUMENT ME! + * @return * * @throws PrinterException - * DOCUMENT ME! */ - public int printWrappedAlignment(int pwidth, int pheight, int pi, - Graphics pg) throws PrinterException + public int printWrappedAlignment(int pageWidth, int pageHeight, int pageNumber, + Graphics g) throws PrinterException { int annotationHeight = 0; - AnnotationLabels labels = null; if (av.isShowAnnotation()) { annotationHeight = getAnnotationPanel().adjustPanelHeight(); - labels = new AnnotationLabels(av); } int hgap = av.getCharHeight(); @@ -1163,74 +1084,42 @@ public class AlignmentPanel extends GAlignmentPanel implements int idWidth = getVisibleIdWidth(false); - int maxwidth = av.getAlignment().getWidth(); - if (av.hasHiddenColumns()) - { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; - } + int maxwidth = av.getAlignment().getVisibleWidth(); - int resWidth = getSeqPanel().seqCanvas.getWrappedCanvasWidth(pwidth - - idWidth); + int resWidth = getSeqPanel().seqCanvas + .getWrappedCanvasWidth(pageWidth - idWidth); int totalHeight = cHeight * (maxwidth / resWidth + 1); - pg.setColor(Color.white); - pg.fillRect(0, 0, pwidth, pheight); - pg.setFont(av.getFont()); - - // ////////////// - // Draw the ids - pg.setColor(Color.black); - - pg.translate(0, -pi * pheight); + g.setColor(Color.white); + g.fillRect(0, 0, pageWidth, pageHeight); + g.setFont(av.getFont()); + g.setColor(Color.black); - pg.setClip(0, pi * pheight, pwidth, pheight); - - int ypos = hgap; + /* + * method: print the whole wrapped alignment, but with a clip region that + * is restricted to the requested page; this supports selective print of + * single pages or ranges, (at the cost of some repeated processing in + * the 'normal' case, when all pages are printed) + */ + g.translate(0, -pageNumber * pageHeight); - do - { - for (int i = 0; i < av.getAlignment().getHeight(); i++) - { - pg.setFont(getIdPanel().getIdCanvas().getIdfont()); - SequenceI s = av.getAlignment().getSequenceAt(i); - String string = s.getDisplayId(av.getShowJVSuffix()); - int xPos = 0; - if (av.isRightAlignIds()) - { - FontMetrics fm = pg.getFontMetrics(); - xPos = idWidth - fm.stringWidth(string) - 4; - } - pg.drawString(string, xPos, - ((i * av.getCharHeight()) + ypos + av.getCharHeight()) - - (av.getCharHeight() / 5)); - } - if (labels != null) - { - pg.translate(-3, - ypos + (av.getAlignment().getHeight() * av.getCharHeight())); - - pg.setFont(av.getFont()); - labels.drawComponent(pg, idWidth); - pg.translate( - +3, - -ypos - - (av.getAlignment().getHeight() * av - .getCharHeight())); - } + g.setClip(0, pageNumber * pageHeight, pageWidth, pageHeight); - ypos += cHeight; - } while (ypos < totalHeight); + /* + * draw sequence ids and annotation labels (if shown) + */ + IdCanvas idCanvas = getIdPanel().getIdCanvas(); + idCanvas.drawIdsWrapped((Graphics2D) g, av, 0, totalHeight); - pg.translate(idWidth, 0); + g.translate(idWidth, 0); - getSeqPanel().seqCanvas.drawWrappedPanel(pg, pwidth - idWidth, + getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(g, pageWidth - idWidth, totalHeight, 0); - if ((pi * pheight) < totalHeight) + if ((pageNumber * pageHeight) < totalHeight) { return Printable.PAGE_EXISTS; - } else { @@ -1261,13 +1150,13 @@ public class AlignmentPanel extends GAlignmentPanel implements public int getVisibleIdWidth(boolean onscreen) { // see if rendering offscreen - check preferences and calc width accordingly - if (!onscreen && Cache.getDefault("FIGURE_AUTOIDWIDTH", false)) + if (!onscreen && Cache.getDefault(Preferences.FIGURE_AUTOIDWIDTH, false)) { return calculateIdWidth(-1).width + 4; } Integer idwidth = null; - if (onscreen - || (idwidth = Cache.getIntegerProperty("FIGURE_FIXEDIDWIDTH")) == null) + if (onscreen || (idwidth = Cache + .getIntegerProperty(Preferences.FIGURE_FIXEDIDWIDTH)) == null) { int w = getIdPanel().getWidth(); return (w > 0 ? w : calculateIdWidth().width + 4); @@ -1275,93 +1164,55 @@ public class AlignmentPanel extends GAlignmentPanel implements return idwidth.intValue() + 4; } - void makeAlignmentImage(jalview.util.ImageMaker.TYPE type, File file) + /** + * Builds an image of the alignment of the specified type (EPS/PNG/SVG) and + * writes it to the specified file + * + * @param type + * @param file + */ + void makeAlignmentImage(ImageMaker.TYPE type, File file) { - int boarderBottomOffset = 5; - long pSessionId = System.currentTimeMillis(); - headless = (System.getProperty("java.awt.headless") != null && System - .getProperty("java.awt.headless").equals("true")); - if (alignFrame != null && !headless) - { - if (file != null) - { - alignFrame.setProgressBar(MessageManager.formatMessage( - "status.saving_file", new Object[] { type.getLabel() }), - pSessionId); - } - } - try + final int borderBottomOffset = 5; + + AlignmentDimension aDimension = getAlignmentDimension(); + // todo use a lambda function in place of callback here? + ImageWriterI writer = new ImageWriterI() { - AlignmentDimension aDimension = getAlignmentDimension(); - try + @Override + public void exportImage(Graphics graphics) throws Exception { - jalview.util.ImageMaker im; - final String imageAction, imageTitle; - if (type == jalview.util.ImageMaker.TYPE.PNG) - { - imageAction = "Create PNG image from alignment"; - imageTitle = null; - } - else if (type == jalview.util.ImageMaker.TYPE.EPS) - { - imageAction = "Create EPS file from alignment"; - imageTitle = alignFrame.getTitle(); - } - else - { - imageAction = "Create SVG file from alignment"; - imageTitle = alignFrame.getTitle(); - } - - im = new jalview.util.ImageMaker(this, type, imageAction, - aDimension.getWidth(), aDimension.getHeight() - + boarderBottomOffset, file, imageTitle, - alignFrame, pSessionId, headless); - Graphics graphics = im.getGraphics(); if (av.getWrapAlignment()) { - if (graphics != null) - { - printWrappedAlignment(aDimension.getWidth(), - aDimension.getHeight() + boarderBottomOffset, 0, - graphics); - im.writeImage(); - } + printWrappedAlignment(aDimension.getWidth(), + aDimension.getHeight() + borderBottomOffset, 0, graphics); } else { - if (graphics != null) - { - printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), - 0, graphics, graphics); - im.writeImage(); - } + printUnwrapped(aDimension.getWidth(), aDimension.getHeight(), 0, + graphics, graphics); } - - } catch (OutOfMemoryError err) - { - // Be noisy here. - System.out.println("########################\n" + "OUT OF MEMORY " - + file + "\n" + "########################"); - new OOMWarning("Creating Image for " + file, err); - // System.out.println("Create IMAGE: " + err); - } catch (Exception ex) - { - ex.printStackTrace(); } - } finally - { + }; - } + String fileTitle = alignFrame.getTitle(); + ImageExporter exporter = new ImageExporter(writer, alignFrame, type, + fileTitle); + int imageWidth = aDimension.getWidth(); + int imageHeight = aDimension.getHeight() + borderBottomOffset; + String of = MessageManager.getString("label.alignment"); + exporter.doExport(file, this, imageWidth, imageHeight, of); } + /** + * Calculates and returns a suitable width and height (in pixels) for an + * exported image + * + * @return + */ public AlignmentDimension getAlignmentDimension() { - int maxwidth = av.getAlignment().getWidth(); - if (av.hasHiddenColumns()) - { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth); - } + int maxwidth = av.getAlignment().getVisibleWidth(); int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight()) + getScalePanel().getHeight(); @@ -1370,16 +1221,15 @@ public class AlignmentPanel extends GAlignmentPanel implements if (av.getWrapAlignment()) { height = getWrappedHeight(); - if (headless) + if (Jalview.isHeadlessMode()) { // need to obtain default alignment width and then add in any // additional allowance for id margin // this duplicates the calculation in getWrappedHeight but adjusts for // offscreen idWith width = alignFrame.getWidth() - vscroll.getPreferredSize().width - - alignFrame.getInsets().left - - alignFrame.getInsets().right - getVisibleIdWidth() - + getVisibleIdWidth(false); + - alignFrame.getInsets().left - alignFrame.getInsets().right + - getVisibleIdWidth() + getVisibleIdWidth(false); } else { @@ -1395,27 +1245,6 @@ public class AlignmentPanel extends GAlignmentPanel implements } - /** - * DOCUMENT ME! - */ - public void makeEPS(File epsFile) - { - makeAlignmentImage(jalview.util.ImageMaker.TYPE.EPS, epsFile); - } - - /** - * DOCUMENT ME! - */ - public void makePNG(File pngFile) - { - makeAlignmentImage(jalview.util.ImageMaker.TYPE.PNG, pngFile); - } - - public void makeSVG(File svgFile) - { - makeAlignmentImage(jalview.util.ImageMaker.TYPE.SVG, svgFile); - } - public void makePNGImageMap(File imgMapFile, String imageName) { // /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS @@ -1430,33 +1259,32 @@ public class AlignmentPanel extends GAlignmentPanel implements { try { - int s, sSize = av.getAlignment().getHeight(), res, alwidth = av - .getAlignment().getWidth(), g, gSize, f, fSize, sy; + int sSize = av.getAlignment().getHeight(); + int alwidth = av.getAlignment().getWidth(); PrintWriter out = new PrintWriter(new FileWriter(imgMapFile)); - out.println(jalview.io.HTMLOutput.getImageMapHTML()); + out.println(HTMLOutput.getImageMapHTML()); out.println("" + ""); - for (s = 0; s < sSize; s++) + for (int s = 0; s < sSize; s++) { - sy = s * av.getCharHeight() + scaleHeight; + int sy = s * av.getCharHeight() + scaleHeight; SequenceI seq = av.getAlignment().getSequenceAt(s); - SequenceFeature[] features = seq.getSequenceFeatures(); SequenceGroup[] groups = av.getAlignment().findAllGroups(seq); - for (res = 0; res < alwidth; res++) + for (int column = 0; column < alwidth; column++) { - StringBuilder text = new StringBuilder(); + StringBuilder text = new StringBuilder(512); String triplet = null; if (av.getAlignment().isNucleotide()) { triplet = ResidueProperties.nucleotideName.get(seq - .getCharAt(res) + ""); + .getCharAt(column) + ""); } else { - triplet = ResidueProperties.aa2Triplet.get(seq.getCharAt(res) + triplet = ResidueProperties.aa2Triplet.get(seq.getCharAt(column) + ""); } @@ -1465,84 +1293,73 @@ public class AlignmentPanel extends GAlignmentPanel implements continue; } - int alIndex = seq.findPosition(res); - gSize = groups.length; - for (g = 0; g < gSize; g++) + int seqPos = seq.findPosition(column); + int gSize = groups.length; + for (int g = 0; g < gSize; g++) { if (text.length() < 1) { text.append(" res) + if (groups[g].getStartRes() < column + && groups[g].getEndRes() > column) { text.append("
").append(groups[g].getName()) .append(""); } } - if (features != null) + if (text.length() < 1) { - if (text.length() < 1) - { - text.append(" features = seq.findFeatures(column, column); + for (SequenceFeature sf : features) { - - if ((features[f].getBegin() <= seq.findPosition(res)) - && (features[f].getEnd() >= seq.findPosition(res))) + if (sf.isContactFeature()) { - if (features[f].isContactFeature()) - { - if (features[f].getBegin() == seq.findPosition(res) - || features[f].getEnd() == seq - .findPosition(res)) - { - text.append("
").append(features[f].getType()) - .append(" ").append(features[f].getBegin()) - .append(":").append(features[f].getEnd()); - } - } - else + text.append("
").append(sf.getType()).append(" ") + .append(sf.getBegin()).append(":") + .append(sf.getEnd()); + } + else + { + text.append("
"); + text.append(sf.getType()); + String description = sf.getDescription(); + if (description != null + && !sf.getType().equals(description)) { - text.append("
"); - text.append(features[f].getType()); - if (features[f].getDescription() != null - && !features[f].getType().equals( - features[f].getDescription())) - { - text.append(" ").append(features[f].getDescription()); - } - - if (features[f].getValue("status") != null) - { - text.append(" (").append(features[f].getValue("status")) - .append(")"); - } + description = description.replace("\"", """); + text.append(" ").append(description); } } - + String status = sf.getStatus(); + if (status != null && !"".equals(status)) + { + text.append(" (").append(status).append(")"); + } + } + if (text.length() > 1) + { + text.append("')\"; onMouseOut=\"toolTip()\"; href=\"#\">"); + out.println(text.toString()); } - } - if (text.length() > 1) - { - text.append("')\"; onMouseOut=\"toolTip()\"; href=\"#\">"); - out.println(text.toString()); } } } @@ -1561,8 +1378,7 @@ public class AlignmentPanel extends GAlignmentPanel implements { int seqPanelWidth = getSeqPanel().seqCanvas.getWidth(); - if (System.getProperty("java.awt.headless") != null - && System.getProperty("java.awt.headless").equals("true")) + if (Jalview.isHeadlessMode()) { seqPanelWidth = alignFrame.getWidth() - getVisibleIdWidth() - vscroll.getPreferredSize().width @@ -1590,7 +1406,8 @@ public class AlignmentPanel extends GAlignmentPanel implements int maxwidth = av.getAlignment().getWidth(); if (av.hasHiddenColumns()) { - maxwidth = av.getColumnSelection().findColumnPosition(maxwidth) - 1; + maxwidth = av.getAlignment().getHiddenColumns() + .absoluteToVisibleColumn(maxwidth) - 1; } int height = ((maxwidth / chunkWidth) + 1) * cHeight; @@ -1608,19 +1425,22 @@ public class AlignmentPanel extends GAlignmentPanel implements PaintRefresher.RemoveComponent(getIdPanel().getIdCanvas()); PaintRefresher.RemoveComponent(this); + closeChildFrames(); + /* * try to ensure references are nulled */ if (annotationPanel != null) { annotationPanel.dispose(); + annotationPanel = null; } if (av != null) { av.removePropertyChangeListener(propertyChangeListener); - jalview.structure.StructureSelectionManager ssm = av - .getStructureSelectionManager(); + propertyChangeListener = null; + StructureSelectionManager ssm = av.getStructureSelectionManager(); ssm.removeStructureViewerListener(getSeqPanel(), null); ssm.removeSelectionListener(getSeqPanel()); ssm.removeCommandListener(av); @@ -1639,6 +1459,23 @@ public class AlignmentPanel extends GAlignmentPanel implements } /** + * Close any open dialogs that would be orphaned when this one is closed + */ + protected void closeChildFrames() + { + if (overviewPanel != null) + { + overviewPanel.dispose(); + overviewPanel = null; + } + if (calculationDialog != null) + { + calculationDialog.closeFrame(); + calculationDialog = null; + } + } + + /** * hides or shows dynamic annotation rows based on groups and av state flags */ public void updateAnnotation() @@ -1668,7 +1505,7 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override public String getViewName() { - return av.viewName; + return av.getViewName(); } /** @@ -1797,38 +1634,9 @@ public class AlignmentPanel extends GAlignmentPanel implements * @param verticalOffset * the number of visible sequences to show above the mapped region */ - public void scrollToCentre(SearchResultsI sr, int verticalOffset) + protected void scrollToCentre(SearchResultsI sr, int verticalOffset) { - /* - * To avoid jumpy vertical scrolling (if some sequences are gapped or not - * mapped), we can make the scroll-to location a sequence above the one - * actually mapped. - */ - SequenceI mappedTo = sr.getResults().get(0).getSequence(); - List seqs = av.getAlignment().getSequences(); - - /* - * This is like AlignmentI.findIndex(seq) but here we are matching the - * dataset sequence not the aligned sequence - */ - boolean matched = false; - for (SequenceI seq : seqs) - { - if (mappedTo == seq.getDatasetSequence()) - { - matched = true; - break; - } - } - if (!matched) - { - return; // failsafe, shouldn't happen - } - - /* - * Scroll to position but centring the target residue. - */ - scrollToPosition(sr, verticalOffset, true, true); + scrollToPosition(sr, verticalOffset, true); } /** @@ -1841,6 +1649,11 @@ public class AlignmentPanel extends GAlignmentPanel implements this.scrollComplementaryPanel = b; } + /** + * Get whether to scroll complement panel + * + * @return true if cDNA/protein complement panels should be scrolled + */ protected boolean isSetToScrollComplementPanel() { return this.scrollComplementaryPanel; @@ -1859,7 +1672,7 @@ public class AlignmentPanel extends GAlignmentPanel implements if (adjustHeight) { // sort, repaint, update overview - paintAlignment(true); + paintAlignment(true, false); } else { @@ -1870,14 +1683,15 @@ public class AlignmentPanel extends GAlignmentPanel implements @Override /** - * Property change event fired when a change is made to the viewport ranges + * Property change event fired when a change is made to the viewport ranges * object associated with this alignment panel's viewport */ public void propertyChange(PropertyChangeEvent evt) { // update this panel's scroll values based on the new viewport ranges values - int x = vpRanges.getStartRes(); - int y = vpRanges.getStartSeq(); + ViewportRanges ranges = av.getRanges(); + int x = ranges.getStartRes(); + int y = ranges.getStartSeq(); setScrollValues(x, y); // now update any complementary alignment (its viewport ranges object @@ -1889,4 +1703,136 @@ public class AlignmentPanel extends GAlignmentPanel implements setToScrollComplementPanel(true); } } + + /** + * Set the reference to the PCA/Tree chooser dialog for this panel. This + * reference should be nulled when the dialog is closed. + * + * @param calculationChooser + */ + public void setCalculationDialog(CalculationChooser calculationChooser) + { + calculationDialog = calculationChooser; + } + + /** + * Returns the reference to the PCA/Tree chooser dialog for this panel (null + * if none is open) + */ + public CalculationChooser getCalculationDialog() + { + return calculationDialog; + } + + @Override + public SequenceRenderer getSequenceRenderer() + { + return seqPanel.seqCanvas.getSequenceRenderer(); + } + + public boolean scrollTo(int ostart, int end, int seqIndex, + boolean scrollToNearest, boolean redrawOverview) + { + int startv, endv, starts, ends;// , width; + + int start = -1; + if (av.hasHiddenColumns()) + { + AlignmentI al = av.getAlignment(); + start = al.getHiddenColumns().absoluteToVisibleColumn(ostart); + end = al.getHiddenColumns().absoluteToVisibleColumn(end); + if (start == end) + { + if (!scrollToNearest && !al.getHiddenColumns().isVisible(ostart)) + { + // don't scroll - position isn't visible + return false; + } + } + } + else + { + start = ostart; + } + + ViewportRanges ranges = av.getRanges(); + if (!av.getWrapAlignment()) + { + /* + * int spos=av.getStartRes(),sqpos=av.getStartSeq(); if ((startv = + * av.getStartRes()) >= start) { spos=start-1; // seqIn // + * setScrollValues(start - 1, seqIndex); } else if ((endv = + * av.getEndRes()) <= end) { // setScrollValues(spos=startv + 1 + end - + * endv, seqIndex); spos=startv + 1 + end - endv; } else if ((starts = + * av.getStartSeq()) > seqIndex) { setScrollValues(av.getStartRes(), + * seqIndex); } else if ((ends = av.getEndSeq()) <= seqIndex) { + * setScrollValues(av.getStartRes(), starts + seqIndex - ends + 1); } + */ + + // below is scrolling logic up to Jalview 2.8.2 + // if ((av.getStartRes() > end) + // || (av.getEndRes() < start) + // || ((av.getStartSeq() > seqIndex) || (av.getEndSeq() < seqIndex))) + // { + // if (start > av.getAlignment().getWidth() - hextent) + // { + // start = av.getAlignment().getWidth() - hextent; + // if (start < 0) + // { + // start = 0; + // } + // + // } + // if (seqIndex > av.getAlignment().getHeight() - vextent) + // { + // seqIndex = av.getAlignment().getHeight() - vextent; + // if (seqIndex < 0) + // { + // seqIndex = 0; + // } + // } + // setScrollValues(start, seqIndex); + // } + // logic copied from jalview.gui.AlignmentPanel: + if ((startv = ranges.getStartRes()) >= start) + { + /* + * Scroll left to make start of search results visible + */ + setScrollValues(start - 1, seqIndex); + } + else if ((endv = ranges.getEndRes()) <= end) + { + /* + * Scroll right to make end of search results visible + */ + setScrollValues(startv + 1 + end - endv, seqIndex); + } + else if ((starts = ranges.getStartSeq()) > seqIndex) + { + /* + * Scroll up to make start of search results visible + */ + setScrollValues(ranges.getStartRes(), seqIndex); + } + else if ((ends = ranges.getEndSeq()) <= seqIndex) + { + /* + * Scroll down to make end of search results visible + */ + setScrollValues(ranges.getStartRes(), starts + seqIndex - ends + 1); + } + /* + * Else results are already visible - no need to scroll + */ + } + else + { + ranges.scrollToWrappedVisible(start); + } + + paintAlignment(redrawOverview, false); + return true; + } + }