From: gmungoc Date: Mon, 4 Mar 2019 12:30:09 +0000 (+0000) Subject: Merge branch 'bug/JAL-3099alignmentVisibleWidth' into merge/JAL-3099 X-Git-Tag: Release_2_11_0~17^2~78 X-Git-Url: http://source.jalview.org/gitweb/?p=jalview.git;a=commitdiff_plain;h=985fd5ff517f3eb5221a7aefec88138341514779;hp=-c Merge branch 'bug/JAL-3099alignmentVisibleWidth' into merge/JAL-3099 Conflicts: src/jalview/gui/AlignmentPanel.java src/jalview/gui/IdCanvas.java test/jalview/datamodel/AlignmentTest.java --- 985fd5ff517f3eb5221a7aefec88138341514779 diff --combined src/jalview/datamodel/Alignment.java index 3e0856a,11d28a0..0f51b7e --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@@ -720,31 -720,17 +720,17 @@@ public class Alignment implements Align return maxLength; } - /* + @Override - public int getWidth() + public int getVisibleWidth() { - final Wrapper temp = new Wrapper(); - - forEachSequence(new Consumer() + int w = getWidth(); + if (hiddenCols != null) { - @Override - public void accept(SequenceI s) - { - if (s.getLength() > temp.inner) - { - temp.inner = s.getLength(); - } - } - }, 0, sequences.size() - 1); - - return temp.inner; + w -= hiddenCols.getSize(); + } + return w; } - - public static class Wrapper - { - public int inner; - }*/ /** * DOCUMENT ME! @@@ -1922,12 -1908,9 +1908,12 @@@ } @Override - public void setHiddenColumns(HiddenColumns cols) + public boolean setHiddenColumns(HiddenColumns cols) { + boolean changed = cols == null ? hiddenCols != null + : !cols.equals(hiddenCols); hiddenCols = cols; + return changed; } @Override diff --combined src/jalview/datamodel/AlignmentI.java index 9c73873,f129a4c..93a2456 --- a/src/jalview/datamodel/AlignmentI.java +++ b/src/jalview/datamodel/AlignmentI.java @@@ -48,15 -48,29 +48,29 @@@ public interface AlignmentI extends Ann /** * - * Calculates the maximum width of the alignment, including gaps. + * Answers the width of the alignment, including gaps, that is, the length of + * the longest sequence, or -1 if there are no sequences. Avoid calling this + * method repeatedly where possible, as it has to perform a calculation. Note + * that this width includes any hidden columns. * - * @return Greatest sequence length within alignment, or -1 if no sequences - * present + * @return + * @see AlignmentI#getVisibleWidth() */ @Override int getWidth(); /** + * + * Answers the visible width of the alignment, including gaps, that is, the + * length of the longest sequence, excluding any hidden columns. Answers -1 if + * there are no sequences. Avoid calling this method repeatedly where + * possible, as it has to perform a calculation. + * + * @return + */ + int getVisibleWidth(); + + /** * Calculates if this set of sequences (visible and invisible) are all the * same length * @@@ -581,13 -595,11 +595,13 @@@ AlignedCodonFrame getMapping(SequenceI mapFrom, SequenceI mapTo); /** - * Set the hidden columns collection on the alignment + * Set the hidden columns collection on the alignment. Answers true if the + * hidden column selection changed, else false. * * @param cols + * @return */ - public void setHiddenColumns(HiddenColumns cols); + public boolean setHiddenColumns(HiddenColumns cols); /** * Set the first sequence as representative and hide its insertions. Typically diff --combined src/jalview/gui/AlignFrame.java index 606e2e7,a620d5a..b080a25 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@@ -64,7 -64,6 +64,7 @@@ import jalview.gui.ColourMenuHelper.Col import jalview.gui.ViewSelectionMenu.ViewSetProvider; import jalview.io.AlignmentProperties; import jalview.io.AnnotationFile; +import jalview.io.BackupFiles; import jalview.io.BioJsHTMLOutput; import jalview.io.DataSourceType; import jalview.io.FileFormat; @@@ -734,9 -733,9 +734,9 @@@ public class AlignFrame extends GAlignF int aSize = alignPanels.size(); - tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null); + tabbedPane.setVisible(aSize > 1 || ap.av.getViewName() != null); - if (aSize == 1 && ap.av.viewName == null) + if (aSize == 1 && ap.av.getViewName() == null) { this.getContentPane().add(ap, BorderLayout.CENTER); } @@@ -749,7 -748,7 +749,7 @@@ expandViews.setEnabled(true); gatherViews.setEnabled(true); - tabbedPane.addTab(ap.av.viewName, ap); + tabbedPane.addTab(ap.av.getViewName(), ap); ap.setVisible(false); } @@@ -772,7 -771,7 +772,7 @@@ gatherViews.setEnabled(true); tabbedPane.setVisible(true); AlignmentPanel first = alignPanels.get(0); - tabbedPane.addTab(first.av.viewName, first); + tabbedPane.addTab(first.av.getViewName(), first); this.getContentPane().add(tabbedPane, BorderLayout.CENTER); } @@@ -873,7 -872,7 +873,7 @@@ * @param av * AlignViewport */ - void setMenusFromViewport(AlignViewport av) + public void setMenusFromViewport(AlignViewport av) { padGapsMenuitem.setSelected(av.isPadGaps()); colourTextMenuItem.setSelected(av.isShowColourText()); @@@ -964,11 -963,6 +964,11 @@@ return progressBar.operationInProgress(); } + /** + * Sets the text of the status bar. Note that setting a null or empty value + * will cause the status bar to be hidden, with possibly undesirable flicker + * of the screen layout. + */ @Override public void setStatus(String text) { @@@ -1160,8 -1154,7 +1160,8 @@@ shortName.lastIndexOf(java.io.File.separatorChar) + 1); } - success = new Jalview2XML().saveAlignment(this, file, shortName); + success = new jalview.project.Jalview2XML().saveAlignment(this, file, + shortName); statusBar.setText(MessageManager.formatMessage( "label.successfully_saved_to_file_in_format", new Object[] @@@ -1193,13 -1186,9 +1193,13 @@@ } else { + // create backupfiles object and get new temp filename destination + BackupFiles backupfiles = new BackupFiles(file); + try { - PrintWriter out = new PrintWriter(new FileWriter(file)); + PrintWriter out = new PrintWriter( + new FileWriter(backupfiles.getTempFilePath())); out.print(output); out.close(); @@@ -1212,11 -1201,6 +1212,11 @@@ success = false; ex.printStackTrace(); } + + backupfiles.setWriteSuccess(success); + // do the backup file roll and rename the temp file to actual file + success = backupfiles.rollBackupsAndRenameTempFile(); + } } @@@ -2413,12 -2397,15 +2413,12 @@@ @Override public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e) { - SequenceGroup sg = new SequenceGroup(); - - for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++) - { - sg.addSequence(viewport.getAlignment().getSequenceAt(i), false); - } + SequenceGroup sg = new SequenceGroup( + viewport.getAlignment().getSequences()); sg.setEndRes(viewport.getAlignment().getWidth() - 1); viewport.setSelectionGroup(sg); + viewport.isSelectionGroupChanged(true); viewport.sendSelection(); // JAL-2034 - should delegate to // alignPanel to decide if overview needs @@@ -2714,8 -2701,7 +2714,8 @@@ /* * Create a new AlignmentPanel (with its own, new Viewport) */ - AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel); + AlignmentPanel newap = new jalview.project.Jalview2XML() + .copyAlignPanel(alignPanel); if (!copyAnnotation) { /* @@@ -2727,10 -2713,10 +2727,10 @@@ newap.av.setGatherViewsHere(false); - if (viewport.viewName == null) + if (viewport.getViewName() == null) { - viewport.viewName = MessageManager - .getString("label.view_name_original"); + viewport.setViewName(MessageManager + .getString("label.view_name_original")); } /* @@@ -2754,7 -2740,7 +2754,7 @@@ newap.refresh(true); // adjust layout of annotations } - newap.av.viewName = getNewViewName(viewTitle); + newap.av.setViewName(getNewViewName(viewTitle)); addAlignmentPanel(newap, true); newap.alignmentChanged(); @@@ -2817,9 -2803,9 +2817,9 @@@ if (comp instanceof AlignmentPanel) { AlignmentPanel ap = (AlignmentPanel) comp; - if (!existingNames.contains(ap.av.viewName)) + if (!existingNames.contains(ap.av.getViewName())) { - existingNames.add(ap.av.viewName); + existingNames.add(ap.av.getViewName()); } } } @@@ -2902,7 -2888,7 +2902,7 @@@ viewport.setFollowHighlight(state); if (state) { - alignPanel.scrollToPosition(viewport.getSearchResults(), false); + alignPanel.scrollToPosition(viewport.getSearchResults()); } } @@@ -3049,6 -3035,7 +3049,7 @@@ viewport.expandColSelection(sg, false); viewport.hideAllSelectedSeqs(); viewport.hideSelectedColumns(); + alignPanel.updateLayout(); alignPanel.paintAlignment(true, true); viewport.sendSelection(); } @@@ -3073,6 -3060,7 +3074,7 @@@ public void hideSelColumns_actionPerformed(ActionEvent e) { viewport.hideSelectedColumns(); + alignPanel.updateLayout(); alignPanel.paintAlignment(true, true); viewport.sendSelection(); } @@@ -3611,9 -3599,9 +3613,9 @@@ frameTitle += " from "; - if (viewport.viewName != null) + if (viewport.getViewName() != null) { - frameTitle += viewport.viewName + " of "; + frameTitle += viewport.getViewName() + " of "; } frameTitle += this.title; @@@ -4781,7 -4769,7 +4783,7 @@@ if (reply != null) { - viewport.viewName = reply; + viewport.setViewName(reply); // TODO warn if reply is in getExistingViewNames()? tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply); } @@@ -5319,10 -5307,6 +5321,10 @@@ { if (avc.createGroup()) { + if (applyAutoAnnotationSettings.isSelected()) + { + alignPanel.updateAnnotation(true, false); + } alignPanel.alignmentChanged(); } } @@@ -5413,9 -5397,7 +5415,9 @@@ */ public List getAlignPanels() { - return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels; + // alignPanels is never null + // return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels; + return alignPanels; } /** diff --combined src/jalview/gui/AlignmentPanel.java index 82e2113,d8f1629..51e703d --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@@ -37,6 -37,7 +37,6 @@@ import jalview.schemes.ResiduePropertie import jalview.structure.StructureSelectionManager; import jalview.util.Comparison; import jalview.util.MessageManager; -import jalview.util.Platform; import jalview.viewmodel.ViewportListenerI; import jalview.viewmodel.ViewportRanges; @@@ -47,7 -48,6 +47,7 @@@ import java.awt.Dimension import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentAdapter; @@@ -328,12 -328,12 +328,12 @@@ public class AlignmentPanel extends GAl } /** - * Highlight the given results on the alignment. + * Highlight the given results on the alignment * */ public void highlightSearchResults(SearchResultsI results) { - boolean scrolled = scrollToPosition(results, 0, true, false); + boolean scrolled = scrollToPosition(results, 0, false); boolean noFastPaint = scrolled && av.getWrapAlignment(); @@@ -345,11 -345,13 +345,11 @@@ * (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); } /** @@@ -362,12 -364,14 +362,12 @@@ * @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 */ protected boolean scrollToPosition(SearchResultsI results, - int verticalOffset, boolean redrawOverview, boolean centre) + int verticalOffset, boolean centre) { int startv, endv, starts, ends; ViewportRanges ranges = av.getRanges(); @@@ -473,7 -477,7 +473,7 @@@ scrollNeeded = ranges.scrollToWrappedVisible(start); } - paintAlignment(redrawOverview, false); + paintAlignment(false, false); return scrollNeeded; } @@@ -542,10 -546,37 +542,10 @@@ protected void validateAnnotationDimensions(boolean adjustPanelHeight) { int annotationHeight = getAnnotationPanel().adjustPanelHeight(); + annotationHeight = getAnnotationPanel() + .adjustForAlignFrame(adjustPanelHeight, annotationHeight); - 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, insets. - */ - int stuff = Platform.isAMac() ? 120 : 140; - int availableHeight = alignFrame.getHeight() - stuff; - - /* - * 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)); @@@ -584,7 -615,6 +584,7 @@@ { annotationScroller.setVisible(true); annotationSpaceFillerHolder.setVisible(true); + validateAnnotationDimensions(false); } int canvasWidth = getSeqPanel().seqCanvas.getWidth(); @@@ -637,16 -667,9 +637,9 @@@ } 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.getAlignment().getHiddenColumns() - .absoluteToVisibleColumn(width); - } - hextent = getSeqPanel().seqCanvas.getWidth() / av.getCharWidth(); vextent = getSeqPanel().seqCanvas.getHeight() / av.getCharHeight(); @@@ -912,16 -935,30 +905,16 @@@ } /** - * 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 @@@ -930,7 -967,7 +923,7 @@@ * @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 { @@@ -944,8 -981,8 +937,8 @@@ : 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); @@@ -954,20 -991,29 +947,20 @@@ /* * 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; - final int alignmentWidth = av.getAlignment().getWidth(); - final int pagesWide = (alignmentWidth / totalRes) + 1; - int alignmentWidth = av.getAlignment().getVisibleWidth(); ++ 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; @@@ -978,7 -1024,7 +971,7 @@@ pagesHigh /= pageHeight; - if (pi >= (pagesWide * pagesHigh)) + if (pageIndex >= (pagesWide * pagesHigh)) { return Printable.NO_SUCH_PAGE; } @@@ -997,12 -1043,47 +990,12 @@@ * then reset to top left (0, 0) */ idGraphics.translate(0, scaleHeight); - idGraphics.setFont(getIdPanel().getIdCanvas().getIdfont()); - Color currentColor = null; - Color currentTextColor = null; - - 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; - } + IdCanvas idCanvas = getIdPanel().getIdCanvas(); + List selection = av.getSelectionGroup() == null ? null + : av.getSelectionGroup().getSequences(null); + idCanvas.drawIds((Graphics2D) idGraphics, av, startSeq, endSeq - 1, + selection); - idGraphics.drawString(displayId, xPos, - (((i - startSeq) * charHeight) + charHeight) - - (charHeight / 5)); - } idGraphics.setFont(av.getFont()); idGraphics.translate(0, -scaleHeight); @@@ -1012,7 -1093,7 +1005,7 @@@ */ alignmentGraphics.translate(alignmentGraphicsOffset, scaleHeight); getSeqPanel().seqCanvas.drawPanelForPrinting(alignmentGraphics, startRes, - endRes, startSeq, endSeq); + endRes, startSeq, endSeq - 1); alignmentGraphics.translate(-alignmentGraphicsOffset, 0); if (av.isShowAnnotation() && (endSeq == alignmentHeight)) @@@ -1042,27 -1123,31 +1035,27 @@@ } /** - * 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; if (av.isShowAnnotation()) { annotationHeight = getAnnotationPanel().adjustPanelHeight(); - labels = new AnnotationLabels(av); } int hgap = av.getCharHeight(); @@@ -1076,47 -1161,67 +1069,42 @@@ int idWidth = getVisibleIdWidth(false); - int maxwidth = av.getAlignment().getWidth(); - if (av.hasHiddenColumns()) - { - maxwidth = av.getAlignment().getHiddenColumns() - .absoluteToVisibleColumn(maxwidth) - 1; - } + int maxwidth = av.getAlignment().getVisibleWidth(); int resWidth = getSeqPanel().seqCanvas - .getWrappedCanvasWidth(pwidth - idWidth); + .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); + g.setColor(Color.white); + g.fillRect(0, 0, pageWidth, pageHeight); + g.setFont(av.getFont()); + g.setColor(Color.black); - pg.translate(0, -pi * pheight); - - pg.setClip(0, pi * pheight, pwidth, pheight); - - int ypos = hgap; - - 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())); + /* + * 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); - 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.drawWrappedPanelForPrinting(pg, pwidth - idWidth, + getSeqPanel().seqCanvas.drawWrappedPanelForPrinting(g, pageWidth - idWidth, totalHeight, 0); - if ((pi * pheight) < totalHeight) + if ((pageNumber * pageHeight) < totalHeight) { return Printable.PAGE_EXISTS; - } else { @@@ -1243,12 -1348,7 +1231,7 @@@ public AlignmentDimension getAlignmentDimension() { - int maxwidth = av.getAlignment().getWidth(); - if (av.hasHiddenColumns()) - { - maxwidth = av.getAlignment().getHiddenColumns() - .absoluteToVisibleColumn(maxwidth); - } + int maxwidth = av.getAlignment().getVisibleWidth(); int height = ((av.getAlignment().getHeight() + 1) * av.getCharHeight()) + getScalePanel().getHeight(); @@@ -1563,7 -1663,7 +1546,7 @@@ @Override public String getViewName() { - return av.viewName; + return av.getViewName(); } /** @@@ -1694,7 -1794,7 +1677,7 @@@ */ protected void scrollToCentre(SearchResultsI sr, int verticalOffset) { - scrollToPosition(sr, verticalOffset, true, true); + scrollToPosition(sr, verticalOffset, true); } /** diff --combined src/jalview/gui/IdCanvas.java index cf88c90,9ff0652..951db78 --- a/src/jalview/gui/IdCanvas.java +++ b/src/jalview/gui/IdCanvas.java @@@ -63,6 -63,10 +63,6 @@@ public class IdCanvas extends JPanel im List searchResults; - FontMetrics fm; - - AnnotationLabels labels = null; - AnnotationPanel ap; private Font idfont; @@@ -84,7 -88,7 +84,7 @@@ /** * DOCUMENT ME! * - * @param gg + * @param g * DOCUMENT ME! * @param hiddenRows * true - check and display hidden row marker if need be @@@ -97,7 -101,7 +97,7 @@@ * @param ypos * DOCUMENT ME! */ - public void drawIdString(Graphics2D gg, boolean hiddenRows, SequenceI s, + public void drawIdString(Graphics2D g, boolean hiddenRows, SequenceI s, int i, int starty, int ypos) { int xPos = 0; @@@ -106,40 -110,39 +106,40 @@@ if ((searchResults != null) && searchResults.contains(s)) { - gg.setColor(Color.black); - gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(), + g.setColor(Color.black); + g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(), charHeight); - gg.setColor(Color.white); + g.setColor(Color.white); } else if ((av.getSelectionGroup() != null) && av.getSelectionGroup().getSequences(null).contains(s)) { - gg.setColor(Color.lightGray); - gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(), + g.setColor(Color.lightGray); + g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(), charHeight); - gg.setColor(Color.white); + g.setColor(Color.white); } else { - gg.setColor(av.getSequenceColour(s)); - gg.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(), + g.setColor(av.getSequenceColour(s)); + g.fillRect(0, ((i - starty) * charHeight) + ypos, getWidth(), charHeight); - gg.setColor(Color.black); + g.setColor(Color.black); } if (av.isRightAlignIds()) { + FontMetrics fm = g.getFontMetrics(); xPos = panelWidth - fm.stringWidth(s.getDisplayId(av.getShowJVSuffix())) - 4; } - gg.drawString(s.getDisplayId(av.getShowJVSuffix()), xPos, + g.drawString(s.getDisplayId(av.getShowJVSuffix()), xPos, (((i - starty + 1) * charHeight) + ypos) - (charHeight / 5)); if (hiddenRows) { - drawMarker(i, starty, ypos); + drawMarker(g, av, i, starty, ypos); } } @@@ -196,7 -199,7 +196,7 @@@ gg.translate(0, transY); - drawIds(ss, es); + drawIds(gg, av, ss, es, searchResults); gg.translate(0, -transY); @@@ -252,167 -255,153 +252,161 @@@ gg.setColor(Color.white); gg.fillRect(0, 0, getWidth(), imgHeight); - drawIds(av.getRanges().getStartSeq(), av.getRanges().getEndSeq()); + drawIds(gg, av, av.getRanges().getStartSeq(), av.getRanges().getEndSeq(), searchResults); g.drawImage(image, 0, 0, this); } /** - * DOCUMENT ME! + * Draws sequence ids from sequence index startSeq to endSeq (inclusive), with + * the font and other display settings configured on the viewport. Ids of + * sequences included in the selection are coloured grey, otherwise the + * current id colour for the sequence id is used. * - * @param starty - * DOCUMENT ME! - * @param endy - * DOCUMENT ME! + * @param g + * @param alignViewport + * @param startSeq + * @param endSeq + * @param selection */ - void drawIds(int starty, int endy) + void drawIds(Graphics2D g, AlignViewport alignViewport, final int startSeq, + final int endSeq, List selection) { - if (av.isSeqNameItalics()) + Font font = alignViewport.getFont(); + if (alignViewport.isSeqNameItalics()) { - setIdfont(new Font(av.getFont().getName(), Font.ITALIC, - av.getFont().getSize())); + setIdfont(new Font(font.getName(), Font.ITALIC, + font.getSize())); } else { - setIdfont(av.getFont()); + setIdfont(font); } - gg.setFont(getIdfont()); - fm = gg.getFontMetrics(); + g.setFont(getIdfont()); + FontMetrics fm = g.getFontMetrics(); - if (av.antiAlias) + if (alignViewport.antiAlias) { - gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } Color currentColor = Color.white; Color currentTextColor = Color.black; - boolean hasHiddenRows = av.hasHiddenRows(); + boolean hasHiddenRows = alignViewport.hasHiddenRows(); - if (av.getWrapAlignment()) + if (alignViewport.getWrapAlignment()) { - drawIdsWrapped(starty, hasHiddenRows); + drawIdsWrapped(g, alignViewport, startSeq, getHeight()); return; } - // No need to hang on to labels if we're not wrapped - labels = null; - // Now draw the id strings int panelWidth = getWidth(); int xPos = 0; - SequenceI sequence; // Now draw the id strings - for (int i = starty; i <= endy; i++) + for (int i = startSeq; i <= endSeq; i++) { - sequence = av.getAlignment().getSequenceAt(i); + SequenceI sequence = alignViewport.getAlignment().getSequenceAt(i); if (sequence == null) { continue; } - if (hasHiddenRows || av.isDisplayReferenceSeq()) + if (hasHiddenRows || alignViewport.isDisplayReferenceSeq()) { - setHiddenFont(sequence); + g.setFont(getHiddenFont(sequence, alignViewport)); } // Selected sequence colours - if ((searchResults != null) && searchResults.contains(sequence)) + if (selection != null && selection.contains(sequence)) { currentColor = Color.black; currentTextColor = Color.white; } - else if ((av.getSelectionGroup() != null) && av.getSelectionGroup() - .getSequences(null).contains(sequence)) + else if ((alignViewport.getSelectionGroup() != null) && alignViewport + .getSelectionGroup().getSequences(null).contains(sequence)) { currentColor = Color.lightGray; currentTextColor = Color.black; } else { - currentColor = av.getSequenceColour(sequence); + currentColor = alignViewport.getSequenceColour(sequence); currentTextColor = Color.black; } - gg.setColor(currentColor); + g.setColor(currentColor); - gg.fillRect(0, (i - starty) * av.getCharHeight(), getWidth(), - av.getCharHeight()); + int charHeight = alignViewport.getCharHeight(); + g.fillRect(0, (i - startSeq) * charHeight, + getWidth(), charHeight); - gg.setColor(currentTextColor); + g.setColor(currentTextColor); - String string = sequence.getDisplayId(av.getShowJVSuffix()); + String string = sequence + .getDisplayId(alignViewport.getShowJVSuffix()); - if (av.isRightAlignIds()) + if (alignViewport.isRightAlignIds()) { xPos = panelWidth - fm.stringWidth(string) - 4; } - gg.drawString(string, xPos, - (((i - starty) * av.getCharHeight()) + av.getCharHeight()) - - (av.getCharHeight() / 5)); + g.drawString(string, xPos, (((i - startSeq) * charHeight) + charHeight) + - (charHeight / 5)); if (hasHiddenRows) { - drawMarker(i, starty, 0); + drawMarker(g, alignViewport, i, startSeq, 0); } } } /** - * Draws sequence ids in wrapped mode + * Draws sequence ids, and annotation labels if annotations are shown, in + * wrapped mode * - * @param starty - * @param hasHiddenRows + * @param g + * @param alignViewport + * @param startSeq */ - protected void drawIdsWrapped(int starty, boolean hasHiddenRows) + void drawIdsWrapped(Graphics2D g, AlignViewport alignViewport, + int startSeq, int pageHeight) { - int maxwidth = av.getAlignment().getVisibleWidth(); - int alheight = av.getAlignment().getHeight(); + int alignmentWidth = alignViewport.getAlignment().getWidth(); + final int alheight = alignViewport.getAlignment().getHeight(); - if (alignViewport.hasHiddenColumns()) - { - alignmentWidth = alignViewport.getAlignment().getHiddenColumns() - .absoluteToVisibleColumn(alignmentWidth) - 1; - } - int annotationHeight = 0; - if (av.isShowAnnotation()) + AnnotationLabels labels = null; + if (alignViewport.isShowAnnotation()) { if (ap == null) { - ap = new AnnotationPanel(av); + ap = new AnnotationPanel(alignViewport); } - annotationHeight = ap.adjustPanelHeight(); - if (labels == null) - { - labels = new AnnotationLabels(av); - } + labels = new AnnotationLabels(alignViewport); } - int hgap = av.getCharHeight(); - if (av.getScaleAboveWrapped()) + final int charHeight = alignViewport.getCharHeight(); + int hgap = charHeight; + if (alignViewport.getScaleAboveWrapped()) { - hgap += av.getCharHeight(); + hgap += charHeight; } - int cHeight = alheight * av.getCharHeight() + hgap + annotationHeight; + /* + * height of alignment + gap + annotations (if shown) + */ + int cHeight = alheight * charHeight + hgap + + annotationHeight; - ViewportRanges ranges = av.getRanges(); + ViewportRanges ranges = alignViewport.getRanges(); int rowSize = ranges.getViewportWidth(); @@@ -420,58 -409,49 +414,58 @@@ * draw repeating sequence ids until out of sequence data or * out of visible space, whichever comes first */ + boolean hasHiddenRows = alignViewport.hasHiddenRows(); int ypos = hgap; - int row = ranges.getStartRes(); - while ((ypos <= getHeight()) && (row < maxwidth)) + int rowStartRes = ranges.getStartRes(); + while ((ypos <= pageHeight) && (rowStartRes < alignmentWidth)) { - for (int i = starty; i < alheight; i++) + for (int i = startSeq; i < alheight; i++) { - SequenceI s = av.getAlignment().getSequenceAt(i); - if (hasHiddenRows || av.isDisplayReferenceSeq()) + SequenceI s = alignViewport.getAlignment().getSequenceAt(i); + if (hasHiddenRows || alignViewport.isDisplayReferenceSeq()) { - setHiddenFont(s); + g.setFont(getHiddenFont(s, alignViewport)); } else { - gg.setFont(getIdfont()); + g.setFont(getIdfont()); } - - drawIdString(gg, hasHiddenRows, s, i, 0, ypos); + drawIdString(g, hasHiddenRows, s, i, 0, ypos); } - if (labels != null && av.isShowAnnotation()) + if (labels != null && alignViewport.isShowAnnotation()) { - gg.translate(0, ypos + (alheight * av.getCharHeight())); - labels.drawComponent(gg, getWidth()); - gg.translate(0, -ypos - (alheight * av.getCharHeight())); + g.translate(0, ypos + (alheight * charHeight)); + labels.drawComponent(g, getWidth()); + g.translate(0, -ypos - (alheight * charHeight)); } ypos += cHeight; - row += rowSize; + rowStartRes += rowSize; } } - void drawMarker(int i, int starty, int yoffset) + /** + * Draws a marker (a blue right-pointing triangle) between sequences to + * indicate hidden sequences. + * + * @param g + * @param alignViewport + * @param seqIndex + * @param starty + * @param yoffset + */ + void drawMarker(Graphics2D g, AlignViewport alignViewport, int seqIndex, int starty, int yoffset) { - - SequenceI[] hseqs = av.getAlignment() + SequenceI[] hseqs = alignViewport.getAlignment() .getHiddenSequences().hiddenSequences; // Use this method here instead of calling hiddenSeq adjust // 3 times. int hSize = hseqs.length; - int hiddenIndex = i; - int lastIndex = i - 1; - int nextIndex = i + 1; + int hiddenIndex = seqIndex; + int lastIndex = seqIndex - 1; + int nextIndex = seqIndex + 1; for (int j = 0; j < hSize; j++) { @@@ -492,56 -472,52 +486,56 @@@ } } + /* + * are we below or above the hidden sequences? + */ boolean below = (hiddenIndex > lastIndex + 1); boolean above = (nextIndex > hiddenIndex + 1); - gg.setColor(Color.blue); + g.setColor(Color.blue); + int charHeight = av.getCharHeight(); + + /* + * vertices of the triangle, below or above hidden seqs + */ + int[] xPoints = new int[] + { getWidth() - charHeight, + getWidth() - charHeight, getWidth() }; + int yShift = seqIndex - starty; + if (below) { - gg.fillPolygon( - new int[] - { getWidth() - av.getCharHeight(), - getWidth() - av.getCharHeight(), getWidth() }, - new int[] - { (i - starty) * av.getCharHeight() + yoffset, - (i - starty) * av.getCharHeight() + yoffset - + av.getCharHeight() / 4, - (i - starty) * av.getCharHeight() + yoffset }, - 3); + int[] yPoints = new int[] { yShift * charHeight + yoffset, + yShift * charHeight + yoffset + charHeight / 4, + yShift * charHeight + yoffset }; + g.fillPolygon(xPoints, yPoints, 3); } if (above) { - gg.fillPolygon( - new int[] - { getWidth() - av.getCharHeight(), - getWidth() - av.getCharHeight(), getWidth() }, - new int[] - { (i - starty + 1) * av.getCharHeight() + yoffset, - (i - starty + 1) * av.getCharHeight() + yoffset - - av.getCharHeight() / 4, - (i - starty + 1) * av.getCharHeight() + yoffset }, - 3); - + yShift++; + int[] yPoints = new int[] { yShift * charHeight + yoffset, + yShift * charHeight + yoffset - charHeight / 4, + yShift * charHeight + yoffset }; + g.fillPolygon(xPoints, yPoints, 3); } } - void setHiddenFont(SequenceI seq) + /** + * Answers the standard sequence id font, or a bold font if the sequence is + * set as reference or a hidden group representative + * + * @param seq + * @param alignViewport + * @return + */ + private Font getHiddenFont(SequenceI seq, AlignViewport alignViewport) { - Font bold = new Font(av.getFont().getName(), Font.BOLD, - av.getFont().getSize()); - if (av.isReferenceSeq(seq) || av.isHiddenRepSequence(seq)) { - gg.setFont(bold); - } - else - { - gg.setFont(getIdfont()); + return new Font(av.getFont().getName(), Font.BOLD, + av.getFont().getSize()); } + return getIdfont(); } /** diff --combined src/jalview/gui/ScalePanel.java index d181804,d214db6..9788ec6 --- a/src/jalview/gui/ScalePanel.java +++ b/src/jalview/gui/ScalePanel.java @@@ -23,6 -23,7 +23,6 @@@ package jalview.gui import jalview.datamodel.ColumnSelection; import jalview.datamodel.HiddenColumns; import jalview.datamodel.SequenceGroup; -import jalview.datamodel.SequenceI; import jalview.renderer.ScaleRenderer; import jalview.renderer.ScaleRenderer.ScaleMark; import jalview.util.MessageManager; @@@ -157,7 -158,12 +157,12 @@@ public class ScalePanel extends JPane protected void rightMouseButtonPressed(MouseEvent evt, final int res) { JPopupMenu pop = new JPopupMenu(); - if (reveal != null) + + /* + * grab the hidden range in case mouseMoved nulls it + */ + final int[] hiddenRange = reveal; + if (hiddenRange != null) { JMenuItem item = new JMenuItem( MessageManager.getString("label.reveal")); @@@ -166,8 -172,9 +171,9 @@@ @Override public void actionPerformed(ActionEvent e) { - av.showColumn(reveal[0]); + av.showColumn(hiddenRange[0]); reveal = null; + ap.updateLayout(); ap.paintAlignment(true, true); av.sendSelection(); } @@@ -184,6 -191,7 +190,7 @@@ { av.showAllHiddenColumns(); reveal = null; + ap.updateLayout(); ap.paintAlignment(true, true); av.sendSelection(); } @@@ -208,6 -216,7 +215,7 @@@ av.setSelectionGroup(null); } + ap.updateLayout(); ap.paintAlignment(true, true); av.sendSelection(); } @@@ -236,7 -245,15 +244,7 @@@ } av.getColumnSelection().addElement(res); - SequenceGroup sg = new SequenceGroup(); - // try to be as quick as possible - SequenceI[] iVec = av.getAlignment().getSequencesArray(); - for (int i = 0; i < iVec.length; i++) - { - sg.addSequence(iVec[i], false); - iVec[i] = null; - } - iVec = null; + SequenceGroup sg = new SequenceGroup(av.getAlignment().getSequences()); sg.setStartRes(res); sg.setEndRes(res); @@@ -267,9 -284,7 +275,9 @@@ { mouseDragging = false; - int res = (evt.getX() / av.getCharWidth()) + int xCords = Math.max(0, evt.getX()); // prevent negative X coordinates + + int res = (xCords / av.getCharWidth()) + av.getRanges().getStartRes(); if (av.hasHiddenColumns()) @@@ -311,17 -326,12 +319,17 @@@ } stretchingGroup = false; ap.paintAlignment(false, false); + av.isSelectionGroupChanged(true); + av.isColSelChanged(true); av.sendSelection(); } /** * Action on dragging the mouse in the scale panel is to expand or shrink the - * selection group range (including any hidden columns that it spans) + * selection group range (including any hidden columns that it spans). Note + * that the selection is only broadcast at the start of the drag (on + * mousePressed) and at the end (on mouseReleased), to avoid overload + * redrawing of other views. * * @param evt */ diff --combined src/jalview/gui/SeqCanvas.java index dc87eba,ce7b63b..2a370c4 --- a/src/jalview/gui/SeqCanvas.java +++ b/src/jalview/gui/SeqCanvas.java @@@ -32,6 -32,7 +32,6 @@@ import jalview.util.Comparison import jalview.viewmodel.ViewportListenerI; import jalview.viewmodel.ViewportRanges; -import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; @@@ -55,11 -56,6 +55,11 @@@ import javax.swing.JComponent */ public class SeqCanvas extends JComponent implements ViewportListenerI { + /* + * pixels gap between sequences and annotations when in wrapped mode + */ + static final int SEQS_ANNOTATION_GAP = 3; + private static final String ZEROS = "0000000000"; final FeatureRenderer fr; @@@ -87,9 -83,9 +87,9 @@@ private int labelWidthWest; // label left width in pixels if shown - private int wrappedSpaceAboveAlignment; // gap between widths + int wrappedSpaceAboveAlignment; // gap between widths - private int wrappedRepeatHeightPx; // height in pixels of wrapped width + int wrappedRepeatHeightPx; // height in pixels of wrapped width private int wrappedVisibleWidths; // number of wrapped widths displayed @@@ -369,27 -365,31 +369,27 @@@ width -= (width % charWidth); height -= (height % charHeight); - // selectImage is the selection group outline image - BufferedImage selectImage = drawSelectionGroup( - ranges.getStartRes(), ranges.getEndRes(), - ranges.getStartSeq(), ranges.getEndSeq()); - if ((img != null) && (fastPaint || (getVisibleRect().width != g.getClipBounds().width) || (getVisibleRect().height != g.getClipBounds().height))) { - BufferedImage lcimg = buildLocalImage(selectImage); - g.drawImage(lcimg, 0, 0, this); + g.drawImage(img, 0, 0, this); + + drawSelectionGroup((Graphics2D) g, ranges.getStartRes(), + ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); + fastPaint = false; } - else if ((width > 0) && (height > 0)) + else if (width > 0 && height > 0) { - // img is a cached version of the last view we drew, if any - // if we have no img or the size has changed, make a new one + /* + * img is a cached version of the last view we drew, if any + * if we have no img or the size has changed, make a new one + */ if (img == null || width != img.getWidth() || height != img.getHeight()) { - img = setupImage(); - if (img == null) - { - return; - } + img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); gg = (Graphics2D) img.getGraphics(); gg.setFont(av.getFont()); } @@@ -412,11 -412,11 +412,11 @@@ drawPanel(gg, ranges.getStartRes(), ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq(), 0); } - - // lcimg is a local *copy* of img which we'll draw selectImage on top of - BufferedImage lcimg = buildLocalImage(selectImage); - g.drawImage(lcimg, 0, 0, this); + drawSelectionGroup(gg, ranges.getStartRes(), + ranges.getEndRes(), ranges.getStartSeq(), ranges.getEndSeq()); + + g.drawImage(img, 0, 0, this); } if (av.cursorMode) @@@ -445,8 -445,14 +445,8 @@@ { drawPanel(g1, startRes, endRes, startSeq, endSeq, 0); - BufferedImage selectImage = drawSelectionGroup(startRes, endRes, + drawSelectionGroup((Graphics2D) g1, startRes, endRes, startSeq, endSeq); - if (selectImage != null) - { - ((Graphics2D) g1).setComposite(AlphaComposite - .getInstance(AlphaComposite.SRC_OVER)); - g1.drawImage(selectImage, 0, 0, this); - } } /** @@@ -464,14 -470,102 +464,14 @@@ public void drawWrappedPanelForPrinting(Graphics g, int canvasWidth, int canvasHeight, int startRes) { - SequenceGroup group = av.getSelectionGroup(); - drawWrappedPanel(g, canvasWidth, canvasHeight, startRes); + SequenceGroup group = av.getSelectionGroup(); if (group != null) { - BufferedImage selectImage = null; - try - { - selectImage = new BufferedImage(canvasWidth, canvasHeight, - BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works - } catch (OutOfMemoryError er) - { - System.gc(); - System.err.println("Print image OutOfMemory Error.\n" + er); - new OOMWarning("Creating wrapped alignment image for printing", er); - } - if (selectImage != null) - { - Graphics2D g2 = selectImage.createGraphics(); - setupSelectionGroup(g2, selectImage); - drawWrappedSelection(g2, group, canvasWidth, canvasHeight, + drawWrappedSelection((Graphics2D) g, group, canvasWidth, canvasHeight, startRes); - - g2.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - g.drawImage(selectImage, 0, 0, this); - g2.dispose(); - } - } - } - - /* - * Make a local image by combining the cached image img - * with any selection - */ - private BufferedImage buildLocalImage(BufferedImage selectImage) - { - // clone the cached image - BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), - img.getType()); - - // BufferedImage lcimg = new BufferedImage(img.getWidth(), img.getHeight(), - // img.getType()); - Graphics2D g2d = lcimg.createGraphics(); - g2d.drawImage(img, 0, 0, null); - - // overlay selection group on lcimg - if (selectImage != null) - { - g2d.setComposite( - AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - g2d.drawImage(selectImage, 0, 0, this); } - - g2d.dispose(); - - return lcimg; - } - - /* - * Set up a buffered image of the correct height and size for the sequence canvas - */ - private BufferedImage setupImage() - { - BufferedImage lcimg = null; - - int charWidth = av.getCharWidth(); - int charHeight = av.getCharHeight(); - - int width = getWidth(); - int height = getHeight(); - - width -= (width % charWidth); - height -= (height % charHeight); - - if ((width < 1) || (height < 1)) - { - return null; - } - - try - { - lcimg = new BufferedImage(width, height, - BufferedImage.TYPE_INT_ARGB); // ARGB so alpha compositing works - } catch (OutOfMemoryError er) - { - System.gc(); - System.err.println( - "Group image OutOfMemory Redraw Error.\n" + er); - new OOMWarning("Creating alignment image for display", er); - - return null; - } - - return lcimg; } /** @@@ -564,7 -658,7 +564,7 @@@ calculateWrappedGeometry(canvasWidth, canvasHeight); /* - * draw one width at a time (including any scales or annotation shown), + * draw one width at a time (excluding any scales shown), * until we have run out of either alignment or vertical space available */ int ypos = wrappedSpaceAboveAlignment; @@@ -611,22 -705,14 +611,22 @@@ * (av.getScaleAboveWrapped() ? 2 : 1); /* - * height in pixels of the wrapped widths + * compute height in pixels of the wrapped widths + * - start with space above plus sequences */ wrappedRepeatHeightPx = wrappedSpaceAboveAlignment; - // add sequences - wrappedRepeatHeightPx += av.getRanges().getViewportHeight() + wrappedRepeatHeightPx += av.getAlignment().getHeight() * charHeight; - // add annotations panel height if shown - wrappedRepeatHeightPx += getAnnotationHeight(); + + /* + * add annotations panel height if shown + * also gap between sequences and annotations + */ + if (av.isShowAnnotation()) + { + wrappedRepeatHeightPx += getAnnotationHeight(); + wrappedRepeatHeightPx += SEQS_ANNOTATION_GAP; // 3px + } /* * number of visible widths (the last one may be part height), @@@ -670,9 -756,8 +670,9 @@@ * @param endColumn * @param canvasHeight */ - protected void drawWrappedWidth(Graphics g, int ypos, int startColumn, - int endColumn, int canvasHeight) + protected void drawWrappedWidth(Graphics g, final int ypos, + final int startColumn, final int endColumn, + final int canvasHeight) { ViewportRanges ranges = av.getRanges(); int viewportWidth = ranges.getViewportWidth(); @@@ -719,8 -804,7 +719,8 @@@ if (av.isShowAnnotation()) { - g.translate(0, cHeight + ypos + 3); + final int yShift = cHeight + ypos + SEQS_ANNOTATION_GAP; + g.translate(0, yShift); if (annotations == null) { annotations = new AnnotationPanel(av); @@@ -728,7 -812,7 +728,7 @@@ annotations.renderer.drawComponent(annotations, av, g, -1, startColumn, endx + 1); - g.translate(0, -cHeight - ypos - 3); + g.translate(0, -yShift); } g.setClip(clip); g.translate(-xOffset, 0); @@@ -870,20 -954,10 +870,14 @@@ int startx = startRes; int endx; int ypos = hgap; // vertical offset - int maxwidth = av.getAlignment().getWidth(); - - if (av.hasHiddenColumns()) - { - maxwidth = av.getAlignment().getHiddenColumns() - .absoluteToVisibleColumn(maxwidth); - } + int maxwidth = av.getAlignment().getVisibleWidth(); // chop the wrapped alignment extent up into panel-sized blocks and treat // each block as if it were a block from an unwrapped alignment + g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND, 3f, new float[] + { 5f, 3f }, 0f)); + g.setColor(Color.RED); while ((ypos <= canvasHeight) && (startx < maxwidth)) { // set end value to be start + width, or maxwidth, whichever is smaller @@@ -908,7 -982,6 +902,7 @@@ // update horizontal offset startx += cWidth; } + g.setStroke(new BasicStroke()); } int getAnnotationHeight() @@@ -1075,21 -1148,14 +1069,21 @@@ } + /** + * Draws the outlines of any groups defined on the alignment (excluding the + * current selection group, if any) + * + * @param g1 + * @param startRes + * @param endRes + * @param startSeq + * @param endSeq + * @param offset + */ void drawGroupsBoundaries(Graphics g1, int startRes, int endRes, int startSeq, int endSeq, int offset) { Graphics2D g = (Graphics2D) g1; - // - // /////////////////////////////////// - // Now outline any areas if necessary - // /////////////////////////////////// SequenceGroup group = null; int groupIndex = -1; @@@ -1102,15 -1168,18 +1096,15 @@@ if (group != null) { - g.setStroke(new BasicStroke()); - g.setColor(group.getOutlineColour()); - do { + g.setColor(group.getOutlineColour()); + drawPartialGroupOutline(g, group, startRes, endRes, startSeq, endSeq, offset); groupIndex++; - g.setStroke(new BasicStroke()); - if (groupIndex >= av.getAlignment().getGroups().size()) { break; @@@ -1124,28 -1193,33 +1118,28 @@@ } - - /* - * Draw the selection group as a separate image and overlay + /** + * Draws the outline of the current selection group (if any) + * + * @param g + * @param startRes + * @param endRes + * @param startSeq + * @param endSeq */ - private BufferedImage drawSelectionGroup(int startRes, int endRes, + private void drawSelectionGroup(Graphics2D g, int startRes, int endRes, int startSeq, int endSeq) { SequenceGroup group = av.getSelectionGroup(); if (group == null) { - // nothing to draw - return null; + return; } - // set up drawing colour - Graphics2D g = (Graphics2D) selectionImage.getGraphics(); - - setupSelectionGroup(g, selectionImage); - + g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, + BasicStroke.JOIN_ROUND, 3f, new float[] + { 5f, 3f }, 0f)); + g.setColor(Color.RED); if (!av.getWrapAlignment()) { drawUnwrappedSelection(g, group, startRes, endRes, startSeq, endSeq, @@@ -1156,7 -1230,9 +1150,7 @@@ drawWrappedSelection(g, group, getWidth(), getHeight(), av.getRanges().getStartRes()); } - - g.dispose(); - return selectionImage; + g.setStroke(new BasicStroke()); } /** @@@ -1247,23 -1323,33 +1241,23 @@@ } - /* - * Set up graphics for selection group - */ - private void setupSelectionGroup(Graphics2D g, - BufferedImage selectionImage) - { - // set background to transparent - g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, 0.0f)); - g.fillRect(0, 0, selectionImage.getWidth(), selectionImage.getHeight()); - - // set up foreground to draw red dashed line - g.setComposite(AlphaComposite.Src); - g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_ROUND, 3f, new float[] - { 5f, 3f }, 0f)); - g.setColor(Color.RED); - } - - /* + /** * Draw a selection group over an unwrapped alignment - * @param g graphics object to draw with - * @param group selection group - * @param startRes start residue of area to draw - * @param endRes end residue of area to draw - * @param startSeq start sequence of area to draw - * @param endSeq end sequence of area to draw - * @param offset vertical offset (used when called from wrapped alignment code) + * + * @param g + * graphics object to draw with + * @param group + * selection group + * @param startRes + * start residue of area to draw + * @param endRes + * end residue of area to draw + * @param startSeq + * start sequence of area to draw + * @param endSeq + * end sequence of area to draw + * @param offset + * vertical offset (used when called from wrapped alignment code) */ private void drawUnwrappedSelection(Graphics2D g, SequenceGroup group, int startRes, int endRes, int startSeq, int endSeq, int offset) @@@ -1301,16 -1387,8 +1295,16 @@@ } } - /* - * Draw the selection group as a separate image and overlay + /** + * Draws part of a selection group outline + * + * @param g + * @param group + * @param startRes + * @param endRes + * @param startSeq + * @param endSeq + * @param verticalOffset */ private void drawPartialGroupOutline(Graphics2D g, SequenceGroup group, int startRes, int endRes, int startSeq, int endSeq, diff --combined test/jalview/datamodel/AlignmentTest.java index 8aed114,5e400c0..dd19eb6 --- a/test/jalview/datamodel/AlignmentTest.java +++ b/test/jalview/datamodel/AlignmentTest.java @@@ -1485,51 -1485,33 +1485,81 @@@ public class AlignmentTes assertEquals(".PQR...", seq3.getSequenceAsString()); } + /** + * Test for setHiddenColumns, to check it returns true if the hidden columns + * have changed, else false + */ + @Test(groups = { "Functional" }) + public void testSetHiddenColumns() + { + AlignmentI al = new Alignment(new SequenceI[] {}); + assertFalse(al.getHiddenColumns().hasHiddenColumns()); + + HiddenColumns hc = new HiddenColumns(); + assertFalse(al.setHiddenColumns(hc)); // no change + assertSame(hc, al.getHiddenColumns()); + + hc.hideColumns(2, 4); + assertTrue(al.getHiddenColumns().hasHiddenColumns()); + + /* + * set a different object but with the same columns hidden + */ + HiddenColumns hc2 = new HiddenColumns(); + hc2.hideColumns(2, 4); + assertFalse(al.setHiddenColumns(hc2)); // no change + assertSame(hc2, al.getHiddenColumns()); + + assertTrue(al.setHiddenColumns(null)); + assertNull(al.getHiddenColumns()); + assertTrue(al.setHiddenColumns(hc)); + assertSame(hc, al.getHiddenColumns()); + + al.getHiddenColumns().hideColumns(10, 12); + hc2.hideColumns(10, 12); + assertFalse(al.setHiddenColumns(hc2)); // no change + + /* + * hide columns 15-16 then 17-18 in hc + * hide columns 15-18 in hc2 + * these are not now 'equal' objects even though they + * represent the same set of columns + */ + assertSame(hc2, al.getHiddenColumns()); + hc.hideColumns(15, 16); + hc.hideColumns(17, 18); + hc2.hideColumns(15, 18); + assertFalse(hc.equals(hc2)); + assertTrue(al.setHiddenColumns(hc)); // 'changed' + } ++ + @Test(groups = { "Functional" }) + public void testGetWidth() + { + SequenceI seq1 = new Sequence("seq1", "ABCDEF--"); + SequenceI seq2 = new Sequence("seq2", "-JKLMNO--"); + SequenceI seq3 = new Sequence("seq2", "-PQR"); + AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 }); + + assertEquals(9, a.getWidth()); + + // width includes hidden columns + a.getHiddenColumns().hideColumns(2, 5); + assertEquals(9, a.getWidth()); + } + + @Test(groups = { "Functional" }) + public void testGetVisibleWidth() + { + SequenceI seq1 = new Sequence("seq1", "ABCDEF--"); + SequenceI seq2 = new Sequence("seq2", "-JKLMNO--"); + SequenceI seq3 = new Sequence("seq2", "-PQR"); + AlignmentI a = new Alignment(new SequenceI[] { seq1, seq2, seq3 }); + + assertEquals(9, a.getVisibleWidth()); + + // width excludes hidden columns + a.getHiddenColumns().hideColumns(2, 5); + assertEquals(5, a.getVisibleWidth()); + } }