Java tutorial
/******************************************************************************* * Copyright (c) 2007 Pascal Essiembre. * 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 * * Contributors: * Pascal Essiembre - initial API and implementation ******************************************************************************/ package org.eclipse.babel.editor.util; import java.awt.ComponentOrientation; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.io.Reader; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Set; import org.eclipse.babel.editor.compat.SwtRapCompatibilitySWT; import org.eclipse.babel.editor.plugin.MessagesEditorPlugin; import org.eclipse.babel.editor.preferences.MsgEditorPreferences; import org.eclipse.babel.messages.Messages; import org.eclipse.babel.swt.ResourceManager; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.DecorationOverlayIcon; import org.eclipse.jface.viewers.IDecoration; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; /** * Utility methods related to application UI. * * @author Pascal Essiembre */ public final class UIUtils { /** Name of resource bundle image. */ public static final String IMAGE_RESOURCE_BUNDLE = "resourcebundle.gif"; //$NON-NLS-1$ /** Name of properties file image. */ public static final String IMAGE_PROPERTIES_FILE = "propertiesfile.gif"; //$NON-NLS-1$ /** Name of new properties file image. */ public static final String IMAGE_NEW_PROPERTIES_FILE = "newpropertiesfile.gif"; //$NON-NLS-1$ /** Name of hierarchical layout image. */ public static final String IMAGE_LAYOUT_HIERARCHICAL = "hierarchicalLayout.gif"; //$NON-NLS-1$ /** Name of flat layout image. */ public static final String IMAGE_LAYOUT_FLAT = "flatLayout.gif"; //$NON-NLS-1$ /** Name of add icon. */ public static final String IMAGE_ADD = "add.png"; //$NON-NLS-1$ /** Name of edit icon. */ public static final String IMAGE_RENAME = "rename.gif"; //$NON-NLS-1$ /** Name of "view left" icon. */ /** Name of refactoring icon. */ public static final String IMAGE_REFACTORING = "refactoring.png"; //$NON-NLS-1$ public static final String IMAGE_VIEW_LEFT = "viewLeft.gif"; //$NON-NLS-1$ /** Name of locale icon. */ public static final String IMAGE_LOCALE = "locale.gif"; //$NON-NLS-1$ /** Name of new locale icon. */ public static final String IMAGE_NEW_LOCALE = "newLocale.gif"; //$NON-NLS-1$ /** Name of expand all icon. */ public static final String IMAGE_EXPAND_ALL = "expandall.png"; //$NON-NLS-1$ /** Name of collapse all icon. */ public static final String IMAGE_COLLAPSE_ALL = "collapseall.png"; //$NON-NLS-1$ public static final String IMAGE_KEY = "keyDefault.png"; //$NON-NLS-1$ public static final String IMAGE_INCOMPLETE_ENTRIES = "incomplete.gif"; //$NON-NLS-1$ public static final String IMAGE_EMPTY = "empty.gif"; //$NON-NLS-1$ public static final String IMAGE_MISSING_TRANSLATION = "missing_translation.gif"; //$NON-NLS-1$ public static final String IMAGE_UNUSED_TRANSLATION = "unused_translation.png"; //$NON-NLS-1$ public static final String IMAGE_UNUSED_AND_MISSING_TRANSLATIONS = "unused_and_missing_translations.png"; //$NON-NLS-1$ public static final String IMAGE_WARNED_TRANSLATION = "warned_translation.png"; //$NON-NLS-1$ public static final String IMAGE_DUPLICATE = "duplicate.gif"; //$NON-NLS-1$ public static final String IMAGE_KEY_MISSING_TRANSLATION = "MissingTranslationImageKey"; public static final String IMAGE_KEY_UNUSED_TRANSLATION = "UnusedTranslationImageKey"; public static final String IMAGE_KEY_MISSING_UNUSED_TRANSLATION = "MissingUnusedTranslationImageKey"; public static final String IMAGE_KEY_DUPLICATE_ENTRY_TRANSLATION = "DuplicateEntryTranslationImageKey"; public static final String IMAGE_KEY_UNUSED_DUPLICATE_ENTRY_TRANSLATION = "UnusedDuplicateEntryTranslationImageKey"; public static final String IMAGE_WARNING = "warning.gif"; //$NON-NLS-1$ public static final String IMAGE_ERROR = "error_co.gif"; //$NON-NLS-1$ public static final String PDE_NATURE = "org.eclipse.pde.PluginNature"; //$NON-NLS-1$ public static final String JDT_JAVA_NATURE = "org.eclipse.jdt.core.javanature"; //$NON-NLS-1$ /** * The root locale used for the original properties file. This constant is * defined in java.util.Local starting with jdk6. */ public static final Locale ROOT_LOCALE = new Locale(""); //$NON-NLS-1$ /** * Sort the Locales alphabetically. Make sure the root Locale is first. * * @param locales */ public static final void sortLocales(Locale[] locales) { List<Locale> localesList = new ArrayList<Locale>(Arrays.asList(locales)); Comparator<Locale> comp = new Comparator<Locale>() { public int compare(Locale l1, Locale l2) { if (ROOT_LOCALE.equals(l1)) { return -1; } if (ROOT_LOCALE.equals(l2)) { return 1; } String name1 = ""; //$NON-NLS-1$ String name2 = ""; //$NON-NLS-1$ if (l1 != null) { name1 = l1.getDisplayName(); } if (l2 != null) { name2 = l2.getDisplayName(); } return name1.compareTo(name2); } }; Collections.sort(localesList, comp); for (int i = 0; i < locales.length; i++) { locales[i] = localesList.get(i); } } public static String wildcardToRegex(String wildcard) { StringBuffer s = new StringBuffer(wildcard.length()); s.append('^'); for (int i = 0, is = wildcard.length(); i < is; i++) { char c = wildcard.charAt(i); switch (c) { case '*': s.append(".*"); break; case '?': s.append("."); break; // escape special regexp-characters case '(': case ')': case '[': case ']': case '$': case '^': case '.': case '{': case '}': case '|': case '\\': s.append("\\"); s.append(c); break; default: s.append(c); break; } } s.append('$'); return (s.toString()); } /** * @param locale * @return true if the locale is selected by the local-filter defined in the * preferences * @see MsgEditorPreferences#getFilterLocalesStringMatcher() */ public static boolean isDisplayed(Locale locale) { if (ROOT_LOCALE.equals(locale) || locale == null) { return true; } String stringPatterns = MsgEditorPreferences.getFilterLocalesStringMatcher(); String[] wildcards = stringPatterns.split(","); if (wildcards == null || wildcards.length == 0) { return true; } String locStr = locale.toString(); for (int i = 0; i < wildcards.length; i++) { if (locStr.matches(wildcardToRegex(wildcards[i]))) { return true; } } return false; } /** * Reads the filter of locales in the preferences and apply it to filter the * passed locales. * * @param locales * @return The new collection of locales; removed the ones not selected by * the preferences. */ public static Locale[] filterLocales(Locale[] locales) { String stringPatterns = MsgEditorPreferences.getFilterLocalesStringMatcher(); Set<Locale> already = new HashSet<Locale>(); // first look for the root locale: ArrayList<Locale> result = new ArrayList<Locale>(); for (int j = 0; j < locales.length; j++) { Locale loc = locales[j]; if (ROOT_LOCALE.equals(loc) || loc == null) { already.add(loc); result.add(loc); break; } } // now go through each pattern until already indexed locales found all // locales or we run out of locales. String[] wildcards = stringPatterns.split(","); for (int pi = 0; pi < wildcards.length; pi++) { String pattern = wildcardToRegex(wildcards[pi]); for (int j = 0; j < locales.length; j++) { Locale loc = locales[j]; if (!already.contains(loc) && loc != null && loc.toString().matches(pattern)) { already.add(loc); result.add(loc); if (already.size() == locales.length) { for (int k = 0; k < locales.length; k++) { locales[k] = (Locale) result.get(k); } return locales; } } } } Locale[] filtered = new Locale[result.size()]; for (int k = 0; k < filtered.length; k++) { filtered[k] = result.get(k); } return filtered; } /** * Constructor. */ private UIUtils() { super(); } /** * Creates a font by altering the font associated with the given control and * applying the provided style (size is unaffected). * * @param control * control we base our font data on * @param style * style to apply to the new font * @return newly created font */ public static Font createFont(String fontKey, Control control, int style) { return createFont(fontKey, control, style, 0); } /** * Creates a font by altering the font associated with the given control and * applying the provided style and relative size. * * @param fontKey the font key for the caching system * @param control * control we base our font data on * @param style * style to apply to the new font * @param relSize * size to add or remove from the control size * @return newly created font */ public static Font createFont(String fontKey, Control control, int style, int relSize) { return ResourceManager.getWidgetFont(fontKey, control, style, relSize); } /** * Gets a system color. * * @param colorId * SWT constant * @return system color */ public static Color getSystemColor(int colorId) { return MessagesEditorPlugin.getDefault().getWorkbench().getDisplay().getSystemColor(colorId); } /** * Gets the approximate width required to display a given number of * characters in a control. * * @param control * the control on which to get width * @param numOfChars * the number of chars * @return width */ public static int getWidthInChars(Control control, int numOfChars) { GC gc = new GC(control); Point extent = gc.textExtent("W");//$NON-NLS-1$ gc.dispose(); return numOfChars * extent.x; } /** * Gets the approximate height required to display a given number of * characters in a control, assuming, they were laid out vertically. * * @param control * the control on which to get height * @param numOfChars * the number of chars * @return height */ public static int getHeightInChars(Control control, int numOfChars) { GC gc = new GC(control); Point extent = gc.textExtent("W");//$NON-NLS-1$ gc.dispose(); return numOfChars * extent.y; } /** * Shows an error dialog based on the supplied arguments. * * @param shell * the shell * @param exception * the core exception * @param msgKey * key to the plugin message text */ public static void showErrorDialog(Shell shell, CoreException exception, String message) { exception.printStackTrace(); ErrorDialog.openError(shell, message, exception.getLocalizedMessage(), exception.getStatus()); } /** * Shows an error dialog based on the supplied arguments. * * @param shell * the shell * @param exception * the core exception * @param msgKey * key to the plugin message text */ public static void showErrorDialog(Shell shell, Exception exception, String message) { exception.printStackTrace(); IStatus status = new Status(IStatus.ERROR, MessagesEditorPlugin.PLUGIN_ID, 0, message + " " //$NON-NLS-1$ + Messages.error_seeLogs, exception); ErrorDialog.openError(shell, message, exception.getLocalizedMessage(), status); } /** * Gets a locale, null-safe, display name. * * @param locale * locale to get display name * @return display name */ public static String getDisplayName(Locale locale) { if (locale == null || ROOT_LOCALE.equals(locale)) { return Messages.editor_i18nentry_rootlocale_label; } return locale.getDisplayName(); } /** * Gets an image descriptor. * * @param name * image name * @return image descriptor */ public static ImageDescriptor getImageDescriptor(String name) { return MessagesEditorPlugin.getImageDescriptor(name); } /** * Gets an image. * * @param imageName * image name * @return image */ public static Image getImage(String imageName) { ImageDescriptor desc = MessagesEditorPlugin.getImageDescriptor(imageName); if (desc == null) return null; else return ResourceManager.getImage(desc); } /** * @return Image for the icon that indicates a key with no issues */ public static Image getKeyImage() { Image image = getImage(UIUtils.IMAGE_KEY); return image; } /** * @return Image for the icon which indicates a key that has missing * translations */ public static Image getMissingTranslationImage() { Image result = ResourceManager.getImage(IMAGE_KEY_MISSING_TRANSLATION); if (result == null) { Image image = getImage(UIUtils.IMAGE_KEY); ImageDescriptor missing = ImageDescriptor.createFromImage(UIUtils.getImage(UIUtils.IMAGE_ERROR)); result = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage(); ResourceManager.addImage(IMAGE_KEY_MISSING_TRANSLATION, result); } return result; } /** * @return Image for the icon which indicates a key that is unused */ public static Image getUnusedTranslationsImage() { Image result = ResourceManager.getImage(IMAGE_KEY_UNUSED_TRANSLATION); if (result == null) { Image image = getImage(UIUtils.IMAGE_UNUSED_TRANSLATION); ImageDescriptor missing = ImageDescriptor.createFromImage(getImage(UIUtils.IMAGE_WARNING)); result = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage(); ResourceManager.addImage(IMAGE_KEY_UNUSED_TRANSLATION, result); } return result; } /** * @return Image for the icon which indicates a key that has missing * translations and is unused */ public static Image getMissingAndUnusedTranslationsImage() { Image result = ResourceManager.getImage(IMAGE_KEY_MISSING_UNUSED_TRANSLATION); if (result == null) { Image image = getImage(UIUtils.IMAGE_UNUSED_TRANSLATION); ImageDescriptor missing = ImageDescriptor.createFromImage(getImage(UIUtils.IMAGE_ERROR)); result = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage(); ResourceManager.addImage(IMAGE_KEY_MISSING_UNUSED_TRANSLATION, result); } return result; } /** * @return Image for the icon which indicates a key that has duplicate * entries */ public static Image getDuplicateEntryImage() { Image result = ResourceManager.getImage(IMAGE_KEY_DUPLICATE_ENTRY_TRANSLATION); if (result == null) { Image image = getImage(UIUtils.IMAGE_KEY); ImageDescriptor missing = ImageDescriptor.createFromImage(getImage(UIUtils.IMAGE_WARNING)); result = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage(); ResourceManager.addImage(IMAGE_KEY_DUPLICATE_ENTRY_TRANSLATION, result); } return result; } /** * @return Image for the icon which indicates a key that has duplicate * entries and is unused */ public static Image getDuplicateEntryAndUnusedTranslationsImage() { Image result = ResourceManager.getImage(IMAGE_KEY_UNUSED_DUPLICATE_ENTRY_TRANSLATION); if (result == null) { Image image = getImage(UIUtils.IMAGE_UNUSED_TRANSLATION); ImageDescriptor missing = ImageDescriptor.createFromImage(getImage(UIUtils.IMAGE_DUPLICATE)); result = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage(); ResourceManager.addImage(IMAGE_KEY_UNUSED_DUPLICATE_ENTRY_TRANSLATION, result); } return result; } /** * Gets the orientation suited for a given locale. * * @param locale * the locale * @return <code>SWT.RIGHT_TO_LEFT</code> or <code>SWT.LEFT_TO_RIGHT</code> */ public static int getOrientation(Locale locale) { if (locale != null) { ComponentOrientation orientation = ComponentOrientation.getOrientation(locale); if (orientation == ComponentOrientation.RIGHT_TO_LEFT) { return SwtRapCompatibilitySWT.RIGHT_TO_LEFT; } } return SWT.LEFT_TO_RIGHT; } /** * Parses manually the project descriptor looking for a nature. * <p> * Calling IProject.getNature(naturedId) throws exception if the Nature is * not defined in the currently executed platform. For example if looking * for a pde nature inside an eclipse-platform. * </p> * <p> * This method returns the result without that constraint. * </p> * * @param proj * The project to examine * @param nature * The nature to look for. * @return true if the nature is defined in that project. */ public static boolean hasNature(IProject proj, String nature) { IFile projDescr = proj.getFile(".project"); //$NON-NLS-1$ if (!projDescr.exists()) { return false;// a corrupted project } // <classpathentry kind="src" path="src"/> InputStream in = null; try { projDescr.refreshLocal(IResource.DEPTH_ZERO, null); in = projDescr.getContents(); // supposedly in utf-8. should not really matter for us Reader r = new InputStreamReader(in, "UTF-8"); LineNumberReader lnr = new LineNumberReader(r); String line = lnr.readLine(); while (line != null) { if (line.trim().equals("<nature>" + nature + "</nature>")) { lnr.close(); r.close(); return true; } line = lnr.readLine(); } lnr.close(); r.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (in != null) try { in.close(); } catch (IOException e) { } } return false; } }