diff options
author | Dirk Fauth | 2013-05-17 13:31:00 +0000 |
---|---|---|
committer | Tom Schindl | 2013-05-17 13:31:00 +0000 |
commit | d2037ceadfa7b70e30d1540146a1c0a082f8de48 (patch) | |
tree | 576cce99f675498ed3a31f85693ded0daae52b99 | |
parent | 8973e881a16149b97efea12df3b00c32ff622d54 (diff) | |
download | org.eclipse.e4.tools-d2037ceadfa7b70e30d1540146a1c0a082f8de48.tar.gz org.eclipse.e4.tools-d2037ceadfa7b70e30d1540146a1c0a082f8de48.tar.xz org.eclipse.e4.tools-d2037ceadfa7b70e30d1540146a1c0a082f8de48.zip |
Bug 405936 - Update ProjectOSGiTranslationProvider to use the new
message extensions
4 files changed, 233 insertions, 90 deletions
diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/common/component/AbstractComponentEditor.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/common/component/AbstractComponentEditor.java index 191b2ad6..830dde39 100644 --- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/common/component/AbstractComponentEditor.java +++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/common/component/AbstractComponentEditor.java @@ -13,7 +13,6 @@ package org.eclipse.e4.tools.emf.ui.common.component; import java.util.Collections; import java.util.List; import javax.inject.Inject; -import javax.inject.Named; import org.eclipse.core.databinding.observable.list.IObservableList; import org.eclipse.core.databinding.observable.value.WritableValue; import org.eclipse.e4.core.di.annotations.Optional; @@ -26,7 +25,7 @@ import org.eclipse.e4.tools.emf.ui.internal.common.properties.ProjectOSGiTransla import org.eclipse.e4.tools.services.IClipboardService.Handler; import org.eclipse.e4.tools.services.IResourcePool; import org.eclipse.e4.tools.services.Translation; -import org.eclipse.e4.tools.services.impl.AbstractTranslationProvider; +import org.eclipse.e4.tools.services.impl.ResourceBundleTranslationProvider; import org.eclipse.e4.ui.model.application.MApplicationElement; import org.eclipse.e4.ui.model.application.ui.MUILabel; import org.eclipse.emf.databinding.FeaturePath; @@ -74,10 +73,6 @@ public abstract class AbstractComponentEditor { @Optional private ProjectOSGiTranslationProvider translationProvider; - @Inject - @Named(TranslationService.LOCALE) - private String locale; - private Composite editorControl; public EditingDomain getEditingDomain() { @@ -134,9 +129,9 @@ public abstract class AbstractComponentEditor { } /** - * Translates an input <code>string</code> using the current - * {@link AbstractTranslationProvider} and <code>locale</code> from the - * {@link TranslationService}. + * Translates an input <code>String</code> using the current + * {@link ResourceBundleTranslationProvider} and <code>locale</code> from + * the {@link TranslationService}. * * @param string * the string to translate, may not be null. @@ -144,7 +139,7 @@ public abstract class AbstractComponentEditor { * translated. */ public String translate(String string) { - return ControlFactory.tr(translationProvider, locale, string); + return ControlFactory.tr(translationProvider, string); } /** @@ -157,7 +152,7 @@ public abstract class AbstractComponentEditor { } protected String getLocalizedLabel(MUILabel element) { - return ControlFactory.getLocalizedLabel(translationProvider, element, locale); + return ControlFactory.getLocalizedLabel(translationProvider, element); } private boolean isFocusChild(Control control) { diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java index cd285a87..35b417a1 100644 --- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java +++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/ModelEditor.java @@ -45,6 +45,7 @@ import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.core.di.annotations.Optional; import org.eclipse.e4.core.di.extensions.Preference; import org.eclipse.e4.core.services.contributions.IContributionFactory; +import org.eclipse.e4.core.services.translation.TranslationService; import org.eclipse.e4.tools.emf.ui.common.EStackLayout; import org.eclipse.e4.tools.emf.ui.common.IContributionClassCreator; import org.eclipse.e4.tools.emf.ui.common.IEditorDescriptor; @@ -328,10 +329,10 @@ public class ModelEditor { this.context.set(ModelEditor.class, this); this.obsManager = new ObservablesManager(); if (project != null) { - ProjectOSGiTranslationProvider translationProvider = new ProjectOSGiTranslationProvider(project) { + ProjectOSGiTranslationProvider translationProvider = new ProjectOSGiTranslationProvider(project, (String) this.context.get(TranslationService.LOCALE)) { @Override - protected void clearCache() { - super.clearCache(); + protected void updateResourceBundle() { + super.updateResourceBundle(); viewer.getControl().getDisplay().asyncExec(new Runnable() { public void run() { diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ControlFactory.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ControlFactory.java index 905fa66c..fd76e8b3 100644 --- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ControlFactory.java +++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/component/ControlFactory.java @@ -814,11 +814,11 @@ public class ControlFactory { } - public static String getLocalizedLabel(ProjectOSGiTranslationProvider translationProvider, MUILabel element, String locale) { - return getLocalizedValue(translationProvider, (MApplicationElement) element, UiPackageImpl.Literals.UI_LABEL__LABEL, UiPackageImpl.Literals.UI_LABEL___GET_LOCALIZED_LABEL, locale); + public static String getLocalizedLabel(ProjectOSGiTranslationProvider translationProvider, MUILabel element) { + return getLocalizedValue(translationProvider, (MApplicationElement) element, UiPackageImpl.Literals.UI_LABEL__LABEL, UiPackageImpl.Literals.UI_LABEL___GET_LOCALIZED_LABEL); } - public static String getLocalizedValue(ProjectOSGiTranslationProvider translationProvider, MApplicationElement element, EStructuralFeature feature, EOperation operation, String locale) { + public static String getLocalizedValue(ProjectOSGiTranslationProvider translationProvider, MApplicationElement element, EStructuralFeature feature, EOperation operation) { EObject eo = (EObject) element; if (translationProvider == null) { try { @@ -834,16 +834,16 @@ public class ControlFactory { String value = (String) eo.eGet(feature); if (value != null && value.trim().length() > 0) { - return tr(translationProvider, locale, value); + return tr(translationProvider, value); } return null; } - public static String tr(ProjectOSGiTranslationProvider translationProvider, String locale, String label) { + public static String tr(ProjectOSGiTranslationProvider translationProvider, String label) { if (label.startsWith("%") && translationProvider != null) { //$NON-NLS-1$ String key = label.substring(1); - String translation = translationProvider.translate(locale, key); + String translation = translationProvider.translate(key); return translation == key ? label : translation; } return label; diff --git a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ProjectOSGiTranslationProvider.java b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ProjectOSGiTranslationProvider.java index 436711cd..016d28ba 100644 --- a/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ProjectOSGiTranslationProvider.java +++ b/bundles/org.eclipse.e4.tools.emf.ui/src/org/eclipse/e4/tools/emf/ui/internal/common/properties/ProjectOSGiTranslationProvider.java @@ -1,21 +1,19 @@ -/******************************************************************************* - * Copyright (c) 2010 BestSolution.at and others. - * 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: - * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation - ******************************************************************************/ package org.eclipse.e4.tools.emf.ui.internal.common.properties; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.ArrayList; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; import java.util.List; +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; +import java.util.ResourceBundle.Control; +import javax.inject.Inject; +import javax.inject.Named; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResourceChangeEvent; @@ -24,18 +22,46 @@ import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.runtime.CoreException; -import org.eclipse.e4.tools.services.impl.AbstractTranslationProvider; +import org.eclipse.e4.core.di.annotations.Optional; +import org.eclipse.e4.core.services.translation.TranslationService; +import org.eclipse.e4.tools.services.impl.ResourceBundleHelper; +import org.eclipse.e4.tools.services.impl.ResourceBundleTranslationProvider; +import org.osgi.framework.Constants; -public abstract class ProjectOSGiTranslationProvider extends AbstractTranslationProvider { +public class ProjectOSGiTranslationProvider extends ResourceBundleTranslationProvider { + + public static final String META_INF_DIRECTORY_NAME = "META-INF"; //$NON-NLS-1$ + public static final String MANIFEST_DEFAULT_PATH = "META-INF/MANIFEST.MF"; //$NON-NLS-1$ + + /** + * The {@link IProject} this translation provider is connected to + */ private IProject project; - private List<String> observedFiles = new ArrayList<String>(); - private IResourceChangeListener listener; + /** + * The manifest header identifying the base name of the bundle's + * localization entries. + */ private String basename; + /** + * The Locale to use for translations. + */ + private Locale locale; + + /** + * @param project + * The {@link IProject} this translation provider should be + * connected to. + * @param locale + * The initial {@link Locale} for which this translation provider + * should be created. + */ + public ProjectOSGiTranslationProvider(IProject project, String locale) { + // create the translation provider with no initial ResourceBundle as we + // need to calculate it first + super(null); - public ProjectOSGiTranslationProvider(IProject project) { - super(); this.project = project; - this.listener = new IResourceChangeListener() { + this.project.getWorkspace().addResourceChangeListener(new IResourceChangeListener() { public void resourceChanged(IResourceChangeEvent event) { if (event.getType() == IResourceChangeEvent.POST_CHANGE) { @@ -52,59 +78,92 @@ public abstract class ProjectOSGiTranslationProvider extends AbstractTranslation } } } - }; - this.project.getWorkspace().addResourceChangeListener(listener); - IFile f = this.project.getFile("META-INF/MANIFEST.MF"); //$NON-NLS-1$ + }); + setLocale(locale, false); + + IFile f = this.project.getFile(MANIFEST_DEFAULT_PATH); if (f.exists()) { handleManifestChange(f); } else { - basename = "OSGI-INF/l10n/bundle"; //$NON-NLS-1$ + basename = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; } } - boolean visit(IResourceDelta delta) throws CoreException { + @Inject + void setLocale(@Named(TranslationService.LOCALE) String locale, @Optional Boolean performUpdate) { + try { + this.locale = locale == null ? Locale.getDefault() : ResourceBundleHelper.toLocale(locale); + } catch (Exception e) { + this.locale = Locale.getDefault(); + } + + if (performUpdate == null || performUpdate) + updateResourceBundle(); + } + + /** + * + * @param delta + * The resource delta that represents the changes in the state of + * a resource tree between two discrete points in time. + * @return <code>true</code> if the resource delta's children should be + * visited; <code>false</code> if they should be skipped. + */ + boolean visit(IResourceDelta delta) { if (delta.getResource() instanceof IWorkspaceRoot) { return true; - } else if (delta.getResource().equals(project)) { + } else if (delta.getResource().equals(this.project)) { return true; - } else if (delta.getResource().getProjectRelativePath().toString().equals("META-INF")) { //$NON-NLS-1$ + } else if (delta.getResource().getProjectRelativePath().toString().equals(META_INF_DIRECTORY_NAME)) { return true; - } else if (delta.getResource().getProjectRelativePath().toString().equals("META-INF/MANIFEST.MF")) { //$NON-NLS-1$ + } else if (delta.getResource().getProjectRelativePath().toString().equals(MANIFEST_DEFAULT_PATH)) { handleManifestChange((IFile) delta.getResource()); return false; - } - - for (String o : observedFiles) { - if (delta.getResource().getProjectRelativePath().toString().equals(o)) { - clearCache(); + } else if (delta.getResource() instanceof IFile) { + String filename = ((IFile) delta.getResource()).getName(); + // extract base bundle name out of local basename + String fileBaseName = this.basename.substring(this.basename.lastIndexOf("/") + 1, this.basename.length()); //$NON-NLS-1$ + if (filename.startsWith(fileBaseName)) { + updateResourceBundle(); return false; } + } - String[] p = o.split("/"); //$NON-NLS-1$ - int i = 0; - String path = ""; //$NON-NLS-1$ - do { - path += p[i]; - if (delta.getResource().getProjectRelativePath().toString().equals(path)) { - return true; - } - path += "/"; //$NON-NLS-1$ - } while (++i < p.length); + if (delta.getResource().getProjectRelativePath().toString().equals(this.basename)) { + updateResourceBundle(); + return false; } + String[] p = this.basename.split("/"); //$NON-NLS-1$ + int i = 0; + String path = ""; //$NON-NLS-1$ + do { + path += p[i]; + if (delta.getResource().getProjectRelativePath().toString().equals(path)) { + return true; + } + path += "/"; //$NON-NLS-1$ + } while (++i < p.length); + return false; } + /** + * Will check if the manifest header identifying the base name of the + * bundle's localization entries has changed and if so it will update the + * underlying {@link ResourceBundle} and clear the caches. + * + * @param file + * The reference to the manifest file of the current project. + */ private void handleManifestChange(IFile file) { try { String newValue = extractBasenameFromManifest(file); if (!newValue.equals(basename)) { + basename = newValue; if (basename != null) { - basename = newValue; - clearCache(); - } else { - basename = newValue; + updateResourceBundle(); } } @@ -117,14 +176,29 @@ public abstract class ProjectOSGiTranslationProvider extends AbstractTranslation } } + /** + * Extracts the manifest header identifying the base name of the bundle's + * localization entries. + * + * @param file + * The reference to the manifest file of the current project. + * @return The manifest header identifying the base name of the bundle's + * localization entries. + * @throws CoreException + * If loading the contents of the given {@link IFile} fails + * @throws IOException + * If reading out of the given file fails. + * + * @see IFile#getContents() + */ public static String extractBasenameFromManifest(IFile file) throws CoreException, IOException { InputStream in = file.getContents(); BufferedReader r = new BufferedReader(new InputStreamReader(in)); String line; - String newValue = "OSGI-INF/l10n/bundle"; //$NON-NLS-1$ + String newValue = Constants.BUNDLE_LOCALIZATION_DEFAULT_BASENAME; while ((line = r.readLine()) != null) { - if (line.startsWith("Bundle-Localization:")) { //$NON-NLS-1$ - newValue = line.substring("Bundle-Localization:".length()).trim(); //$NON-NLS-1$ + if (line.startsWith(Constants.BUNDLE_LOCALIZATION)) { + newValue = line.substring(Constants.BUNDLE_LOCALIZATION.length() + 1).trim(); break; } } @@ -133,33 +207,106 @@ public abstract class ProjectOSGiTranslationProvider extends AbstractTranslation return newValue; } - @Override - protected InputStream getResourceAsStream(String name) { - IFile f = project.getFile(name); - observedFiles.add(name); - try { - if (f.exists()) { - return f.getContents(); + /** + * Reloads the underlying ResourceBundle. + */ + protected void updateResourceBundle() { + setResourceBundle(ResourceBundleHelper.getEquinoxResourceBundle(this.basename, this.locale, new ProjectResourceBundleControl(true), new ProjectResourceBundleControl(false))); + } + + /** + * Specialization of {@link Control} which loads the {@link ResourceBundle} + * by using file structures of a project instead of using a classloader. + * + * @author Dirk Fauth + */ + class ProjectResourceBundleControl extends ResourceBundle.Control { + + /** + * Flag to determine whether the default locale should be used as + * fallback locale in case there is no {@link ResourceBundle} found for + * the specified locale. + */ + private final boolean useFallback; + + /** + * @param useFallback + * <code>true</code> if the default locale should be used as + * fallback locale in the search path or <code>false</code> + * if there should be no fallback. + */ + ProjectResourceBundleControl(boolean useFallback) { + this.useFallback = useFallback; + } + + @Override + public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException { + + String bundleName = toBundleName(baseName, locale); + ResourceBundle bundle = null; + if (format.equals("java.properties")) { //$NON-NLS-1$ + final String resourceName = toResourceName(bundleName, "properties"); //$NON-NLS-1$ + InputStream stream = null; + try { + stream = AccessController.doPrivileged(new PrivilegedExceptionAction<InputStream>() { + public InputStream run() throws IOException { + return getResourceAsStream(resourceName); + } + }); + } catch (PrivilegedActionException e) { + throw (IOException) e.getException(); + } + if (stream != null) { + try { + bundle = new PropertyResourceBundle(stream); + } finally { + stream.close(); + } + } } else { - return null; + throw new IllegalArgumentException("unknown format: " + format); //$NON-NLS-1$ } - } catch (CoreException e) { - return null; + return bundle; } - } - @Override - protected void clearCache() { - super.clearCache(); - observedFiles.clear(); - } + /** + * Loads the properties file by using the {@link IProject} of the + * {@link ProjectOSGiTranslationProvider}. + * + * @param name + * @return The {@link InputStream} to the properties file to load + */ + protected InputStream getResourceAsStream(String name) { + IFile f = project.getFile(name); + try { + if (f.exists()) { + return f.getContents(); + } else { + return null; + } + } catch (CoreException e) { + return null; + } + } - @Override - protected String getBasename() { - return basename; - } + @Override + public List<String> getFormats(String baseName) { + return FORMAT_PROPERTIES; + } - public void dispose() { + @Override + public Locale getFallbackLocale(String baseName, Locale locale) { + return this.useFallback ? super.getFallbackLocale(baseName, locale) : null; + } + // this implementation simply doesn't cache the values in the + // ResourceBundle. If we recognize performance issues in the + // Application Model Editor because of this we should consider + // returning 0 here and overriding needsReload() with the information + // which bundle needs to be reloaded + @Override + public long getTimeToLive(String baseName, Locale locale) { + return TTL_DONT_CACHE; + } } -}
\ No newline at end of file +} |