package org.csstudio.sds.ui.thumbnail; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.List; import org.csstudio.sds.internal.persistence.PersistenceUtil; import org.csstudio.sds.model.AbstractWidgetModel; import org.csstudio.sds.model.ContainerModel; import org.csstudio.sds.model.DisplayModel; import org.csstudio.sds.model.LinkingContainerModel; import org.csstudio.sds.ui.editparts.ExecutionMode; import org.csstudio.sds.ui.internal.editparts.DisplayEditPart; import org.csstudio.sds.ui.internal.editparts.WidgetEditPartFactory; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.draw2d.Graphics; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.SWTGraphics; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gef.EditPart; import org.eclipse.gef.editparts.ScalableFreeformRootEditPart; import org.eclipse.gef.ui.parts.GraphicalViewerImpl; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; public class SdsThumbnailCreator { public ImageData createImage(DisplayModel displayModel, final int thumbSize, final Display display) { ThumbnailCreationJob job = new ThumbnailCreationJob(display, displayModel, thumbSize, false); return job.getImageData(); } public ImageData createImageWithZoomingIn(DisplayModel displayModel, final int thumbSize, final Display display) { ThumbnailCreationJob job = new ThumbnailCreationJob(display, displayModel, thumbSize, true); return job.getImageData(); } private static class ThumbnailCreationJob implements Runnable { private final Display display; private final DisplayModel displayModel; private final int thumbSize; private final boolean isZoomInEnabled; private ImageData imageData; public ThumbnailCreationJob(Display display, DisplayModel displayModel, int thumbSize, boolean isZoomInEnabled) { this.display = display; this.thumbSize = thumbSize; this.displayModel = displayModel; this.isZoomInEnabled = isZoomInEnabled; if (!display.isDisposed()) { display.syncExec(this); } } public ImageData getImageData() { return imageData; } @Override public void run() { if (!display.isDisposed()) { loadLinkingContainersRecursive(displayModel, 10); Shell shell = new Shell(display, SWT.NO_TRIM); Image image = null; try { shell.setLayout(new FillLayout()); shell.setSize(displayModel.getWidth(), displayModel.getHeight()); ThumbnailDrawingViewer viewer = new ThumbnailDrawingViewer(); viewer.createControl(shell); viewer.setEditPartFactory(new NoBorderWidgetEditPartFactory( ExecutionMode.EDIT_MODE)); viewer.setRootEditPart(new ScalableFreeformRootEditPart()); viewer.setContents(displayModel); shell.layout(); image = viewer.createImage(thumbSize, isZoomInEnabled); imageData = image.getImageData(); } finally { if (image != null) { image.dispose(); } shell.dispose(); } } } private void loadLinkingContainersRecursive(ContainerModel model, int recursionDepth) { List<AbstractWidgetModel> childWidgets = model.getWidgets(); for (AbstractWidgetModel childModel : childWidgets) { int childRecursionDepth = recursionDepth; if (childModel instanceof LinkingContainerModel) { LinkingContainerModel linkingContainerChildModel = (LinkingContainerModel) childModel; if (childRecursionDepth > 0) { loadLinkingContainer(linkingContainerChildModel); childRecursionDepth -= 1; } else { mockFillLinkingContainer(linkingContainerChildModel); } } if (childModel instanceof ContainerModel) { loadLinkingContainersRecursive((ContainerModel) childModel, childRecursionDepth); } } } private void mockFillLinkingContainer(LinkingContainerModel modelToBeFilled) { modelToBeFilled.setResourceLoaded(true); modelToBeFilled.setColor( AbstractWidgetModel.PROP_COLOR_BACKGROUND, "#FF0000"); modelToBeFilled.setColor( AbstractWidgetModel.PROP_COLOR_FOREGROUND, "#000000"); } private void loadLinkingContainer(LinkingContainerModel linkingContainerModel) { // Load linked resource DisplayModel loadedModel = new DisplayModel(); InputStream inputStream = getInputStream(linkingContainerModel.getResource()); if (inputStream != null) { PersistenceUtil.syncFillModel(loadedModel, inputStream); } List<AbstractWidgetModel> loadedWidgets = loadedModel.getWidgets(); loadedModel.removeWidgets(loadedWidgets); linkingContainerModel.addWidgets(loadedWidgets); linkingContainerModel.setColor( AbstractWidgetModel.PROP_COLOR_BACKGROUND, loadedModel.getColor(AbstractWidgetModel.PROP_COLOR_BACKGROUND)); linkingContainerModel.setColor( AbstractWidgetModel.PROP_COLOR_FOREGROUND, loadedModel.getColor(AbstractWidgetModel.PROP_COLOR_FOREGROUND)); linkingContainerModel.setResourceLoaded(true); } /** * Return the {@link InputStream} of the file that is available on the * specified path. * * @param path * The {@link IPath} to the file * * @return The corresponding {@link InputStream} or null */ private InputStream getInputStream(final IPath path) { InputStream result = null; // try workspace IResource r = ResourcesPlugin.getWorkspace().getRoot() .findMember(path, false); if (r instanceof IFile) { try { result = ((IFile) r).getContents(); } catch (CoreException e) { result = null; } } if (result == null) { // try from local file system try { result = new FileInputStream(path.toFile()); } catch (FileNotFoundException e) { result = null; } } return result; } } private static class ThumbnailDrawingViewer extends GraphicalViewerImpl { public Image createImage(int thumbSize, boolean isZoomInEnabled) { IFigure figure = getLightweightSystem().getRootFigure(); Rectangle bounds = figure.getBounds(); double widthFactor = (double) thumbSize / (double) bounds.width; double heightFactor = (double) thumbSize / (double) bounds.height; double factor = Math.min(widthFactor, heightFactor); Image image = new Image(Display.getCurrent(), (int) Math.ceil((double) bounds.width * factor), (int) Math.ceil((double) bounds.height * factor)); GC gc = new GC(image); Graphics graphics = new SWTGraphics(gc); // Special handling if max zoom level == 1 if(!isZoomInEnabled && factor > 1) { factor = 1; // center figure in image figure.translate((image.getBounds().width - bounds.width) / 2, (image.getBounds().height - bounds.height) / 2); } graphics.scale(factor); figure.paint(graphics); gc.dispose(); // TODO disposing in finally-Block return image; } } private static class NoBorderWidgetEditPartFactory extends WidgetEditPartFactory { public NoBorderWidgetEditPartFactory(ExecutionMode executionMode) { super(executionMode); } @Override public EditPart createEditPart(EditPart context, Object modelElement) { EditPart result = super.createEditPart(context, modelElement); if (modelElement instanceof DisplayModel) { ((DisplayEditPart) result) .setExecutionMode(ExecutionMode.RUN_MODE); } return result; } } }