package org.plantuml.idea.rendering; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Pair; import net.sourceforge.plantuml.*; import net.sourceforge.plantuml.core.UmlSource; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Collections; import static org.plantuml.idea.rendering.PlantUmlRenderer.getTitles; import static org.plantuml.idea.rendering.PlantUmlRenderer.zoomDiagram; public class PlantUmlPartialRenderer extends PlantUmlNormalRenderer { private static final Logger logger = Logger.getInstance(PlantUmlPartialRenderer.class); @NotNull public RenderResult partialRender(RenderRequest renderRequest, @Nullable RenderCacheItem cachedItem, long start, String[] sourceSplit) { try { FileFormatOption formatOption = new FileFormatOption(renderRequest.getFormat().getFormat()); RenderResult renderResult = new RenderResult(RenderingType.PARTIAL, sourceSplit.length); for (int page = 0; page < sourceSplit.length; page++) { processPage(renderRequest, cachedItem, sourceSplit[page], formatOption, renderResult, page); } logger.debug("partial rendering done ", System.currentTimeMillis() - start, "ms"); return renderResult; } catch (PartialRenderingException e) { logger.debug(e); return renderError(renderRequest, e); } } @NotNull protected RenderResult renderError(RenderRequest renderRequest, PartialRenderingException e) { RenderResult renderResult = new RenderResult(RenderingType.PARTIAL, 1); ByteArrayOutputStream os = new ByteArrayOutputStream(); try { UmlSource source = new UmlSource(Collections.<CharSequence2>singletonList(new CharSequence2Impl("", new LineLocationImpl(null, null))), false); ErrorUml singleError = new ErrorUml(ErrorUmlType.EXECUTION_ERROR, e.getMessage(), 0, null); PSystemError pSystemError = new PSystemError(source, singleError, null); pSystemError.exportDiagram(os, 0, new FileFormatOption(FileFormat.PNG)); } catch (IOException e1) { logger.warn(e1); throw e; } renderResult.addRenderedImage(new ImageItem(renderRequest.getBaseDir(), renderRequest.getSource(), null, 0, "(Error)", os.toByteArray(), null, RenderingType.PARTIAL, null)); return renderResult; } public void processPage(RenderRequest renderRequest, @Nullable RenderCacheItem cachedItem, String s, FileFormatOption formatOption, RenderResult renderResult, int page) { long partialPageProcessingStart = System.currentTimeMillis(); String partialSource = "@startuml\n" + s + "\n@enduml"; boolean obsolete = cachedItem == null || renderRequest.requestedRefreshOrIncludesChanged() || RenderingType.PARTIAL.renderingTypeChanged(cachedItem) || renderRequest.getZoom() != cachedItem.getZoom() || !partialSource.equals(cachedItem.getImagesItemPageSource(page)); boolean pageSelected = renderRequest.getPage() == -1 || renderRequest.getPage() == page; boolean shouldRender = pageSelected && (obsolete || !cachedItem.hasImage(page)); if (shouldRender) { renderResult.addRenderedImage(renderImage(renderRequest, page, formatOption, partialSource)); } else if (obsolete) { renderResult.addUpdatedTitle(updateTitle(renderRequest, page, partialSource)); } else { logger.debug("page ", page, " cached"); renderResult.addCachedImage(cachedItem.getImageItem(page)); } logger.debug("processing of page ", page, " done in ", System.currentTimeMillis() - partialPageProcessingStart, "ms"); } private ImageItem updateTitle(RenderRequest renderRequest, int page, String partialSource) { long start = System.currentTimeMillis(); logger.debug("updating title, page ", page); SourceStringReader reader = new SourceStringReader(partialSource); String title = getTitle(reader); ImageItem imageItem = new ImageItem(renderRequest.getBaseDir(), renderRequest.getSource(), partialSource, page, TITLE_ONLY, null, null, RenderingType.PARTIAL, title); logger.debug("updateTitle " + (System.currentTimeMillis() - start)); return imageItem; } private String getTitle(SourceStringReader reader) { Titles titles = getTitles(1, reader.getBlocks()); if (titles.size() > 1) { throw new PartialRenderingException(); } return titles.get(0); } private ImageItem renderImage(RenderRequest renderRequest, int page, FileFormatOption formatOption, String partialSource) { logger.debug("rendering partially, page ", page); SourceStringReader reader = new SourceStringReader(partialSource); Pair<Integer, Titles> pages = zoomDiagram(reader, renderRequest.getZoom()); Integer totalPages = pages.first; Titles titles = pages.second; if (totalPages > 1) { throw new PartialRenderingException(); } if (titles.size() > 1) { logger.warn("too many titles " + titles + ", partialSource=" + partialSource); } try { return new ImageItem(page, generateImageItem(renderRequest, renderRequest.getSource(), partialSource, reader, formatOption, 0, page, RenderingType.PARTIAL, titles.get(0))); } catch (RenderingCancelledException e) { throw e; } catch (Throwable e) { throw new RuntimeException(e); } } }