Community
Participate
Working Groups
Created attachment 271302 [details] Differences from original diagram to generated Image When using the SaveImageFeature, right after saving a diagram in the editor, in some situations the generated image is missing some elements to draw. Those situations look pseudo-random. This is what I´ve found after a few dozen tests: -It will not draw any pictogram inside the container shape (it will keep text), inclduing decorators. -Everything else seems to get drawn correctly. -It looks to happen randomly. Doing the same thing twice will sometimes trigger it sometimes not. Maybe there is an underlying race condition? -It seems to happen more often when removing than adding elements -It seems to happen more often when removing connections than other elements. -If you create the image again, changing nothing in the diagram, it generates the image properly. Please find examples attached as images. Code: This is the creation of the image, using a implementation of org.eclipse.graphiti.features.ISaveImageFeature Code: ... IDiagramTypeProvider dtp; dtp = GraphitiUi .getExtensionManager() .createDiagramTypeProvider(diagram, "TypeProvider"); //$NON-NLS-1$ ISaveDocImageFeature flowSaveImageFeature = ((FlowFeatureProvider) dtp.getFeatureProvider()).getSaveDocImageFeature(); SaveImageContext context = new SaveImageContext(); context.putProperty(ISaveDocImageFeature.EDITOR_PROPERTY_ID, fde); flowSaveImageFeature.execute(context); ... Big chunk of the definition of the Yellow element (dialog activity) which little screen inside is not getting drawn. Part of the "cascaded elements" are failing to get drawn. Code: ... @Override public ContainerShape getShape(ContainerShape targetContainer, ISprayStyle sprayStyle) { // Create a ContainerShape for this Shape Diagram diagram = peService.getDiagramForShape(targetContainer); ContainerShape containerShape = peCreateService.createContainerShape(targetContainer, true); SprayLayoutService.setId(containerShape, "FlowShapeDialogActivity.containerShape"); // define general layout for ContainerShape sprayStyle = new com.wincornixdorf.tools.flow.spray.styles.FlowYellow(); sprayStyle.getStyle(diagram).setProportional(false); sprayStyle.getStyle(diagram).setStretchH(false); sprayStyle.getStyle(diagram).setStretchV(false); // layout data SprayLayoutType containerLayout = SprayLayoutType.FIT; SprayLayoutService.setLayoutManager(containerShape, containerLayout, 0, 0, true); SprayLayoutService.getLayoutData(containerShape).setVisible(true); createCascadedElements(diagram, containerShape, sprayStyle); createAnchorPoints(diagram, containerShape); // Fix the broken coordinate syaten for not active container shapes SprayAbstractLayoutManager.fixOffset(containerShape); return containerShape; } // START GENERATING CASCADED ELEMENTS protected void createCascadedElements(Diagram diagram, ContainerShape containerShape, ISprayStyle sprayStyle) { IDirectEditingInfo directEditingInfo = getFeatureProvider().getDirectEditingInfo(); directEditingInfo.setMainPictogramElement(containerShape); directEditingInfo.setPictogramElement(containerShape); GraphicsAlgorithm element_0 = gaService.createInvisibleRectangle(containerShape); element_0.setStyle(sprayStyle.getStyle(diagram)); SprayLayoutService.setShapeFromDsl(containerShape, true); gaService.setLocationAndSize(element_0, 0, 0, 150, 65); createElement_1(diagram, containerShape, sprayStyle); // Set start values for height and width as properties on the element for Layout Feature SprayLayoutManager.setSizePictogramProperties(containerShape); } protected Shape createElement_2(Diagram diagram, ContainerShape parentShape, ISprayStyle sprayStyle) { Shape shape_2 = peCreateService.createShape(parentShape, false); SprayLayoutService.setId(shape_2, "FlowShapeDialogActivity.shape_2"); Text element_2 = gaService.createPlainText(shape_2); ISprayStyle style_2 = new com.wincornixdorf.tools.flow.spray.styles.FlowTextBold(); element_2.setStyle(style_2.getStyle(diagram)); gaService.setLocationAndSize(element_2, 5, 0, 130, 8); SprayLayoutService.setLayoutData(shape_2, 130, 8, true); element_2.setHorizontalAlignment(Orientation.ALIGNMENT_CENTER); element_2.setVerticalAlignment(Orientation.ALIGNMENT_BOTTOM); peService.setPropertyValue(element_2, ISprayConstants.TEXT_ID, TextIds.activityName.name()); peService.setPropertyValue(shape_2, ISprayConstants.TEXT_ID, TextIds.activityName.name()); element_2.setValue(""); getFeatureProvider().getDirectEditingInfo().setGraphicsAlgorithm(element_2); return shape_2; } protected Shape createElement_3(Diagram diagram, ContainerShape parentShape, ISprayStyle sprayStyle) { List<Point> pointList_3 = new ArrayList<Point>(); pointList_3.add(gaService.createPoint(1, 20, 0, 0)); pointList_3.add(gaService.createPoint(149, 20, 0, 0)); Shape shape_3 = peCreateService.createShape(parentShape, false); SprayLayoutService.setId(shape_3, "FlowShapeDialogActivity.shape_3"); Polyline element_3 = gaService.createPlainPolyline(shape_3, pointList_3); ISprayStyle style_3 = sprayStyle; element_3.setStyle(style_3.getStyle(diagram)); return shape_3; } protected Shape createElement_4(Diagram diagram, ContainerShape parentShape, ISprayStyle sprayStyle) { Shape shape_4 = peCreateService.createShape(parentShape, false); SprayLayoutService.setId(shape_4, "FlowShapeDialogActivity.shape_4"); Text element_4 = gaService.createPlainText(shape_4); ISprayStyle style_4 = new com.wincornixdorf.tools.flow.spray.styles.FlowText(); element_4.setStyle(style_4.getStyle(diagram)); gaService.setLocationAndSize(element_4, 5, 16, 6, 8); SprayLayoutService.setLayoutData(shape_4, 6, 8, true); element_4.setHorizontalAlignment(Orientation.ALIGNMENT_LEFT); element_4.setVerticalAlignment(Orientation.ALIGNMENT_BOTTOM); peService.setPropertyValue(element_4, ISprayConstants.TEXT_ID, TextIds.activityActionLabel.name()); peService.setPropertyValue(shape_4, ISprayConstants.TEXT_ID, TextIds.activityActionLabel.name()); element_4.setValue(""); getFeatureProvider().getDirectEditingInfo().setGraphicsAlgorithm(element_4); return shape_4; } protected Shape createElement_5(Diagram diagram, ContainerShape parentShape, ISprayStyle sprayStyle) { Shape shape_5 = peCreateService.createShape(parentShape, false); SprayLayoutService.setId(shape_5, "FlowShapeDialogActivity.shape_5"); Text element_5 = gaService.createPlainText(shape_5); ISprayStyle style_5 = new com.wincornixdorf.tools.flow.spray.styles.FlowText(); element_5.setStyle(style_5.getStyle(diagram)); gaService.setLocationAndSize(element_5, 65, 16, 80, 8); SprayLayoutService.setLayoutData(shape_5, 80, 8, true); element_5.setHorizontalAlignment(Orientation.ALIGNMENT_LEFT); element_5.setVerticalAlignment(Orientation.ALIGNMENT_BOTTOM); peService.setPropertyValue(element_5, ISprayConstants.TEXT_ID, TextIds.activityAction.name()); peService.setPropertyValue(shape_5, ISprayConstants.TEXT_ID, TextIds.activityAction.name()); element_5.setValue(""); getFeatureProvider().getDirectEditingInfo().setGraphicsAlgorithm(element_5); return shape_5; } protected Shape createElement_6(Diagram diagram, ContainerShape parentShape, ISprayStyle sprayStyle) { Shape shape_6 = peCreateService.createShape(parentShape, false); SprayLayoutService.setId(shape_6, "FlowShapeDialogActivity.shape_6"); Text element_6 = gaService.createPlainText(shape_6); ISprayStyle style_6 = new com.wincornixdorf.tools.flow.spray.styles.FlowText(); element_6.setStyle(style_6.getStyle(diagram)); gaService.setLocationAndSize(element_6, 5, 30, 60, 8); SprayLayoutService.setLayoutData(shape_6, 60, 8, true); element_6.setHorizontalAlignment(Orientation.ALIGNMENT_LEFT); element_6.setVerticalAlignment(Orientation.ALIGNMENT_BOTTOM); peService.setPropertyValue(element_6, ISprayConstants.TEXT_ID, TextIds.activityParameterLabel.name()); peService.setPropertyValue(shape_6, ISprayConstants.TEXT_ID, TextIds.activityParameterLabel.name()); element_6.setValue(""); getFeatureProvider().getDirectEditingInfo().setGraphicsAlgorithm(element_6); return shape_6; } protected Shape createElement_7(Diagram diagram, ContainerShape parentShape, ISprayStyle sprayStyle) { Shape shape_7 = peCreateService.createShape(parentShape, false); SprayLayoutService.setId(shape_7, "FlowShapeDialogActivity.shape_7"); Text element_7 = gaService.createPlainText(shape_7); ISprayStyle style_7 = new com.wincornixdorf.tools.flow.spray.styles.FlowText(); element_7.setStyle(style_7.getStyle(diagram)); gaService.setLocationAndSize(element_7, 65, 30, 80, 8); SprayLayoutService.setLayoutData(shape_7, 80, 8, true); element_7.setHorizontalAlignment(Orientation.ALIGNMENT_LEFT); element_7.setVerticalAlignment(Orientation.ALIGNMENT_BOTTOM); peService.setPropertyValue(element_7, ISprayConstants.TEXT_ID, TextIds.activityParameter.name()); peService.setPropertyValue(shape_7, ISprayConstants.TEXT_ID, TextIds.activityParameter.name()); element_7.setValue(""); getFeatureProvider().getDirectEditingInfo().setGraphicsAlgorithm(element_7); return shape_7; } protected Shape createElement_1(Diagram diagram, ContainerShape parentShape, ISprayStyle sprayStyle) { ContainerShape shape_1 = peCreateService.createContainerShape(parentShape, false); SprayLayoutService.setId(shape_1, "FlowShapeDialogActivity.shape_1"); RoundedRectangle element_1 = gaService.createPlainRoundedRectangle(shape_1, 15, 15); ISprayStyle style_1 = new com.wincornixdorf.tools.flow.spray.styles.FlowYellow(); element_1.setStyle(style_1.getStyle(diagram)); gaService.setLocationAndSize(element_1, 0, 0, 150, 65); SprayLayoutService.setLayoutData(shape_1, 150, 65, true); createElement_2(diagram, shape_1, style_1); createElement_3(diagram, shape_1, style_1); createElement_4(diagram, shape_1, style_1); createElement_5(diagram, shape_1, style_1); createElement_6(diagram, shape_1, style_1); createElement_7(diagram, shape_1, style_1); return shape_1; } // STOP GENERATING CASCADED ELEMENTS protected void createAnchorPoints(Diagram diagram, ContainerShape containerShape) { peCreateService.createChopboxAnchor(containerShape); } public SprayLayoutManager getShapeLayout() { ... }
Ignacio, what is the ISaveDocImageFeature and its implementation? Can you share the code? Michael
Hi Michael, Sure thing. I will provide you with some bigger snippets of components that play a role in this. Hopefully this can help. If you need any other info please let me know! ISaveDocImageFeature is quite empty: -------- ... import org.eclipse.graphiti.features.ISaveImageFeature; ... public interface ISaveDocImageFeature extends ISaveImageFeature { /** * The property id. */ String EDITOR_PROPERTY_ID = "editor"; //$NON-NLS-1$ void setProject(IProject project); } ... ------- What might be more interesting for you is a save image feature definition and the save conf used. ------- /** * Feature to save an image file of Graphiti based editor. * * @author ignacio.ibanez * */ public class SaveDocImageFeature extends DefaultSaveImageFeature implements ICustomFeature, ISaveDocImageFeature { private IProject project; /** * Creates a new SaveDocImage Feature. * * @param fp The feature provider for the SaveDocImage feature */ public SaveDocImageFeature(final IFeatureProvider fp) { super(fp); } @Override public String getName() { return ToolsMessages.SaveDocImageFeature_Title; } @Override public void setProject(IProject project) { this.project = project; } @Override public void save(ISaveImageContext context) { // Get viewer containing the diagram to print (by default the one // contained in the diagram editor that starts this feature GraphicalViewer viewer = getGraphicalViewer(context); // Configure and open dialog SaveDocImageConfiguration saveAsImageConfiguration = getSaveAsImageConfiguration(viewer); saveAsImageConfiguration.saveScaledImage(); IFolder ifolder = GraphitiUtil.getDocImageFolder(getDiagram(), project); String finalFilePath = GraphitiUtil.getDocImageFolderPath(getDiagram()); if (project != null) { ifolder = project.getFolder(ifolder.getProjectRelativePath()); IFolder imagesFolder = project.getFolder(ifolder.getProjectRelativePath()); finalFilePath = imagesFolder.getRawLocation().toOSString(); } String fileName = FilenameUtils.removeExtension(EMFFunctionUtil.EOBJ2IFILE.apply(getDiagram()).getName()); File folder = new File(finalFilePath); folder.mkdirs(); Shell shell = Display.getCurrent().getActiveShell(); try { CreateResourcesUtil.createFolders(ifolder, null); // Add extension to filename (if none exists) fileName = addFileExtension( saveAsImageConfiguration.getFormattedFileExtension(), fileName); finalFilePath = finalFilePath + System.getProperty("file.separator") //$NON-NLS-1$ + fileName; // $NON-NLS-1$ finalFilePath = addFileExtension( saveAsImageConfiguration.getFormattedFileExtension(), finalFilePath); IFile iFile = ifolder.getFile(fileName); // If the image is set as read/only we change it to non-read/only if (iFile.exists() && iFile.isReadOnly()) { ResourceAttributes resAttr = iFile.getResourceAttributes(); resAttr.setReadOnly(false); iFile.setResourceAttributes(resAttr); } // Create the save as image operation ... IRunnableWithProgress operation = getSaveAsImageOperation( saveAsImageConfiguration, finalFilePath); // ... and start save as image new ProgressMonitorDialog(shell).run(false, false, operation); } catch (Exception e) { String message = "Cannot save image: "; //$NON-NLS-1$ MessageDialog.openError(shell, "Cannot save image ", message + e.getMessage()); //$NON-NLS-1$ } } @Override protected SaveDocImageConfiguration getSaveAsImageConfiguration( GraphicalViewer viewer) { Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); SaveDocImageConfiguration saveAsImageDialog = new SaveDocImageConfiguration( shell, viewer); // Add exporters saveAsImageDialog.addExporters(getDiagramExporters()); return saveAsImageDialog; } /** * Gets the diagram editor. * * @param context the save image context. * @return the diagram editor. */ private DiagramEditor getEditor(ISaveImageContext context) { return (DiagramEditor) context.getProperty(EDITOR_PROPERTY_ID); // $NON-NLS-1$ } @Override protected GraphicalViewer getGraphicalViewer(ISaveImageContext context) { IDiagramContainerUI diagramContainer = getEditor(context).getDiagramBehavior().getDiagramContainer(); if (diagramContainer != null) { return diagramContainer.getAdapter(GraphicalViewer.class); } else { return null; } } @Override public String getImageId() { return null; } @Override public boolean canExecute(ICustomContext context) { return true; } @Override public void execute(ICustomContext context) { //NOSONAR needed for ICustomFeature super.execute(context); } } ------- public class SaveDocImageConfiguration extends AbstractConfiguration implements ISaveAsImageConfiguration { private static final String[] IMAGE_FILE_EXTENSIONS = new String[] { "BMP", "GIF", "JPG", "PNG", "RLE" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ private static final int[] IMAGE_FILE_TYPES = new int[] { SWT.IMAGE_BMP, SWT.IMAGE_GIF, SWT.IMAGE_JPEG, SWT.IMAGE_PNG, SWT.IMAGE_BMP_RLE }; private static final int DEFAULT_IMAGE_INDEX = 2; // PNG private static final double DEFAULT_UPPER_BOUND = 10000.0D; // selected values private int formatIndex = DEFAULT_IMAGE_INDEX; /** * Creates a new ExportDiagramDialog. * * @param shell * The Shell of this dialog. * @param graphicalViewer * The GraphicalViewer, which to save. */ public SaveDocImageConfiguration(final Shell shell, final GraphicalViewer graphicalViewer) { super(shell, graphicalViewer); } @Override public int configure() { return open(); } @Override public void addExporters(Map<String, Boolean> diagramExporterTypes) { // nothing to add here } /** * Saves the scaled image. */ public void saveScaledImage() { if (getImageFormat() == SWT.IMAGE_PNG) { setScaledImage(getImageScaleFactor(), DEFAULT_UPPER_BOUND); } else { setScaledImage(getImageScaleFactor()); } } @Override public final int getImageFormat() { if (formatIndex >= IMAGE_FILE_TYPES.length) { // Custom file type provided via extension return -1; } return IMAGE_FILE_TYPES[formatIndex]; } @Override public final String getFormattedFileExtension() { return IMAGE_FILE_EXTENSIONS[formatIndex].toLowerCase(Locale.ENGLISH); } @Override public final String getFileExtension() { return IMAGE_FILE_EXTENSIONS[formatIndex]; } @Override public double getImageScaleFactor() { return 1.0; } } -------