/* ======================================================================== * PlantUML : a free UML diagram generator * ======================================================================== * * (C) Copyright 2009-2023, Arnaud Roques * * Project Info: http://plantuml.com * * If you like this project or if you find it useful, you can support us at: * * http://plantuml.com/patreon (only 1$ per month!) * http://plantuml.com/paypal * * This file is part of PlantUML. * * PlantUML is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * PlantUML distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public * License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA. * * * Original Author: Arnaud Roques * * */ package net.sourceforge.plantuml.svek; import java.awt.Color; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import net.sourceforge.plantuml.BackSlash; import net.sourceforge.plantuml.OptionPrint; import net.sourceforge.plantuml.StringUtils; import net.sourceforge.plantuml.awt.geom.Dimension2D; import net.sourceforge.plantuml.command.CommandExecutionResult; import net.sourceforge.plantuml.cucadiagram.dot.GraphvizUtils; import net.sourceforge.plantuml.flashcode.FlashCodeFactory; import net.sourceforge.plantuml.flashcode.FlashCodeUtils; import net.sourceforge.plantuml.fun.IconLoader; import net.sourceforge.plantuml.graphic.AbstractTextBlock; import net.sourceforge.plantuml.graphic.GraphicPosition; import net.sourceforge.plantuml.graphic.GraphicStrings; import net.sourceforge.plantuml.graphic.HorizontalAlignment; import net.sourceforge.plantuml.graphic.QuoteUtils; import net.sourceforge.plantuml.graphic.StringBounder; import net.sourceforge.plantuml.graphic.TextBlock; import net.sourceforge.plantuml.graphic.TextBlockUtils; import net.sourceforge.plantuml.ugraphic.AffineTransformType; import net.sourceforge.plantuml.ugraphic.PixelImage; import net.sourceforge.plantuml.ugraphic.UGraphic; import net.sourceforge.plantuml.ugraphic.UImage; import net.sourceforge.plantuml.ugraphic.color.HColor; import net.sourceforge.plantuml.ugraphic.color.HColorUtils; import net.sourceforge.plantuml.version.PSystemVersion; import net.sourceforge.plantuml.version.Version; public class GraphvizCrash extends AbstractTextBlock implements IEntityImage { private final TextBlock text1; private final BufferedImage flashCode; private final String text; private final boolean graphviz244onWindows; public GraphvizCrash(String text, boolean graphviz244onWindows, Throwable rootCause) { this.text = text; this.graphviz244onWindows = graphviz244onWindows; final FlashCodeUtils utils = FlashCodeFactory.getFlashCodeUtils(); this.flashCode = utils.exportFlashcode(text, Color.BLACK, Color.WHITE); this.text1 = GraphicStrings.createBlackOnWhite(init(rootCause), IconLoader.getRandom(), GraphicPosition.BACKGROUND_CORNER_TOP_RIGHT); } public static List anErrorHasOccured(Throwable exception, String text) { final List strings = new ArrayList<>(); if (exception == null) { strings.add("An error has occured!"); } else { strings.add("An error has occured : " + exception); } final String quote = StringUtils.rot(QuoteUtils.getSomeQuote()); strings.add("" + quote); strings.add(" "); strings.add("Diagram size: " + lines(text) + " lines / " + text.length() + " characters."); strings.add(" "); return strings; } private static int lines(String text) { int result = 0; for (int i = 0; i < text.length(); i++) { if (text.charAt(i) == BackSlash.CHAR_NEWLINE) { result++; } } return result; } public static void checkOldVersionWarning(List strings) { final long days = (System.currentTimeMillis() - Version.compileTime()) / 1000L / 3600 / 24; if (days >= 90) { strings.add(" "); strings.add("This version of PlantUML is " + days + " days old, so you should"); strings.add("consider upgrading from https://plantuml.com/download"); } } public static void pleaseGoTo(List strings) { strings.add(" "); strings.add("Please go to https://plantuml.com/graphviz-dot to check your GraphViz version."); strings.add(" "); } public static void youShouldSendThisDiagram(List strings) { strings.add("You should send this diagram and this image to plantuml@gmail.com or"); strings.add("post to https://plantuml.com/qa to solve this issue."); strings.add("You can try to turn arround this issue by simplifing your diagram."); } public static void thisMayBeCaused(final List strings) { strings.add("This may be caused by :"); strings.add(" - a bug in PlantUML"); strings.add(" - a problem in GraphViz"); } private List init(Throwable rootCause) { final List strings = anErrorHasOccured(null, text); strings.add("For some reason, dot/GraphViz has crashed."); strings.add(""); strings.add("RootCause " + rootCause); if (rootCause != null) { strings.addAll(CommandExecutionResult.getStackTrace(rootCause)); } strings.add(""); strings.add("This has been generated with PlantUML (" + Version.versionString() + ")."); checkOldVersionWarning(strings); strings.add(" "); addProperties(strings); strings.add(" "); try { final String dotVersion = GraphvizUtils.dotVersion(); strings.add("Default dot version: " + dotVersion); } catch (Throwable e) { strings.add("Cannot determine dot version: " + e.toString()); } pleaseGoTo(strings); youShouldSendThisDiagram(strings); if (flashCode != null) { addDecodeHint(strings); } return strings; } private List getText2() { final List strings = new ArrayList<>(); strings.add(" "); strings.add("It looks like you are running GraphViz 2.44 under Windows."); strings.add("If you have just installed GraphViz, you may have to execute"); strings.add("the post-install command dot -c like in the following example:"); return strings; } private List getText3() { final List strings = new ArrayList<>(); strings.add(" "); strings.add("You may have to have Administrator rights to avoid the following error message:"); return strings; } public static void addDecodeHint(final List strings) { strings.add(" "); strings.add(" Diagram source: (Use http://zxing.org/w/decode.jspx to decode the qrcode)"); } public static void addProperties(final List strings) { strings.addAll(OptionPrint.interestingProperties()); strings.addAll(OptionPrint.interestingValues()); } public boolean isHidden() { return false; } public HColor getBackcolor() { return HColorUtils.WHITE; } public Dimension2D calculateDimension(StringBounder stringBounder) { return getMain().calculateDimension(stringBounder); } public void drawU(UGraphic ug) { getMain().drawU(ug); } private TextBlock getMain() { TextBlock result = text1; if (flashCode != null) { final UImage flash = new UImage(new PixelImage(flashCode, AffineTransformType.TYPE_NEAREST_NEIGHBOR)) .scale(3); result = TextBlockUtils.mergeTB(result, flash, HorizontalAlignment.LEFT); } if (graphviz244onWindows) { final TextBlock text2 = GraphicStrings.createBlackOnWhite(getText2()); result = TextBlockUtils.mergeTB(result, text2, HorizontalAlignment.LEFT); final UImage dotc = new UImage(new PixelImage(PSystemVersion.getDotc(), AffineTransformType.TYPE_BILINEAR)); result = TextBlockUtils.mergeTB(result, dotc, HorizontalAlignment.LEFT); final TextBlock text3 = GraphicStrings.createBlackOnWhite(getText3()); result = TextBlockUtils.mergeTB(result, text3, HorizontalAlignment.LEFT); final UImage dotd = new UImage(new PixelImage(PSystemVersion.getDotd(), AffineTransformType.TYPE_BILINEAR)); result = TextBlockUtils.mergeTB(result, dotd, HorizontalAlignment.LEFT); } return result; } public ShapeType getShapeType() { return ShapeType.RECTANGLE; } public Margins getShield(StringBounder stringBounder) { return Margins.NONE; } public double getOverscanX(StringBounder stringBounder) { return 0; } }