/* * Copyright (c) 2012 European Synchrotron Radiation Facility, * Diamond Light Source Ltd. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ /* * Program to provide SWT utilities * Created on May 12, 2006 * By Kenneth Evans, Jr. */ package fable.framework.toolbox; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.DirectColorModel; import java.awt.image.IndexColorModel; import java.awt.image.WritableRaster; import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStream; import java.net.URI; import java.text.SimpleDateFormat; import java.util.Date; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResourceStatus; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.graphics.FontMetrics; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.PaletteData; import org.eclipse.swt.graphics.RGB; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.IPathEditorInput; import org.eclipse.ui.IStorageEditorInput; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.examples.rcp.texteditor.editors.PathEditorInput; import org.eclipse.ui.ide.FileStoreEditorInput; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.FileEditorInput; public class SWTUtils { public static final String LS = System.getProperty("line.separator"); /** * Generates a timestamp. * * @return String timestamp with the current time */ public static String timeStamp() { Date now = new Date(); final SimpleDateFormat defaultFormatter = new SimpleDateFormat( "MMM dd, yyyy HH:mm:ss.SSS"); return defaultFormatter.format(now); } /** * Generates a timestamp given a pattern * * @param pattern * appropriate for SimpleDateFormat * @return String timestamp with the current time */ public static String timeStamp(String pattern) { Date now = new Date(); final SimpleDateFormat dateFormatter = new SimpleDateFormat(pattern); return dateFormatter.format(now); } /** * Displays an error MessageDialog. Same as errMsg(null, msg). * * @param msg */ public static void errMsg(String msg) { errMsg(null, msg); } /** * Displays an error MessageDialog. * * @param shell * Can be null. * @param msg */ public static void errMsg(final Shell shell, final String msg) { MessageDialog.openError(shell, "Error", msg); } /** * Same as errMsgAsync(null, msg). Displays an error MessageDialog using * asyncExec. * * @param msg */ public static void errMsgAsync(String msg) { errMsgAsync(null, msg); } /** * Displays an error MessageDialog using asyncExec. * * @param shell * Can be null. * @param msg */ public static void errMsgAsync(final Shell shell, final String msg) { Display.getDefault().asyncExec(new Runnable() { public void run() { MessageDialog.openError(shell, "Error", msg); } }); } /** * Displays a warning MessageDialog. Same as warnMsg(null, msg). * * @param msg */ public static void warnMsg(String msg) { warnMsg(null, msg); } /** * Displays a warning MessageDialog. * * @param shell * Can be null. * @param msg */ public static void warnMsg(final Shell shell, final String msg) { MessageDialog.openWarning(shell, "Warning", msg); } /** * Displays a warning MessageDialog using asyncExec. Same as * warnMsgAsync(null, msg). * * @param msg */ public static void warnMsgAsync(String msg) { warnMsgAsync(null, msg); } /** * Displays a warning MessageDialog using asyncExec. * * @param shell * Can be null. * @param msg */ public static void warnMsgAsync(final Shell shell, final String msg) { Display.getDefault().asyncExec(new Runnable() { public void run() { MessageDialog.openWarning(shell, "Warning", msg); } }); } /** * Displays an information MessageDialog. Same as infoMsg(null, msg). * * @param msg */ public static void infoMsg(String msg) { infoMsg(null, msg); } /** * Displays an information MessageDialog. * * @param shell * Can be null. * @param msg */ public static void infoMsg(final Shell shell, final String msg) { MessageDialog.openInformation(shell, "Information", msg); } /** * Same as infoMsgAsync(null, msg). Displays an information MessageDialog * using asyncExec. * * @param msg */ public static void infoMsgAsync(String msg) { infoMsgAsync(null, msg); } /** * Displays an information MessageDialog using asyncExec. * * @param shell * Can be null. * @param msg */ public static void infoMsgAsync(final Shell shell, final String msg) { Display.getDefault().asyncExec(new Runnable() { public void run() { MessageDialog.openInformation(shell, "Information", msg); } }); } /** * Displays an exception MessageDialog. Same as excMsg(null, msg, ex). * * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excMsg(String msg, Exception ex) { excMsg(null, msg, ex); } /** * Displays an exception MessageDialog. * * @param shell * Can be null. * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excMsg(final Shell shell, final String msg, Exception ex) { String fullMsg = msg + LS + LS + "Exception: " + ex + LS + "Message: " + ex.getMessage(); MessageDialog.openError(shell, "Exception", fullMsg); } /** * Displays an exception MessageDialog using asyncExec. Same as * excMsgAsync(null, msg, ex). * * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excMsgAsync(String msg, Exception ex) { excMsgAsync(null, msg, ex); } /** * Displays an exception MessageDialog using asyncExec. * * @param shell * Can be null. * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excMsgAsync(final Shell shell, final String msg, Exception ex) { final String fullMsg = msg + LS + LS + "Exception: " + ex + LS + "Message: " + ex.getMessage(); Display.getDefault().asyncExec(new Runnable() { public void run() { MessageDialog.openError(shell, "Exception", fullMsg); } }); } /** * Displays an ExceptionMessageDialog. Same as excTraceMsg(null, msg, ex). * * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excTraceMsg(String msg, Exception ex) { excTraceMsg(null, msg, ex); } /** * Displays an exception ExceptionMessageDialog. * * @param shell * Can be null. * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excTraceMsg(final Shell shell, final String msg, Exception ex) { ExceptionMessageDialog.openException(shell, "Exception", msg, ex); } /** * Displays an ExceptionMessageDialog using asyncExec. Same as * excTraceMsgAsync(null, msg, ex). * * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excTraceMsgAsync(String msg, Exception ex) { excTraceMsgAsync(null, msg, ex); } /** * Displays an ExceptionMessageDialog using asyncExec. * * @param shell * Can be null. * @param msg * The first part of the message, to which exception information * is added. * @param ex */ public static void excTraceMsgAsync(final Shell shell, final String msg, final Exception ex) { Display.getDefault().asyncExec(new Runnable() { public void run() { ExceptionMessageDialog.openException(shell, "Exception", msg, ex); } }); } /** * If the SWT Text DELIMITER is CRLF, then it converts LF not preceeded by * CR to DELIMITER. Otherwise it just returns the string. This is necessary * for mixed CRLF and LF to appear as new lines in Text. The Swing TextArea * does not have this problem. * * @param string * The string to convert. * @return */ public static String convertText(String string) { String delimiter = Text.DELIMITER; if (delimiter.equals(LS)) return string; String out = ""; int lf = 0xa; int cr = 0xd; int prev = 0; int len = string.length(); for (int i = 0; i < len; i++) { char chr = string.charAt(i); int val = (int) chr; if (val != lf) { // Regular character out += chr; } else { // Is a LF if (i > 0) { prev = (int) string.charAt(i - 1); if (prev == cr) { // Previous was a CR, add the LF out += chr; } else { // LF without preceding CR, replace with delimiter // (CRLF) out += delimiter; } } else { // LF at start of line (no preceding CR) replace with // delimiter (CRLF) out += delimiter; } } } return out; } /** * Creates a file resource given the file handle and contents. From * org.eclipse.ui.dialogs.WizardnewFileCreationPage. * * @param fileHandle * the file handle to create a file resource with * @param contents * the initial contents of the new file resource, or * <code>null</code> if none (equivalent to an empty stream) * @param monitor * the progress monitor to show visual progress with * @exception CoreException * if the operation fails * @exception OperationCanceledException * if the operation is canceled */ public static void createFileFromIFile(IFile fileHandle, InputStream contents, IProgressMonitor monitor) throws CoreException { if (contents == null) { contents = new ByteArrayInputStream(new byte[0]); } try { // Create a new file resource in the workspace IPath path = fileHandle.getFullPath(); IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); int numSegments = path.segmentCount(); if (numSegments > 2 && !root.getFolder(path.removeLastSegments(1)).exists()) { // If the direct parent of the path doesn't exist, try to create // the // necessary directories. for (int i = numSegments - 2; i > 0; i--) { IFolder folder = root.getFolder(path.removeLastSegments(i)); if (!folder.exists()) { folder.create(false, true, monitor); } } } fileHandle.create(contents, false, monitor); } catch (CoreException e) { // If the file already existed locally, just refresh to get contents if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED) { fileHandle.refreshLocal(IResource.DEPTH_ZERO, null); } else { throw e; } } if (monitor != null && monitor.isCanceled()) { throw new OperationCanceledException(); } } /** * Returns the IPath for a variety of IEditorInput's. From the IMP project, * but modified. Note that given the IPath, you can find the fileName and * other information by using IPath.toFile(). * * @return the IPath corresponding to the given input, or null if none. */ public static IPath getPath(IEditorInput editorInput) { IPath path = null; if (editorInput instanceof IFileEditorInput) { IFileEditorInput fileEditorInput = (IFileEditorInput) editorInput; path = fileEditorInput.getFile().getLocation(); } else if (editorInput instanceof IPathEditorInput) { IPathEditorInput pathInput = (IPathEditorInput) editorInput; path = pathInput.getPath(); } else if (editorInput instanceof IStorageEditorInput) { IStorageEditorInput storageEditorInput = (IStorageEditorInput) editorInput; try { // Can be null path = storageEditorInput.getStorage().getFullPath(); } catch (CoreException ex) { // do nothing; return null; } } else if (editorInput instanceof FileStoreEditorInput) { FileStoreEditorInput fileStoreEditorInput = (FileStoreEditorInput) editorInput; path = new Path(fileStoreEditorInput.getURI().getPath()); } return path; } /** * From the IMP project. * * @return the IFile corresponding to the given input, or null if none. */ public static IFile getFile(IEditorInput editorInput) { IFile file = null; if (editorInput instanceof IFileEditorInput) { IFileEditorInput fileEditorInput = (IFileEditorInput) editorInput; file = fileEditorInput.getFile(); } else if (editorInput instanceof IPathEditorInput) { IPathEditorInput pathInput = (IPathEditorInput) editorInput; IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); if (wsRoot.getLocation().isPrefixOf(pathInput.getPath())) { file = ResourcesPlugin.getWorkspace().getRoot().getFile( pathInput.getPath()); } else { // Can't get an IFile for an arbitrary file on the file system; // return null } } else if (editorInput instanceof IStorageEditorInput) { // IStorageEditorInput storageEditorInput = (IStorageEditorInput) // editorInput; // Can't get an IFile for an arbitrary IStorageEditorInput file = null; } else if (editorInput instanceof FileStoreEditorInput) { IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot(); FileStoreEditorInput fileStoreEditorInput = (FileStoreEditorInput) editorInput; URI uri = fileStoreEditorInput.getURI(); String path = uri.getPath(); // Bug 526: uri.getHost() can be null for a local file URL if (uri.getScheme().equals("file") && (uri.getHost() == null || uri.getHost().equals( "localhost")) && path.startsWith(wsRoot.getLocation().toOSString())) { file = wsRoot.getFile(new Path(path)); } } return file; } /** * @return the name extension (e.g., "java" or "cpp") corresponding to this * input, if known, or the empty string if none. Does not include a * leading ".". From the IMP project. */ public static String getNameExtension(IEditorInput editorInput) { return getPath(editorInput).getFileExtension(); } /** * Recursively enables or disables this control and all its children. * * @param control * Control to be enabled or disabled. * @param enabled * Whether to enable or disable. */ public static void enableControlTree(Control control, boolean enabled) { if (control == null) return; if (control instanceof Composite) { Composite composite = (Composite) control; Control[] controls = composite.getChildren(); for (Control control1 : controls) { enableControlTree(control1, enabled); } } control.setEnabled(enabled); } /** * Converts an SWT ImageData to an AWT BufferedImage. * * @param bufferedImage * @return */ public static BufferedImage convertToAWT(ImageData data) { ColorModel colorModel = null; PaletteData palette = data.palette; if (palette.isDirect) { colorModel = new DirectColorModel(data.depth, palette.redMask, palette.greenMask, palette.blueMask); BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height), false, null); for (int y = 0; y < data.height; y++) { for (int x = 0; x < data.width; x++) { int pixel = data.getPixel(x, y); RGB rgb = palette.getRGB(pixel); bufferedImage.setRGB(x, y, rgb.red << 16 | rgb.green << 8 | rgb.blue); } } return bufferedImage; } else { RGB[] rgbs = palette.getRGBs(); byte[] red = new byte[rgbs.length]; byte[] green = new byte[rgbs.length]; byte[] blue = new byte[rgbs.length]; for (int i = 0; i < rgbs.length; i++) { RGB rgb = rgbs[i]; red[i] = (byte) rgb.red; green[i] = (byte) rgb.green; blue[i] = (byte) rgb.blue; } if (data.transparentPixel != -1) { colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue, data.transparentPixel); } else { colorModel = new IndexColorModel(data.depth, rgbs.length, red, green, blue); } BufferedImage bufferedImage = new BufferedImage(colorModel, colorModel.createCompatibleWritableRaster(data.width, data.height), false, null); WritableRaster raster = bufferedImage.getRaster(); int[] pixelArray = new int[1]; for (int y = 0; y < data.height; y++) { for (int x = 0; x < data.width; x++) { int pixel = data.getPixel(x, y); pixelArray[0] = pixel; raster.setPixel(x, y, pixelArray); } } return bufferedImage; } } /** * Converts an AWT BufferedImage to an SWT ImageData. * * @param bufferedImage * @return */ public static ImageData convertToSWT(BufferedImage bufferedImage) { if (bufferedImage.getColorModel() instanceof DirectColorModel) { DirectColorModel colorModel = (DirectColorModel) bufferedImage .getColorModel(); PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(), colorModel.getBlueMask()); ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette); for (int y = 0; y < data.height; y++) { for (int x = 0; x < data.width; x++) { int rgb = bufferedImage.getRGB(x, y); int pixel = palette.getPixel(new RGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF)); data.setPixel(x, y, pixel); } } return data; } else if (bufferedImage.getColorModel() instanceof IndexColorModel) { IndexColorModel colorModel = (IndexColorModel) bufferedImage .getColorModel(); int size = colorModel.getMapSize(); byte[] reds = new byte[size]; byte[] greens = new byte[size]; byte[] blues = new byte[size]; colorModel.getReds(reds); colorModel.getGreens(greens); colorModel.getBlues(blues); RGB[] rgbs = new RGB[size]; for (int i = 0; i < rgbs.length; i++) { rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF); } PaletteData palette = new PaletteData(rgbs); ImageData data = new ImageData(bufferedImage.getWidth(), bufferedImage.getHeight(), colorModel.getPixelSize(), palette); data.transparentPixel = colorModel.getTransparentPixel(); WritableRaster raster = bufferedImage.getRaster(); int[] pixelArray = new int[1]; for (int y = 0; y < data.height; y++) { for (int x = 0; x < data.width; x++) { raster.getPixel(x, y, pixelArray); data.setPixel(x, y, pixelArray[0]); } } return data; } return null; } /** * Finds the width for a Text control given the number of columns desired. * * @param text * @param cols * @return */ public static int getTextWidth(Text text, int cols) { GC gc = new GC(text); FontMetrics fm = gc.getFontMetrics(); int width = cols * fm.getAverageCharWidth(); gc.dispose(); return width; } /** * Creates a new IEditorInput from a File. Tries to create a FileEditorInput * if the file is in the workbench, otherwise creates a PathEditorInput. * * @param file * @return */ public static IEditorInput createEditorInput(File file) { IPath iPath = new Path(file.getAbsolutePath()); IFile iFile = null; IEditorInput input = null; // Try a FileEditorInput, resource in the workbench, has persistence IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); if (root != null && iPath != null) { iFile = root.getFileForLocation(iPath); } if (iFile != null) { input = new FileEditorInput(iFile); } if (input != null) { return input; } // Try a FileStoreInput, resource in the local file system, has // persistence IFileStore fileStore = null; String parentPath = null; File parent = file.getParentFile(); if (parent != null) { parentPath = parent.getAbsolutePath(); } if (parentPath != null) { fileStore = EFS.getLocalFileSystem().getStore(new Path(parentPath)); } if (fileStore != null) { fileStore = fileStore.getChild(file.getName()); } if (fileStore != null) { input = new FileStoreEditorInput(fileStore); } if (input != null) { return input; } // Try a pathEditorInput. no persistence // KE: This not part of the Eclipse IDE and requires // fable.framework.ui.texteditor, where it is implemented. This branch // should not be reached, and there seems to be no reason to use a // PathEditorInput. It originally did not have persistence but now does. // If eliminated, this plug-in does not need the dependency on // fable.framework.ui.texteditors. input = new PathEditorInput(iPath); return input; } /** * Checks if the file is in the workspace. If so, tries to refresh the * project. Fails silently if this cannot be done. * * @param fileName * The name of the file. * @return If [apparently] successful or not */ public static boolean tryToRefreshProject(String fileName) { if (fileName == null) { return false; } Path iPath = new Path(fileName); IFile iFile = null; IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); if (root != null && iPath != null) { iFile = root.getFileForLocation(iPath); } if (iFile != null) { // Refresh the project if possible try { IProject project = iFile.getProject(); project.refreshLocal(IResource.DEPTH_INFINITE, new NullProgressMonitor()); } catch (Exception ex) { return false; } } else { return false; } return true; } /** * Checks if the file is in the workspace. If so tries to open an editor on * it. Fails silently if this cannot be done. * * @param fileName * The name of the file. * * @param editorID * The ID of the editor to open; e.g., * "org.eclipse.ui.DefaultTextEditor" * @return If [apparently] successful or not */ public static boolean tryToOpenWorkspaceFileEditor(String fileName, String editorID) { if (fileName == null) { return false; } Path iPath = new Path(fileName); IFile iFile = null; IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); if (root != null && iPath != null) { iFile = root.getFileForLocation(iPath); } if (iFile != null) { try { IWorkbenchWindow window = PlatformUI.getWorkbench() .getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage(); IFileEditorInput newInput = new FileEditorInput(iFile); page.openEditor(newInput, editorID); } catch (Exception ex) { return false; } } else { return false; } return true; } /** * Tries to open an editor on the given external file. Fails silently if * this cannot be done. * * @param fileName * External file name. * @return If [apparently] successful or not */ public static boolean tryToOpenExternalFileEditor(String fileName) { if (fileName == null) { return false; } File file = new File(fileName); if (!file.exists() || !file.isFile()) { return false; } try { IFileStore fileStore = EFS.getLocalFileSystem().getStore( file.toURI()); IWorkbenchPage page = PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getActivePage(); IDE.openEditorOnFileStore(page, fileStore); } catch (Exception ex) { return false; } return true; } }