From bab8878fb12f99051cdc622fe6a9767b3109bc70 Mon Sep 17 00:00:00 2001 From: Ben Soares Date: Fri, 21 Jul 2023 17:23:24 +0100 Subject: [PATCH] JAL-244 Fixed idWidth labels in headless mode for non-wrap alignments --- examples/argfiles/test_fab41.txt | 2 +- .../argfiles/test_fab41_nostructureviewers.txt | 2 +- src/jalview/bin/Commands.java | 162 +++++++++++--------- src/jalview/gui/AlignmentPanel.java | 37 +++-- src/jalview/gui/AnnotationLabels.java | 81 ++++++---- src/jalview/jbgui/GAlignmentPanel.java | 2 +- 6 files changed, 169 insertions(+), 117 deletions(-) diff --git a/examples/argfiles/test_fab41.txt b/examples/argfiles/test_fab41.txt index e6f7627..b7f0d45 100644 --- a/examples/argfiles/test_fab41.txt +++ b/examples/argfiles/test_fab41.txt @@ -10,4 +10,4 @@ --paematrix=[label=pAE R4-M5]./examples/test_fab41.result/test_fab41_unrelaxed_rank_4_model_5_scores.json --structure=./examples/test_fab41.result/test_fab41_unrelaxed_rank_5_model_1.pdb --paematrix=[label=pAE R5-M1]./examples/test_fab41.result/test_fab41_unrelaxed_rank_5_model_1_scores.json ---image=output1.html +--image=[textrenderer=text]output1.html diff --git a/examples/argfiles/test_fab41_nostructureviewers.txt b/examples/argfiles/test_fab41_nostructureviewers.txt index eb8fdc0..ab52cdf 100644 --- a/examples/argfiles/test_fab41_nostructureviewers.txt +++ b/examples/argfiles/test_fab41_nostructureviewers.txt @@ -11,4 +11,4 @@ --paematrix=[label=pAE R4-M5]./examples/test_fab41.result/test_fab41_unrelaxed_rank_4_model_5_scores.json --structure=[structureviewer=none]./examples/test_fab41.result/test_fab41_unrelaxed_rank_5_model_1.pdb --paematrix=[label=pAE R5-M1]./examples/test_fab41.result/test_fab41_unrelaxed_rank_5_model_1_scores.json ---image=output1.html +--image=[textrenderer=text]output1.html diff --git a/src/jalview/bin/Commands.java b/src/jalview/bin/Commands.java index d7d1ea3..838b381 100644 --- a/src/jalview/bin/Commands.java +++ b/src/jalview/bin/Commands.java @@ -103,16 +103,20 @@ public class Commands theseArgsWereParsed &= processLinked(id); processGroovyScript(id); boolean processLinkedOkay = theseArgsWereParsed; - + // wait around until alignFrame isn't busy - AlignFrame af=afMap.get(id); - while (af!=null && af.getViewport().isCalcInProgress()) + AlignFrame af = afMap.get(id); + while (af != null && af.getViewport().isCalcInProgress()) { - try { + try + { Thread.sleep(25); - } catch (Exception q) {}; + } catch (Exception q) + { + } + ; } - + theseArgsWereParsed &= processImages(id); if (processLinkedOkay) theseArgsWereParsed &= processOutput(id); @@ -263,12 +267,16 @@ public class Commands if ("" != colour) { ColourSchemeI cs = ColourSchemeProperty.getColourScheme( - af.getViewport(), af.getViewport().getAlignment(), colour); - - if (cs==null && !"None".equals(colour)) + af.getViewport(), af.getViewport().getAlignment(), + colour); + + if (cs == null && !"None".equals(colour)) + { + Console.warn( + "Couldn't parse '" + colour + "' as a colourscheme."); + } + else { - Console.warn("Couldn't parse '"+colour+"' as a colourscheme."); - } else { af.changeColour(cs); } Jalview.testoutput(argParser, Arg.COLOUR, "zappo", colour); @@ -569,15 +577,15 @@ public class Commands structureFilepath, tft, paeFilepath, false, ssFromStructure, false, viewerType); - if (sv==null) + if (sv == null) { Console.error("Failed to import and open structure view."); continue; } try { - long tries=1000; - while (sv.isBusy() && tries>0) + long tries = 1000; + while (sv.isBusy() && tries > 0) { Thread.sleep(25); if (sv.isBusy()) @@ -587,15 +595,18 @@ public class Commands "Waiting for viewer for " + structureFilepath); } } - if (tries==0 && sv.isBusy()) + if (tries == 0 && sv.isBusy()) { - Console.warn("Gave up waiting for structure viewer to load. Something may have gone wrong."); + Console.warn( + "Gave up waiting for structure viewer to load. Something may have gone wrong."); } } catch (Exception x) { - Console.warn("Exception whilst waiting for structure viewer "+structureFilepath,x); + Console.warn("Exception whilst waiting for structure viewer " + + structureFilepath, x); } - Console.debug("Successfully opened viewer for "+structureFilepath); + Console.debug( + "Successfully opened viewer for " + structureFilepath); String structureImageFilename = ArgParser.getValueFromSubValOrArg( avm, av, Arg.STRUCTUREIMAGE, subVals); if (sv != null && structureImageFilename != null) @@ -652,16 +663,18 @@ public class Commands if (sview instanceof AppJmol) { AppJmol jmol = (AppJmol) sview; - try { - Console.debug("Rendering image to "+structureImageFile); + try + { + Console.debug("Rendering image to " + structureImageFile); jmol.makePDBImage(structureImageFile, imageType, renderer, - userBis); - Console.debug("Finished Rendering image to "+structureImageFile); + userBis); + Console.debug("Finished Rendering image to " + + structureImageFile); - } - catch (ImageOutputException ioexc) + } catch (ImageOutputException ioexc) { - Console.warn("Unexpected error whilst exporting image to "+structureImageFile,ioexc); + Console.warn("Unexpected error whilst exporting image to " + + structureImageFile, ioexc); } } @@ -771,57 +784,60 @@ public class Commands Cache.setProperty("EXPORT_EMBBED_BIOJSON", "false"); Console.info("Writing " + file); - try { - switch (type) + try { - - case "svg": - Console.debug("Outputting type '" + type + "' to " + fileName); - af.createSVG(file, renderer); - break; - - case "png": - Console.debug("Outputting type '" + type + "' to " + fileName); - af.createPNG(file, null, userBis); - break; - - case "html": - Console.debug("Outputting type '" + type + "' to " + fileName); - HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); - htmlSVG.exportHTML(fileName, renderer); - break; - - case "biojs": - Console.debug("Creating BioJS MSA Viwer HTML file: " + fileName); - try - { - BioJsHTMLOutput.refreshVersionInfo( - BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); - } catch (URISyntaxException e) + switch (type) { - e.printStackTrace(); + + case "svg": + Console.debug("Outputting type '" + type + "' to " + fileName); + af.createSVG(file, renderer); + break; + + case "png": + Console.debug("Outputting type '" + type + "' to " + fileName); + af.createPNG(file, null, userBis); + break; + + case "html": + Console.debug("Outputting type '" + type + "' to " + fileName); + HtmlSvgOutput htmlSVG = new HtmlSvgOutput(af.alignPanel); + htmlSVG.exportHTML(fileName, renderer); + break; + + case "biojs": + Console.debug( + "Creating BioJS MSA Viwer HTML file: " + fileName); + try + { + BioJsHTMLOutput.refreshVersionInfo( + BioJsHTMLOutput.BJS_TEMPLATES_LOCAL_DIRECTORY); + } catch (URISyntaxException e) + { + e.printStackTrace(); + } + BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); + bjs.exportHTML(fileName); + break; + + case "eps": + Console.debug("Creating EPS file: " + fileName); + af.createEPS(file, name); + break; + + case "imagemap": + Console.debug("Creating ImageMap file: " + fileName); + af.createImageMap(file, name); + break; + + default: + Console.warn(Arg.IMAGE.argString() + " type '" + type + + "' not known. Ignoring"); + break; } - BioJsHTMLOutput bjs = new BioJsHTMLOutput(af.alignPanel); - bjs.exportHTML(fileName); - break; - - case "eps": - Console.debug("Creating EPS file: " + fileName); - af.createEPS(file, name); - break; - - case "imagemap": - Console.debug("Creating ImageMap file: " + fileName); - af.createImageMap(file, name); - break; - - default: - Console.warn(Arg.IMAGE.argString() + " type '" + type - + "' not known. Ignoring"); - break; - } - } catch (Exception ioex) { - Console.warn("Unexpected error during export",ioex); + } catch (Exception ioex) + { + Console.warn("Unexpected error during export", ioex); } } } diff --git a/src/jalview/gui/AlignmentPanel.java b/src/jalview/gui/AlignmentPanel.java index 2396329..8a43a4a 100644 --- a/src/jalview/gui/AlignmentPanel.java +++ b/src/jalview/gui/AlignmentPanel.java @@ -338,18 +338,27 @@ public class AlignmentPanel extends GAlignmentPanel implements // Also check annotation label widths if (includeAnnotations && al.getAlignmentAnnotation() != null) { - fm = c.getFontMetrics(getAlabels().getFont()); - - for (i = 0; i < al.getAlignmentAnnotation().length; i++) + if (Jalview.isHeadlessMode()) + { + AnnotationLabels aal = this.getAlabels(); + int stringWidth = aal.drawLabels(null, false, idWidth, false, fm); + idWidth = Math.max(idWidth, stringWidth); + } + else { - AlignmentAnnotation aa = al.getAlignmentAnnotation()[i]; - if (visibleOnly && !aa.visible) + fm = c.getFontMetrics(getAlabels().getFont()); + + for (i = 0; i < al.getAlignmentAnnotation().length; i++) { - continue; + AlignmentAnnotation aa = al.getAlignmentAnnotation()[i]; + if (visibleOnly && !aa.visible) + { + continue; + } + String label = aa.label; + int stringWidth = fm.stringWidth(label); + idWidth = Math.max(idWidth, stringWidth); } - String label = aa.label; - int stringWidth = fm.stringWidth(label); - idWidth = Math.max(idWidth, stringWidth); } } @@ -581,9 +590,10 @@ public class AlignmentPanel extends GAlignmentPanel implements // not be called directly by programs. // I note that addNotify() is called in several areas of Jalview. - int annotationHeight = getAnnotationPanel().adjustPanelHeight(); - annotationHeight = getAnnotationPanel() - .adjustForAlignFrame(adjustPanelHeight, annotationHeight); + AnnotationPanel ap = getAnnotationPanel(); + int annotationHeight = ap.adjustPanelHeight(); + annotationHeight = ap.adjustForAlignFrame(adjustPanelHeight, + annotationHeight); hscroll.addNotify(); annotationScroller.setPreferredSize( @@ -596,6 +606,7 @@ public class AlignmentPanel extends GAlignmentPanel implements annotationSpaceFillerHolder.getWidth(), annotationHeight)); annotationScroller.validate(); annotationScroller.addNotify(); + ap.validate(); } /** @@ -1186,6 +1197,7 @@ public class AlignmentPanel extends GAlignmentPanel implements } int w = getIdPanel().getWidth(); + w = this.calculateIdWidth(-1, true, true).width; return (w > 0 ? w : calculateIdWidth().width); } @@ -1211,6 +1223,7 @@ public class AlignmentPanel extends GAlignmentPanel implements final int borderBottomOffset = 5; AlignmentDimension aDimension = getAlignmentDimension(); + // todo use a lambda function in place of callback here? ImageWriterI writer = new ImageWriterI() { diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java index ffc565c..26276ae 100755 --- a/src/jalview/gui/AnnotationLabels.java +++ b/src/jalview/gui/AnnotationLabels.java @@ -20,6 +20,7 @@ */ package jalview.gui; +import java.awt.Canvas; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; @@ -135,6 +136,8 @@ public class AnnotationLabels extends JPanel private boolean resizePanel = false; + private int annotationIdWidth = -1; + /** * Creates a new AnnotationLabels object * @@ -1198,36 +1201,41 @@ public class AnnotationLabels extends JPanel { Graphics2D g2d = (Graphics2D) g; Graphics dummy = g2d.create(); - int annotationIdWidth = drawLabels(dummy, clip, width, false); + int newAnnotationIdWidth = drawLabels(dummy, clip, width, false, + null); Dimension d = ap.calculateDefaultAlignmentIdWidth(); int alignmentIdWidth = d.width; if (!iwa.manuallyAdjusted()) { // If no manual adjustment to ID column with has been made then adjust // width match widest of alignment or annotation id widths - width = Math.max(alignmentIdWidth, annotationIdWidth); + width = Math.max(alignmentIdWidth, newAnnotationIdWidth); } - else if (annotationIdWidth > givenWidth - && annotationIdWidth > alignmentIdWidth) + else if (newAnnotationIdWidth != annotationIdWidth + && newAnnotationIdWidth > givenWidth + && newAnnotationIdWidth > alignmentIdWidth) { // otherwise if the annotation id width has become larger than the // current id width, increase - width = annotationIdWidth; + width = newAnnotationIdWidth; + annotationIdWidth = newAnnotationIdWidth; } // set the width if it's changed if (width != ap.av.getIdWidth()) { iwa.setWidth(width); - ap.validateAnnotationDimensions(false); } } - drawLabels(g, clip, width, true); + drawLabels(g, clip, width, true, null); } /** * Render the full set of annotation Labels for the alignment at the given - * cursor. If actuallyDraw is false then no actual drawing will occur, but the - * widest label width will be returned. + * cursor. If actuallyDraw is false or g is null then no actual drawing will + * occur, but the widest label width will be returned. If g is null then + * fmetrics must be supplied. + * + * Returns the width of the annotation labels. * * @param g * Graphics2D instance (needed for font scaling) @@ -1236,21 +1244,27 @@ public class AnnotationLabels extends JPanel * rendered * @param width * Width for scaling labels + * @param fmetrics + * FontMetrics if Graphics object g is null */ public int drawLabels(Graphics g, boolean clip, int width, - boolean actuallyDraw) + boolean actuallyDraw, FontMetrics fmetrics) { int actualWidth = 0; - if (av.getFont().getSize() < 10) + if (actuallyDraw && g != null) { - g.setFont(font); - } - else - { - g.setFont(av.getFont()); + if (av.getFont().getSize() < 10) + { + g.setFont(font); + } + else + { + g.setFont(av.getFont()); + } } - FontMetrics fm = g.getFontMetrics(g.getFont()); + FontMetrics fm = fmetrics == null ? g.getFontMetrics(g.getFont()) + : fmetrics; if (actuallyDraw) { g.setColor(Color.white); @@ -1265,12 +1279,13 @@ public class AnnotationLabels extends JPanel SequenceI lastSeqRef = null; String lastLabel = null; AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation(); - int fontHeight = g.getFont().getSize(); + int fontHeight = g != null ? g.getFont().getSize() + : fm.getFont().getSize(); int y = 0; int x = 0; int graphExtras = 0; int offset = 0; - Font baseFont = g.getFont(); + Font baseFont = g != null ? g.getFont() : fm.getFont(); FontMetrics baseMetrics = fm; int ofontH = fontHeight; int sOffset = 0; @@ -1334,7 +1349,7 @@ public class AnnotationLabels extends JPanel continue; } } - if (actuallyDraw) + if (actuallyDraw && g != null) { g.setColor(Color.black); } @@ -1417,10 +1432,15 @@ public class AnnotationLabels extends JPanel s = ((float) fontHeight) / (float) ofontH; Font f = baseFont .deriveFont(AffineTransform.getScaleInstance(s, s)); - g.setFont(f); - fm = g.getFontMetrics(); - graphExtras = (aa[i].height - (groupSize * (fontHeight + 8))) - / 2; + Canvas c = new Canvas(); + fm = c.getFontMetrics(f); + if (actuallyDraw && g != null) + { + g.setFont(f); + // fm = g.getFontMetrics(); + graphExtras = (aa[i].height + - (groupSize * (fontHeight + 8))) / 2; + } } } if (visible) @@ -1431,7 +1451,7 @@ public class AnnotationLabels extends JPanel { labelWidth = fm.stringWidth(aa[gg].label) + 3; x = width - labelWidth; - if (actuallyDraw) + if (actuallyDraw && g != null) { g.drawString(aa[gg].label, x, y - graphExtras); @@ -1450,13 +1470,16 @@ public class AnnotationLabels extends JPanel } } } - g.setFont(baseFont); + if (actuallyDraw && g != null) + { + g.setFont(baseFont); + } fm = baseMetrics; fontHeight = ofontH; } else { - if (actuallyDraw) + if (actuallyDraw && g != null) { if (vertBar) { @@ -1479,7 +1502,7 @@ public class AnnotationLabels extends JPanel if (!resizePanel && dragEvent != null && aa != null) { - if (actuallyDraw) + if (actuallyDraw && g != null) { g.setColor(Color.lightGray); g.drawString( @@ -1492,7 +1515,7 @@ public class AnnotationLabels extends JPanel if (!av.getWrapAlignment() && ((aa == null) || (aa.length < 1))) { - if (actuallyDraw) + if (actuallyDraw && g != null) { g.drawString(MessageManager.getString("label.right_click"), 2, 8); g.drawString(MessageManager.getString("label.to_add_annotation"), 2, diff --git a/src/jalview/jbgui/GAlignmentPanel.java b/src/jalview/jbgui/GAlignmentPanel.java index 6594e2d..2f0c75e 100755 --- a/src/jalview/jbgui/GAlignmentPanel.java +++ b/src/jalview/jbgui/GAlignmentPanel.java @@ -76,7 +76,7 @@ public class GAlignmentPanel extends JPanel protected JPanel scalePanelHolder = newJPanel(); - protected JPanel idPanelHolder = newJPanel(); + public JPanel idPanelHolder = newJPanel(); protected JPanel idSpaceFillerPanel1 = newJPanel(); -- 1.7.10.2