/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.common.util;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.preference.IPersistentPreferenceStore;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.ISaveableFilter;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.ide.IDE;
import org.eclipse.ui.views.navigator.ResourceNavigator;
import org.eclipse.ui.views.navigator.ResourcePatternFilter;
import org.teiid.core.designer.util.CoreArgCheck;
import org.teiid.core.designer.util.FileUtils;
import org.teiid.designer.ui.common.UiConstants;
import org.teiid.designer.ui.common.UiPlugin;
import org.teiid.designer.ui.common.viewsupport.UiBusyIndicator;
/**
* @since 8.0
*/
public final class UiUtil implements UiConstants {
static IWorkbenchWindow currentWorkbenchWindow;
/**
* Programatically close a IEditorPart for the specified file, if one exists.
*
* @param file
* @param save true will request that the user to save or discard their changes. Should be set to true unless the modelFile is
* being deleted.
* @return true if the editor closed successfully or there was no editor open for the specified modelFile. Will return false
* if the user aborted the close.
*/
public static boolean close( final IFile modelFile,
final boolean save ) {
CloseEditorRunnable runnable = new CloseEditorRunnable(modelFile, save);
Display.getDefault().syncExec(runnable);
return runnable.didClose;
}
/**
* Creates an <code>Image</code> from the specified source <code>Image</code> by changing every occurrence of the old color to
* the new color.
*
* @param theSourceImage the image used to create the new image
* @param theOldColor the color being changed
* @param theNewColor the new color
* @return the new image
*/
public static Image createImage( final Image theSourceImage,
final Color theOldColor,
final Color theNewColor ) {
CoreArgCheck.isNotNull(theSourceImage);
CoreArgCheck.isNotNull(theOldColor);
CoreArgCheck.isNotNull(theNewColor);
ImageData imageData = (ImageData)theSourceImage.getImageData().clone();
PaletteData palette = imageData.palette;
if (palette.isDirect) {
// direct palette. colors are mapped into the pixel value
for (int y = 0; y < imageData.height; y++) {
for (int x = 0; x < imageData.width; x++) {
int value = imageData.getPixel(x, y);
if (palette.getRGB(value).equals(theOldColor.getRGB())) {
imageData.setPixel(x, y, palette.getPixel(theNewColor.getRGB()));
}
}
}
} else {
// indexed palette. colors have an index so swap out old for new.
for (int i = 0; i < palette.colors.length; i++) {
if (palette.colors[i].equals(theOldColor.getRGB())) {
palette.colors[i] = theNewColor.getRGB();
break;
}
}
}
return new Image(null, imageData);
}
/**
* Converts the severity of the specified <code>IStatus</code> to the message type used by
* {@link org.eclipse.jface.dialogs.TitleAreaDialog}s.
*
* @param theStatus the status whose severity is being converted
* @return the message type
* @since 4.3
* @see IMessageProvider
*/
public static int getDialogMessageType( IStatus theStatus ) {
int result = IMessageProvider.NONE;
switch (theStatus.getSeverity()) {
case IStatus.ERROR: {
result = IMessageProvider.ERROR;
break;
}
case IStatus.OK: {
result = IMessageProvider.NONE;
break;
}
case IStatus.INFO: {
result = IMessageProvider.INFORMATION;
break;
}
case IStatus.WARNING: {
result = IMessageProvider.WARNING;
break;
}
default: {
result = IMessageProvider.ERROR;
break;
}
}
return result;
}
/**
* @param file
* @return collection of editors that have the given file as input
*/
public static Collection<IEditorPart> getEditorsForFile( IFile file) {
List<IEditorPart> results = new ArrayList<IEditorPart>();
if (file == null)
return Collections.emptyList();
IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null)
return Collections.emptyList();
IWorkbenchWindow[] workbenchWindows = workbench.getWorkbenchWindows();
if (workbenchWindows == null || workbenchWindows.length == 0)
return Collections.emptyList();
for (IWorkbenchWindow window : workbenchWindows) {
IWorkbenchPage[] pages = window.getPages();
if (pages == null || pages.length == 0)
continue;
for (IWorkbenchPage page : pages) {
// look through the open editors and see if there is one available for this model file.
IEditorReference[] editors = page.getEditorReferences();
if (editors == null || editors.length == 0)
continue;
for (IEditorReference editorReference: editors) {
IEditorPart editor = editorReference.getEditor(false);
if (editor == null)
continue;
IEditorInput input = editor.getEditorInput();
if (input instanceof IFileEditorInput) {
if (file.equals(((IFileEditorInput)input).getFile())) {
// found it;
results.add(editor);
break;
}
}
}
}
}
return results;
}
public static IEditorPart getEditorForFile( IFile file, boolean forceOpen ) {
IEditorPart result = null;
if (file == null)
return null;
IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null)
return null;
IWorkbenchWindow[] workbenchWindows = workbench.getWorkbenchWindows();
if (workbenchWindows == null || workbenchWindows.length == 0)
return null;
IWorkbenchPage firstPage = null;
for (IWorkbenchWindow window : workbenchWindows) {
if (result != null)
continue; // already found it!
IWorkbenchPage[] pages = window.getPages();
if (pages == null || pages.length == 0)
continue;
for (IWorkbenchPage page : pages) {
if (firstPage == null)
firstPage = page;
if (result != null)
continue; // already found it!
// look through the open editors and see if there is one available for this model file.
IEditorReference[] editors = page.getEditorReferences();
if (editors == null || editors.length == 0)
continue;
for (IEditorReference editorReference: editors) {
IEditorPart editor = editorReference.getEditor(false);
if (editor == null)
continue;
IEditorInput input = editor.getEditorInput();
if (input instanceof IFileEditorInput) {
if (file.equals(((IFileEditorInput)input).getFile())) {
// found it;
result = editor;
break;
}
}
}
}
}
if (result == null && firstPage != null && forceOpen) {
// there is no editor open for this object. Open one and hand it the double-click target.
try {
result = IDE.openEditor(firstPage, file);
} catch (PartInitException e) {
UiConstants.Util.log(e);
}
}
return result;
}
/**
* Obtains the identifier of the current perspective.
*
* @return the ID of the current perspective or <code>null</code> if no perspective open or called outside the UI thread
*/
public static String getPerspectiveId() {
IWorkbenchPage page = getWorkbenchPage();
// could happen if not in UI thread
if (page == null) return null;
IPerspectiveDescriptor descriptor = page.getPerspective();
// no perspectives open
if (descriptor == null) return null;
// return the perspective ID
return descriptor.getId();
}
/**
* Obtains the {@link ResourcePatternFilter} from the specified Resource Navigator view. If that view is not a
* {@link ResourceNavigator} or if the view is not showing a default filter is constructed.
*
* @return the filter (never <code>null</code>)
* @throws IllegalArgumentException if the input parameter is <code>null</code> or empty
* @since 5.0.2
*/
public static ViewerFilter getResourceFilter( String theResourceNavigatorViewId ) {
CoreArgCheck.isNotEmpty(theResourceNavigatorViewId);
ViewerFilter result = null;
IViewPart view = UiUtil.getViewPart(theResourceNavigatorViewId);
if ((view == null) || (!(view instanceof ResourceNavigator))) {
// just use the default resource filter
result = new ResourcePatternFilter();
} else {
// get the filter from the view
result = ((ResourceNavigator)view).getPatternFilter();
}
return result;
}
/**
* Obtains the appropriate <code>Image</code> for the specified <code>IStatus</code>.
*
* @param theStatus the status whose image is being requested
* @return the image
* @since 4.3
*/
public static Image getStatusImage( IStatus theStatus ) {
Image result = null;
int severity = theStatus.getSeverity();
switch (severity) {
case IStatus.ERROR: {
result = UiPlugin.getDefault().getImage(Images.TASK_ERROR);
break;
}
case IStatus.WARNING: {
result = UiPlugin.getDefault().getImage(Images.TASK_WARNING);
break;
}
case IStatus.INFO: {
result = UiPlugin.getDefault().getImage(Images.TASK_INFO);
break;
}
default: {
break;
}
}
return result;
}
/**
* @return The current selection within the active part; never null.
* @since 4.0
*/
public static IStructuredSelection getStructuredSelection() {
final ISelection selection = getWorkbenchWindowOnlyIfUiThread().getSelectionService().getSelection();
return (selection instanceof IStructuredSelection ? (IStructuredSelection)selection : StructuredSelection.EMPTY);
}
/**
* Returns the operating system color associated with the specified system color ID defined in the {@link SWT}class.
*
* @param id The system color ID defined in the {@link SWT}class.
* @return The operating system color.
* @since 4.0
*/
public static Color getSystemColor( final int id ) {
return Display.getDefault().getSystemColor(id);
}
/**
* @return The workbench.
* @since 4.0
*/
public static IWorkbench getWorkbench() {
return PlatformUI.getWorkbench();
}
/**
* @return The active workbench page.
* @since 4.0
*/
public static IWorkbenchPage getWorkbenchPage() {
IWorkbenchWindow window = getWorkbenchWindowOnlyIfUiThread();
return (window == null) ? null : window.getActivePage();
}
/**
* Obtains the {@link IViewPart} with the specified identifier.
*
* @param theViewId the identifier of the view part being requested
* @return the view part or <code>null</code> if not open, not found, or if there is no active workbench page
* @throws AssertionError if <code>theViewId</code> is <code>null</code>
* @since 4.2
*/
public static IViewPart getViewPart( String theViewId ) {
CoreArgCheck.isNotNull(theViewId);
IViewPart result = null;
IWorkbenchPage page = getWorkbenchPage();
if (page != null) {
result = page.findView(theViewId);
}
return result;
}
/**
* Obtains the <code>Shell</code> of the active workbench window.
*
* @return the <code>Shell</code>
*/
public static Shell getWorkbenchShellOnlyIfUiThread() {
return getWorkbenchWindowOnlyIfUiThread().getShell();
}
/**
* @return The active workbench window.
* @since 4.0
*/
public static IWorkbenchWindow getWorkbenchWindow() {
UiUtil.runInSwtThread(new Runnable() {
/**
* {@inheritDoc}
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
currentWorkbenchWindow = getWorkbench().getActiveWorkbenchWindow();
}
}, true);
IWorkbenchWindow window = currentWorkbenchWindow;
currentWorkbenchWindow = null;
return window;
}
/**
* @return The active workbench window.
* @since 4.0
*/
public static IWorkbenchWindow getWorkbenchWindowOnlyIfUiThread() {
IWorkbenchWindow activeWorkbenchWindow = getWorkbench().getActiveWorkbenchWindow();
if (activeWorkbenchWindow == null) {
throw new RuntimeException("Active workbench window being requested but is not available. This is most certainly a programming bug.");
}
return activeWorkbenchWindow;
}
/**
* Sets focus to the perspective with the specified ID. The perspective will be opened if not already open.
*
* @param perspectiveId the ID of the perspective to open
*/
public static void openPerspective( String perspectiveId ) {
IWorkbench workbench = getWorkbench();
IWorkbenchWindow window = getWorkbenchWindow();
try {
workbench.showPerspective(perspectiveId, window);
} catch (Exception theException) {
Util.log(theException);
}
}
/**
* Opens a system editor with the specified file system resource.
*
* @param theFile the file being opened in a system editor
* @return <code>true</code>if editor successfully opened; <code>false</code> otherwise.
* @since 4.2
*/
public static boolean openSystemEditor( final File theFile ) {
return openSystemEditor(theFile.getAbsolutePath());
}
/**
* Opens a system editor with the specified workspace file.
*
* @param theFile the file being opened in a system editor
* @return <code>true</code>if editor successfully opened; <code>false</code> otherwise.
* @since 4.2
*/
public static boolean openSystemEditor( final IFile theFile ) {
return openSystemEditor(theFile.getLocation().toOSString());
}
/**
* Opens a system editor with the specified file name (full OS absolute path included).
*
* @param theFileName the file being opened in a system editor
* @return <code>true</code>if editor successfully opened; <code>false</code> otherwise.
* @since 4.2
*/
private static boolean openSystemEditor( final String theFileName ) {
final boolean result[] = {false};
UiBusyIndicator.showWhile(Display.getDefault(), new Runnable() {
/**
* {@inheritDoc}
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
if (Program.findProgram(FileUtils.getExtension(theFileName)) != null) {
try {
// Program.launch(String) the first time it is called with a file having an extension
// that does not have an OS association returns false. It returns true from then on.
// this seems like a bug. the workaround was to first call Program.findProgram(String) which
// always returns null if no association exists.
result[0] = Program.launch(theFileName);
} catch (Throwable theException) {
theException.printStackTrace();
result[0] = false;
}
}
}
});
return result[0];
}
/**
* @param operation The operation to be executed in the SWT thread.
* @param asynchronous True if the operation should be run asynchronously, meaning the calling thread will not be blocked.
* @since 4.1
*/
public static void runInSwtThread( final Runnable operation,
final boolean asynchronous ) {
Display display = (Display.getCurrent() == null ? Display.getDefault() : Display.getCurrent());
if (Thread.currentThread() != display.getThread()) {
if (asynchronous) {
display.asyncExec(operation);
} else {
display.syncExec(operation);
}
} else {
operation.run();
}
}
/**
* Saves the list values to the specified <code>IDialogSettings</code>. If the number of values exceeds the limit, values at
* the front of the list are deleted.
*
* @param theSettings the settings being saved
* @param theId the settings identifier being saved
* @param theValues the values being saved
* @param theLimit the maximum number of values saved
* @since 4.2
*/
public static void save( IDialogSettings theSettings,
String theId,
List theValues,
int theLimit ) {
String[] values = new String[0];
if ((theValues != null) && !theValues.isEmpty()) {
int size = theValues.size();
int j = 0;
if ((theLimit > 0) && (theValues.size() > theLimit)) {
j = (size - theLimit);
values = new String[theLimit];
} else {
values = new String[theValues.size()];
}
for (int i = 0; i < values.length; i++) {
values[i] = theValues.get(j++).toString();
}
}
theSettings.put(theId, values);
}
public static void savePreferences( IPreferenceStore store ) {
if (store.needsSaving() && store instanceof IPersistentPreferenceStore) {
try {
((IPersistentPreferenceStore)store).save();
} catch (IOException err) {
WidgetUtil.showError(err);
}
}
}
/**
* Saves all dirty editors in workspace. If <code>confirm</code> flag is <code>true</code>, a dialog showing all dirty editors
* is presented to the user. Assumes Eclipse workbench is running.
*
* @param shellProvider the shell provide (can be <code>null</code>)
* @param filter a filter that can identify editors that must be saved (can be <code>null</code> if all files must be saved)
* @param confirm <code>true</code> if the user should be asked to confirm saving all dirty editors
* @return <code>true</code> if all applicable dirty editors have been saved
*/
public static boolean saveDirtyEditors( IShellProvider shellProvider,
ISaveableFilter filter,
boolean confirm ) {
IWorkbench workbench = UiPlugin.getDefault().getWorkbench();
if (shellProvider == null) {
shellProvider = workbench.getActiveWorkbenchWindow();
}
ProgressMonitorDialog dialog = new ProgressMonitorDialog(shellProvider.getShell());
// if necessary display a save all open editors dialog
if (workbench.saveAll(shellProvider, dialog, filter, confirm)) {
IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
// save all dialog OK'd but could still have unsaved models if user unchecked them on dialog
if (window != null) {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
IEditorPart[] dirtyEditors = page.getDirtyEditors();
// if no filter than all editors have to have been saved
if (filter == null) {
return (dirtyEditors.length == 0);
}
// only editors selected by filter have to be saved
for (IEditorPart part : dirtyEditors) {
if (filter.select(null, new IWorkbenchPart[] { part })) {
return false;
}
}
return true;
}
}
}
return false;
}
/**
* Simple access to open any view given a registered view string id.
* @param viewId the id of the eclipse contributed view part
* @return successful or not
*/
public static boolean showView(String viewId) {
boolean success = false;
IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
if (activePage != null) {
try {
activePage.showView(viewId);
success = true;
} catch (PartInitException e) {
}
}
return success;
}
/**
* Updates the specified integer-based preference with the specified value if and only if:
* <ul>
* <li>It equals the specified default value and the current preference value is not zero (i.e., does not represent the
* default value). In this case, the value will be removed from the specified preference store.</li>
* <li>It does not equal the specified default value and does not equal the current preference value.</li>
* </ul>
*
* @param preference
* @param value
* @param defaultValue
* @param store
* @since 5.0.1
*/
public static void updateIntegerPreference( String preference,
int value,
int defaultValue,
IPreferenceStore store ) {
int val = store.getInt(preference);
if (value == defaultValue) {
if (val != 0) {
store.setToDefault(preference);
}
} else if (value != val) {
store.setValue(preference, value);
}
}
/**
* Prevents instantiation.
*
* @since 4.0
*/
private UiUtil() {
}
}
/**
* CloseEditorRunnable is a Runnable for closing a IEditorPart that can return a boolean for whether or not the editor actually
* closed.
*/
class CloseEditorRunnable implements Runnable {
private IFile modelFile;
private boolean save;
public boolean didClose = true;
public CloseEditorRunnable( IFile modelFile,
boolean save ) {
this.modelFile = modelFile;
this.save = save;
}
/**
* {@inheritDoc}
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
final IEditorPart editor = UiUtil.getEditorForFile(modelFile, false);
if (editor != null) {
didClose = UiPlugin.getDefault().getCurrentWorkbenchWindow().getActivePage().closeEditor(editor, save);
}
}
}