[379083] Contributes babel-messages editor enhancements and bug fixes

= org.eclipse.babel.core: =
Introduced central object management system (core-class: RBManager). This
functionality was offered by TapiJIs' ResourceBundleManager
class, but due to this merge (Babel & TapiJI), I considered to move the
object management to the org.eclipse.babel.core plug-in. That plug-in
contains of the model and therefore
it's a good idea to place object management there too. To ensure loose
coupling, I defined interfaces, which are widley used by TapiJI.
Due to the merge of these two worlds, some other functionalities had to be
moved from one to another (mostly from TapiJI to Babel). One example is
the ConfigurationManager. This class has access to the preferences (defined in
TapiJI) via the babelConfiguration Xpt. Some factory classes had to be
introduced as well.
An example is the MessagesBundleGroupFactory class. It creates bundle
groups based on a PropertiesFileGroupStrategy, which is quite uncommon,
but in some cases of vital importance.
Also some Utility-classes had to be implemented.

= org.eclipse.babel.editor: =
Modifications were made due to huge changes in org.eclipse.babel.core
(writing Interfaces, ...). Also many bugs have been fixed or partly fixed
(only 222152) during the integration with TapiJI.
(see: Bugs: 222127, 222131, 222138, 222152, 222140, 226383, 226389,
226390). I also had to implement workarounds for special problems, see
class DirtyHack.

[222127] fix [222131] fix [222138] fix [222140] fix [226383] fix
[226389] fix

close 379083
diff --git a/org.eclipse.babel.core/META-INF/CVS/Entries b/org.eclipse.babel.core/META-INF/CVS/Entries
new file mode 100644
index 0000000..99183f4
--- /dev/null
+++ b/org.eclipse.babel.core/META-INF/CVS/Entries
@@ -0,0 +1 @@
+/MANIFEST.MF/1.5/Fri Aug 14 19:53:04 2009//
diff --git a/org.eclipse.babel.core/META-INF/CVS/Repository b/org.eclipse.babel.core/META-INF/CVS/Repository
new file mode 100644
index 0000000..060aa2a
--- /dev/null
+++ b/org.eclipse.babel.core/META-INF/CVS/Repository
@@ -0,0 +1 @@
+org.eclipse.babel/plugins/org.eclipse.babel.core/META-INF
diff --git a/org.eclipse.babel.core/META-INF/CVS/Root b/org.eclipse.babel.core/META-INF/CVS/Root
new file mode 100644
index 0000000..d58b082
--- /dev/null
+++ b/org.eclipse.babel.core/META-INF/CVS/Root
@@ -0,0 +1 @@
+:pserver:anonymous@dev.eclipse.org:/cvsroot/technology
diff --git a/org.eclipse.babel.core/META-INF/MANIFEST.MF b/org.eclipse.babel.core/META-INF/MANIFEST.MF
index ef390e4..2ed2b8d 100644
--- a/org.eclipse.babel.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.babel.core/META-INF/MANIFEST.MF
@@ -1,18 +1,31 @@
 Manifest-Version: 1.0
 Bundle-ManifestVersion: 2
 Bundle-Name: Babel Core Plug-in
-Bundle-SymbolicName: org.eclipse.babel.core
+Bundle-SymbolicName: org.eclipse.babel.core;singleton:=true
 Bundle-Version: 0.8.0.qualifier
-Export-Package: org.eclipse.babel.core.message,
- org.eclipse.babel.core.message.checks,
+Export-Package: org.eclipse.babel.core.configuration;uses:="org.eclipse.babel.core.message.resource.ser",
+ org.eclipse.babel.core.factory,
+ org.eclipse.babel.core.message,
+ org.eclipse.babel.core.message.checks;uses:="org.eclipse.babel.core.message.checks.proximity,org.eclipselabs.tapiji.translator.rbe.babel.bundle",
+ org.eclipse.babel.core.message.checks.internal,
  org.eclipse.babel.core.message.checks.proximity,
+ org.eclipse.babel.core.message.internal;
+  uses:="org.eclipse.babel.core.message.resource,
+   org.eclipse.babel.core.message.strategy,
+   org.eclipse.core.resources,
+   org.eclipselabs.tapiji.translator.rbe.babel.bundle",
+ org.eclipse.babel.core.message.manager;uses:="org.eclipse.core.resources,org.eclipselabs.tapiji.translator.rbe.babel.bundle",
  org.eclipse.babel.core.message.resource,
- org.eclipse.babel.core.message.resource.ser,
- org.eclipse.babel.core.message.strategy,
+ org.eclipse.babel.core.message.resource.internal;uses:="org.eclipse.babel.core.message,org.eclipse.babel.core.message.resource.ser,org.eclipse.core.resources",
+ org.eclipse.babel.core.message.resource.ser;uses:="org.eclipselabs.tapiji.translator.rbe.babel.bundle",
+ org.eclipse.babel.core.message.strategy;uses:="org.eclipse.babel.core.message.resource.ser,org.eclipse.babel.core.message,org.eclipse.core.resources",
  org.eclipse.babel.core.message.tree,
- org.eclipse.babel.core.message.tree.visitor,
- org.eclipse.babel.core.util
+ org.eclipse.babel.core.message.tree.internal,
+ org.eclipse.babel.core.message.tree.visitor;uses:="org.eclipse.babel.core.message,org.eclipselabs.tapiji.translator.rbe.babel.bundle",
+ org.eclipse.babel.core.util;uses:="org.eclipse.core.resources"
 Require-Bundle: org.eclipse.core.databinding,
  org.eclipse.core.resources,
- org.eclipse.core.runtime
-Bundle-RequiredExecutionEnvironment: J2SE-1.5
+ org.eclipse.core.runtime,
+ org.eclipse.jdt.core;bundle-version="3.6.2",
+ org.eclipse.pde.core;bundle-version="3.7.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
diff --git a/org.eclipse.babel.core/build.properties b/org.eclipse.babel.core/build.properties
index 8bb29ea..eabc8e4 100644
--- a/org.eclipse.babel.core/build.properties
+++ b/org.eclipse.babel.core/build.properties
@@ -2,7 +2,7 @@
 output.. = bin/
 bin.includes = META-INF/,\
                .,\
-               bin/
-src.includes = META-INF/,\
                bin/,\
+               plugin.xml
+src.includes = bin/,\
                src/
diff --git a/org.eclipse.babel.core/plugin.xml b/org.eclipse.babel.core/plugin.xml
new file mode 100644
index 0000000..0814425
--- /dev/null
+++ b/org.eclipse.babel.core/plugin.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+   <extension-point id="babelConfiguration" name="babelConfiguration.exsd" schema="schema/babelConfiguration.exsd"/>
+
+</plugin>
diff --git a/org.eclipse.babel.core/schema/babelConfiguration.exsd b/org.eclipse.babel.core/schema/babelConfiguration.exsd
new file mode 100644
index 0000000..1683ef6
--- /dev/null
+++ b/org.eclipse.babel.core/schema/babelConfiguration.exsd
@@ -0,0 +1,119 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.babel.core" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appinfo>
+         <meta.schema plugin="org.eclipse.babel.core" id="babelConfiguration" name="babelConfiguration"/>
+      </appinfo>
+      <documentation>
+         Xpt, which is implemented by TapiJI to provide access to TapiJIPreferences.
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appinfo>
+            <meta.element />
+         </appinfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="IConfiguration"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute translatable="true"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="IConfiguration">
+      <complexType>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appinfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.babel.core.configuration.IConfiguration"/>
+               </appinfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="since"/>
+      </appinfo>
+      <documentation>
+         [Enter the first release in which this extension point appears.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="examples"/>
+      </appinfo>
+      <documentation>
+         [Enter extension point usage example here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="apiinfo"/>
+      </appinfo>
+      <documentation>
+         [Enter API information here.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="implementation"/>
+      </appinfo>
+      <documentation>
+         [Enter information about supplied implementation of this extension point.]
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appinfo>
+         <meta.section type="copyright"/>
+      </appinfo>
+      <documentation>
+         /*******************************************************************************
+ * Copyright (c) 2012 TapiJI.
+ * 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:
+ *     Alexej Strelzow - creation
+ ******************************************************************************/
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/ConfigurationManager.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/ConfigurationManager.java
new file mode 100644
index 0000000..d31226e
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/ConfigurationManager.java
@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.babel.core.configuration;
+
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.resource.ser.IPropertiesDeserializerConfig;
+import org.eclipse.babel.core.message.resource.ser.IPropertiesSerializerConfig;
+import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
+import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Singelton, which provides information regarding the configuration of:
+ * <li>TapiJI Preference Page: interface is {@link IConfiguration}</li>
+ * <li>Serializing {@link MessagesBundleGroup} to property file</li>
+ * <li>Deserializing {@link MessagesBundleGroup} from property file</li>
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public class ConfigurationManager {
+
+	private static ConfigurationManager INSTANCE;
+	
+	private IConfiguration config;
+	
+	private IPropertiesSerializerConfig serializerConfig;
+	
+	private IPropertiesDeserializerConfig deserializerConfig;
+	
+	private ConfigurationManager() {
+		config = getConfig();
+	}
+	
+	private IConfiguration getConfig() {
+		
+		IExtensionPoint extp = Platform.getExtensionRegistry().getExtensionPoint(
+                "org.eclipse.babel.core" + ".babelConfiguration");
+        IConfigurationElement[] elements = extp.getConfigurationElements();
+        
+        if (elements.length != 0) {
+        	try {
+				return (IConfiguration) elements[0].createExecutableExtension("class");
+        	} catch (CoreException e) {
+				e.printStackTrace();
+			}
+        } 
+    	return null;
+	}
+
+	/**
+	 * @return The singleton instance
+	 */
+	public static ConfigurationManager getInstance() {
+		if (INSTANCE == null) {
+			INSTANCE = new ConfigurationManager();
+		}
+		return INSTANCE;
+	}
+	
+	/**
+	 * @return TapiJI configuration
+	 */
+	public IConfiguration getConfiguration() {
+		return this.config;
+	}
+
+	/**
+	 * @return Config needed for {@link PropertiesSerializer}
+	 */
+	public IPropertiesSerializerConfig getSerializerConfig() {
+		return serializerConfig;
+	}
+
+	/**
+	 * @param serializerConfig The config for serialization
+	 */
+	public void setSerializerConfig(IPropertiesSerializerConfig serializerConfig) {
+		this.serializerConfig = serializerConfig;
+	}
+
+	/**
+	 * @return Config needed for {@link PropertiesDeserializer}
+	 */
+	public IPropertiesDeserializerConfig getDeserializerConfig() {
+		return deserializerConfig;
+	}
+
+	/**
+	 * @param serializerConfig The config for deserialization
+	 */
+	public void setDeserializerConfig(
+			IPropertiesDeserializerConfig deserializerConfig) {
+		this.deserializerConfig = deserializerConfig;
+	}
+	
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/DirtyHack.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/DirtyHack.java
new file mode 100644
index 0000000..cc0de07
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/DirtyHack.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.babel.core.configuration;
+
+import org.eclipse.babel.core.message.internal.AbstractMessageModel;
+
+/**
+ * Contains following two <b>dirty</b> workaround flags:
+ * <li><b>fireEnabled:</b> deactivates {@link PropertyChangeEvent}-fire in {@link AbstractMessageModel}</li>
+ * <li><b>editorModificationEnabled:</b> prevents <code>EclipsePropertiesEditorResource#setText</code></li>
+ * <br><br>
+ * <b>We need to get rid of this somehow!!!!!!!!!</b>
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public final class DirtyHack {
+
+	private static boolean fireEnabled = true; // no property-fire calls in AbstractMessageModel
+	
+	private static boolean editorModificationEnabled = true; // no setText in EclipsePropertiesEditorResource
+												// set this, if you serialize!
+
+	public static boolean isFireEnabled() {
+		return fireEnabled;
+	}
+
+	public static void setFireEnabled(boolean fireEnabled) {
+		DirtyHack.fireEnabled = fireEnabled;
+	}
+
+	public static boolean isEditorModificationEnabled() {
+		return editorModificationEnabled;
+	}
+
+	public static void setEditorModificationEnabled(
+			boolean editorModificationEnabled) {
+		DirtyHack.editorModificationEnabled = editorModificationEnabled;
+	}
+	
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/IConfiguration.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/IConfiguration.java
new file mode 100644
index 0000000..b35d556
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/configuration/IConfiguration.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.babel.core.configuration;
+
+/**
+ * Interface to TapiJI preference page.
+ * 
+ * @author Alexej Strelzow
+ */
+public interface IConfiguration {
+
+	boolean getAuditSameValue();
+
+	boolean getAuditMissingValue();
+
+	boolean getAuditMissingLanguage();
+
+	boolean getAuditRb();
+
+	boolean getAuditResource();
+
+	String getNonRbPattern();
+
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/factory/MessageFactory.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/factory/MessageFactory.java
new file mode 100644
index 0000000..ade7c19
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/factory/MessageFactory.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.babel.core.factory;
+
+import java.util.Locale;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.internal.Message;
+
+/**
+ * Factory class for creating a {@link IMessage}
+ * 
+ * @author Alexej Strelzow
+ */
+public class MessageFactory {
+
+    static Logger logger = Logger.getLogger(MessageFactory.class.getSimpleName());
+    
+    /**
+     * @param key The key of the message
+     * @param locale The {@link Locale}
+     * @return An instance of {@link IMessage}
+     */
+    public static IMessage createMessage(String key, Locale locale) {
+        String l = locale == null ? "[default]" : locale.toString();
+        logger.log(Level.INFO, "createMessage, key: " + key + " locale: " + l);
+        
+        return new Message(key, locale);
+    }
+    
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/factory/MessagesBundleGroupFactory.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/factory/MessagesBundleGroupFactory.java
new file mode 100644
index 0000000..f9945e6
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/factory/MessagesBundleGroupFactory.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.babel.core.factory;
+
+import java.io.File;
+
+import org.eclipse.babel.core.configuration.ConfigurationManager;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.strategy.PropertiesFileGroupStrategy;
+import org.eclipse.core.resources.IResource;
+
+/**
+ * Factory class for creating a {@link MessagesBundleGroup} with a {@link PropertiesFileGroupStrategy}.
+ * This is in use when we work with TapiJI only and not with <code>EclipsePropertiesEditorResource</code>.
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public class MessagesBundleGroupFactory {
+	
+    public static IMessagesBundleGroup createBundleGroup(IResource resource) {
+    	
+            File ioFile = new File(resource.getRawLocation().toFile().getPath());
+            
+            return new MessagesBundleGroup(new PropertiesFileGroupStrategy(ioFile, 
+            		ConfigurationManager.getInstance().getSerializerConfig(), 
+            		ConfigurationManager.getInstance().getDeserializerConfig()));
+    }
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessage.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessage.java
new file mode 100644
index 0000000..85dae2e
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessage.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer, Alexej Strelzow.
+ * 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:
+ *     Martin Reiterer - initial API
+ *     Alexej Strelzow - extended API
+ ******************************************************************************/
+package org.eclipse.babel.core.message;
+
+import java.util.Locale;
+
+import org.eclipse.babel.core.message.internal.Message;
+
+/**
+ * Interface, implemented by {@link Message}. A message is an abstraction of a
+ * key-value pair, which can be found in resource bundles (1 row).
+ * <br><br>
+ * 
+ * @author Martin Reiterer, Alexej Strelzow
+ */
+public interface IMessage {
+
+    /**
+     * Gets the message key attribute.
+     * @return Returns the key.
+     */
+	String getKey();
+
+    /**
+     * Gets the message text.
+     * @return Returns the text.
+     */
+	String getValue();
+
+    /**
+     * Gets the message locale.
+     * @return Returns the locale
+     */
+	Locale getLocale();
+
+    /**
+     * Gets the comment associated with this message (<code>null</code> if
+     * no comments).
+     * @return Returns the comment.
+     */
+	String getComment();
+
+    /**
+     * Gets whether this message is active or not.
+     * @return <code>true</code> if this message is active.
+     */
+	boolean isActive();
+
+	/**
+	 * @return The toString representation
+	 */
+	String toString();
+
+    /**
+     * Sets whether the message is active or not.  An inactive message is
+     * one that we continue to keep track of, but will not be picked
+     * up by internationalization mechanism (e.g. <code>ResourceBundle</code>).
+     * Typically, those are commented (i.e. //) key/text pairs in a
+     * *.properties file.
+     * @param active The active to set.
+     */
+	void setActive(boolean active);
+
+    /**
+     * Sets the message comment.
+     * @param comment The comment to set.
+     */
+	void setComment(String comment);
+
+    /**
+     * Sets the actual message text.
+     * @param text The text to set.
+     */
+	void setText(String test);
+
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundle.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundle.java
new file mode 100644
index 0000000..ef843f5
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundle.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer, Alexej Strelzow.
+ * 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:
+ *     Martin Reiterer - initial API
+ *     Alexej Strelzow - extended API
+ ******************************************************************************/
+package org.eclipse.babel.core.message;
+
+import java.util.Collection;
+import java.util.Locale;
+
+import org.eclipse.babel.core.message.internal.MessageException;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
+import org.eclipse.babel.core.message.resource.IMessagesResource;
+
+/**
+ * Interface, implemented by {@link MessagesBundle}. A messages bundle is an abstraction of a
+ * resource bundle (the *.properties-file).
+ * <br><br>
+ * 
+ * @author Martin Reiterer, Alexej Strelzow
+ */
+public interface IMessagesBundle {
+
+    /**
+     * Called before this object will be discarded.
+     */
+	void dispose();
+
+    /**
+     * Renames a message key.
+     * @param sourceKey the message key to rename
+     * @param targetKey the new key for the message
+     * @throws MessageException if the target key already exists
+     */
+	void renameMessageKey(String sourceKey, String targetKey);
+
+    /**
+     * Removes a message from this messages bundle.
+     * @param messageKey the key of the message to remove
+     */
+	void removeMessage(String messageKey);
+
+    /**
+     * Duplicates a message.
+     * @param sourceKey the message key to duplicate
+     * @param targetKey the new message key
+     * @throws MessageException if the target key already exists
+     */
+	void duplicateMessage(String sourceKey, String targetKey);
+
+    /**
+     * Gets the locale for the messages bundle (<code>null</code> assumes
+     * the default system locale).
+     * @return Returns the locale.
+     */
+	Locale getLocale();
+
+    /**
+     * Gets all message keys making up this messages bundle.
+     * @return message keys
+     */
+	String[] getKeys();
+
+    /**
+     * Returns the value to the given key, if the key exists.
+     * @param key, the key of a message.
+     * @return The value to the given key.
+     */
+	String getValue(String key);
+
+    /**
+     * Obtains the set of <code>Message</code> objects in this bundle.
+     * @return a collection of <code>Message</code> objects in this bundle
+     */
+	Collection<IMessage> getMessages();
+
+    /**
+     * Gets a message.
+     * @param key a message key
+     * @return a message
+     */
+	IMessage getMessage(String key);
+
+    /**
+     * Adds an empty message.
+     * @param key the new message key
+     */
+	void addMessage(IMessage message);
+
+    /**
+     * Removes messages from this messages bundle.
+     * @param messageKeys the keys of the messages to remove
+     */
+	void removeMessages(String[] messageKeys);
+
+    /**
+     * Sets the comment for this messages bundle.
+     * @param comment The comment to set.
+     */
+	void setComment(String comment);
+
+    /**
+     * Gets the overall comment, or description, for this messages bundle..
+     * @return Returns the comment.
+     */
+	String getComment();
+
+    /**
+     * Gets the underlying messages resource implementation.
+     * @return
+     */
+	IMessagesResource getResource();
+
+    /**
+     * Removes a message from this messages bundle and adds it's parent key to bundle.
+     * E.g.: key = a.b.c gets deleted, a.b gets added with a default message
+     * @param messageKey the key of the message to remove
+     */
+	void removeMessageAddParentKey(String key);
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleGroup.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleGroup.java
new file mode 100644
index 0000000..5de5c0a
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleGroup.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer, Alexej Strelzow.
+ * 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:
+ *     Martin Reiterer - initial API
+ *     Alexej Strelzow - extended API
+ ******************************************************************************/
+package org.eclipse.babel.core.message;
+
+import java.util.Collection;
+import java.util.Locale;
+
+import org.eclipse.babel.core.message.internal.MessageException;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.strategy.PropertiesFileGroupStrategy;
+
+/**
+ * Interface, implemented by {@link MessagesBundleGroup}. A messages bundle
+ * group is an abstraction of a group of resource bundles. <br>
+ * <br>
+ * 
+ * @author Martin Reiterer, Alexej Strelzow
+ */
+public interface IMessagesBundleGroup {
+
+	/**
+	 * Returns a collection of all bundles in this group.
+	 * @return the bundles in this group
+	 */
+	Collection<IMessagesBundle> getMessagesBundles();
+
+	/**
+	 * Returns true if the supplied key is already existing in this group.
+	 * @param key The key that shall be tested.
+	 * @return true <=> The key is already existing.
+	 */
+	boolean containsKey(String key);
+
+	/**
+	 * Gets all messages associated with the given message key.
+	 * @param key a message key
+	 * @return messages
+	 */
+	IMessage[] getMessages(String key);
+
+    /**
+     * Gets the message matching given key and locale.
+     * @param locale The locale for which to retrieve the message
+     * @param key The key matching entry to retrieve the message
+     * @return a message
+     */
+	IMessage getMessage(String key, Locale locale);
+
+    /**
+     * Gets the messages bundle matching given locale.
+     * @param locale The locale of bundle to retreive
+     * @return a bundle
+     */
+	IMessagesBundle getMessagesBundle(Locale locale);
+
+    /**
+     * Removes messages matching the given key from all messages bundle.
+     * @param key The key of messages to remove
+     */
+	void removeMessages(String messageKey);
+
+    /**
+     * Is the given key found in this bundle group.
+     * @param key The key to find
+     * @return <code>true</code> if the key exists in this bundle group.
+     */
+	boolean isKey(String key);
+
+    /**
+     * Adds a messages bundle to this group.
+     * @param locale The locale of the bundle
+     * @param messagesBundle bundle to add
+     * @throws MessageException if a messages bundle for the same locale already exists.
+     */
+	void addMessagesBundle(Locale locale, IMessagesBundle messagesBundle);
+
+    /**
+     * Gets all keys from all messages bundles.
+     * @return all keys from all messages bundles
+     */
+	String[] getMessageKeys();
+
+    /**
+     * Adds an empty message to every messages bundle of this group with the
+     * given.
+     * @param key The message key
+     */
+	void addMessages(String key);
+
+    /**
+     * Gets the number of messages bundles in this group.
+     * @return the number of messages bundles in this group
+     */
+	int getMessagesBundleCount();
+
+    /**
+     * Gets this messages bundle group name. That is the name, which is used
+     * for the tab of the MultiPageEditorPart.
+     * @return bundle group name
+     */
+	String getName();
+
+	/**
+	 * Gets the unique id of the bundle group. That is usually: <directory>"."<default-filename>.
+	 * The default filename is without the suffix (e.g. _en, or _en_GB).
+	 * @return The unique identifier for the resource bundle group
+	 */
+	String getResourceBundleId();
+
+	/**
+	 * @return <code>true</code> if the bundle group has {@link PropertiesFileGroupStrategy} as strategy,
+	 * 	else <code>false</code>. This is the case, when only TapiJI edits the resource bundles and no
+	 *  have been opened.
+	 */
+	boolean hasPropertiesFileGroupStrategy();
+
+	/**
+	 * Whether the given key is found in this messages bundle group.
+	 * @param key The key to find
+	 * @return <code>true</code> if the key exists in this bundle group.
+	 */
+	public boolean isMessageKey(String key);
+
+	/**
+	 * Gets the name of the project, the resource bundle group is in.
+	 * @return The project name
+	 */
+	public String getProjectName();
+
+	/**
+	 * Removes the {@link IMessagesBundle} from the group.
+	 * @param messagesBundle The bundle to remove.
+	 */
+	public void removeMessagesBundle(IMessagesBundle messagesBundle);
+
+	/**
+	 * Called before this object will be discarded. Disposes the underlying
+	 * MessageBundles
+	 */
+	public void dispose();
+
+	/**
+	 * Removes messages matching the given key from all messages bundle and add
+	 * it's parent key to bundles.
+	 * 
+	 * @param key The key of messages to remove
+	 */
+	void removeMessagesAddParentKey(String key);
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/IMessagesResourceChangeListener.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesResourceChangeListener.java
similarity index 76%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/IMessagesResourceChangeListener.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesResourceChangeListener.java
index 2b93d54..70f8650 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/IMessagesResourceChangeListener.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesResourceChangeListener.java
@@ -8,17 +8,23 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.resource;
+
+package org.eclipse.babel.core.message;
+
+import org.eclipse.babel.core.message.resource.IMessagesResource;
 
 /**
  * Listener being notified when a {@link IMessagesResource} content changes.
+ * 
  * @author Pascal Essiembre
  */
 public interface IMessagesResourceChangeListener {
 
 	/**
 	 * Method called when the messages resource has changed.
-	 * @param resource the resource that changed
+	 * 
+	 * @param resource
+	 *            the resource that changed
 	 */
-    void resourceChanged(IMessagesResource resource);
+	void resourceChanged(IMessagesResource resource);
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleGroup.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleGroup.java
deleted file mode 100644
index b6048ad..0000000
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleGroup.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/*******************************************************************************
- * 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.core.message;
-
-import java.beans.PropertyChangeEvent;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-
-import org.eclipse.babel.core.message.resource.IMessagesResource;
-import org.eclipse.babel.core.message.strategy.IMessagesBundleGroupStrategy;
-import org.eclipse.babel.core.util.BabelUtils;
-
-/**
- * Grouping of all messages bundle of the same kind.
- * @author Pascal Essiembre (pascal@essiembre.com)
- */
-public class MessagesBundleGroup extends AbstractMessageModel {
-
-    private static final IMessagesBundleGroupListener[]
-            EMPTY_GROUP_LISTENERS = new IMessagesBundleGroupListener[] {};
-    private static final Message[] EMPTY_MESSAGES = new Message[] {};
-    
-    public static final String PROPERTY_MESSAGES_BUNDLE_COUNT =
-            "messagesBundleCount"; //$NON-NLS-1$
-    public static final String PROPERTY_KEY_COUNT =
-        "keyCount"; //$NON-NLS-1$
-
-    /** For serialization. */
-    private static final long serialVersionUID = -1977849534191384324L;
-    /** Bundles forming the group (key=Locale; value=MessagesBundle). */
-    private final Map<Locale,MessagesBundle> localeBundles = new HashMap<Locale,MessagesBundle>();
-    private final Set<String> keys = new TreeSet<String>(); 
-    private final IMessagesBundleListener messagesBundleListener =
-            new MessagesBundleListener();
-    
-    private final IMessagesBundleGroupStrategy groupStrategy;
-    private static final Locale[] EMPTY_LOCALES = new Locale[] {};
-    private final String name;
-    
-    /**
-     * Creates a new messages bundle group.
-     * @param groupStrategy a IMessagesBundleGroupStrategy instance
-     */
-    public MessagesBundleGroup(IMessagesBundleGroupStrategy groupStrategy) {
-        super();
-        this.groupStrategy = groupStrategy;
-        this.name = groupStrategy.createMessagesBundleGroupName();
-        MessagesBundle[] bundles = groupStrategy.loadMessagesBundles();
-        if (bundles != null) {
-            for (int i = 0; i < bundles.length; i++) {
-                addMessagesBundle(bundles[i]);
-            }
-        }
-    }
-    
-    /**
-     * Called before this object will be discarded.
-     * Disposes the underlying MessageBundles
-     */
-    public void dispose() {
-    	for (MessagesBundle mb : getMessagesBundles()) {
-    		try {
-    			mb.dispose();
-    		} catch (Throwable t) {
-    			//FIXME: remove debug:
-    			System.err.println("Error disposing message-bundle " +
-    					mb.getResource().getResourceLocationLabel());
-    			//disregard crashes: this is a best effort to dispose things.
-    		}
-    	}
-    }
-
-    
-    /**
-     * Gets the messages bundle matching given locale.
-     * @param locale locale of bundle to retreive
-     * @return a bundle
-     */
-    public MessagesBundle getMessagesBundle(Locale locale) {
-        return localeBundles.get(locale);
-    }
-
-    /**
-     * Gets the messages bundle matching given source object.  A source
-     * object being a context-specific concrete underlying implementation of a
-     * <code>MessagesBundle</code> as per defined in
-	 * <code>IMessageResource</code>.
-     * @param source the source object to match
-     * @return a messages bundle
-     * @see IMessagesResource
-     */
-    public MessagesBundle getMessagesBundle(Object source) {
-    	for (MessagesBundle messagesBundle : getMessagesBundles()) {
-            if (equals(source, messagesBundle.getResource().getSource())) {
-                return messagesBundle;
-            }
-        }
-        return null;
-    }
-    
-    /**
-     * Adds an empty <code>MessagesBundle</code> to this group for the
-     * given locale.
-     * @param locale locale for the new bundle added
-     */
-    public void addMessagesBundle(Locale locale) {
-        addMessagesBundle(groupStrategy.createMessagesBundle(locale));
-    }
-
-    /**
-     * Gets all locales making up this messages bundle group.
-     */
-    public Locale[] getLocales() {
-        return localeBundles.keySet().toArray(EMPTY_LOCALES);
-    }
-
-    /**
-     * Gets all messages associated with the given message key.
-     * @param key a message key
-     * @return messages
-     */
-    public Message[] getMessages(String key) {
-        List<Message> messages = new ArrayList<Message>();
-    	for (MessagesBundle messagesBundle : getMessagesBundles()) {
-            Message message = messagesBundle.getMessage(key);
-            if (message != null) {
-                messages.add(message);
-            }
-        }
-        return messages.toArray(EMPTY_MESSAGES);
-    }
-
-    /**
-     * Gets the message matching given key and locale.
-     * @param locale locale for which to retrieve the message
-     * @param key key matching entry to retrieve the message
-     * @return a message
-     */
-    public Message getMessage(String key, Locale locale) {
-        MessagesBundle messagesBundle = getMessagesBundle(locale);
-        if (messagesBundle != null) {
-            return messagesBundle.getMessage(key);
-        }
-        return null;
-    }
-
-    
-    /**
-     * Adds a messages bundle to this group.
-     * @param messagesBundle bundle to add
-     * @throws MessageException if a messages bundle for the same locale
-     *         already exists.
-     */
-    public void addMessagesBundle(MessagesBundle messagesBundle) {
-        if (localeBundles.get(messagesBundle.getLocale()) != null) {
-            throw new MessageException(
-                 "A bundle with the same locale already exists."); //$NON-NLS-1$
-        }
-        
-        int oldBundleCount = localeBundles.size();
-        localeBundles.put(messagesBundle.getLocale(), messagesBundle);
-        firePropertyChange(PROPERTY_MESSAGES_BUNDLE_COUNT,
-                oldBundleCount, localeBundles.size());
-        fireMessagesBundleAdded(messagesBundle);
-        
-        String[] bundleKeys = messagesBundle.getKeys();
-        for (int i = 0; i < bundleKeys.length; i++) {
-			String key = bundleKeys[i];
-            if (!keys.contains(key)) {
-                int oldKeyCount = keys.size();
-                keys.add(key);
-                firePropertyChange(
-                        PROPERTY_KEY_COUNT, oldKeyCount, keys.size());
-                fireKeyAdded(key);
-            }
-        }
-        messagesBundle.addMessagesBundleListener(messagesBundleListener);
-    }
-
-    /**
-     * Gets this messages bundle group name.
-     * @return bundle group name
-     */
-    public String getName() {
-        return name;
-    }
-    
-    /**
-     * Adds an empty message to every messages bundle of this group with the
-     * given.
-     * @param key message key
-     */
-    public void addMessages(String key) {
-        for (MessagesBundle msgBundle : localeBundles.values()) {
-           	msgBundle.addMessage(key);
-        }
-    }
-
-    /**
-     * Renames a key in all messages bundles forming this group.
-     * @param sourceKey the message key to rename
-     * @param targetKey the new message name
-     */
-    public void renameMessageKeys(String sourceKey, String targetKey) {
-        for (MessagesBundle msgBundle : localeBundles.values()) {
-        	msgBundle.renameMessageKey(
-            		sourceKey, targetKey);
-        }
-    }    
-
-    /**
-     * Removes messages matching the given key from all messages bundle.
-     * @param key key of messages to remove
-     */
-    public void removeMessages(String key) {
-        for (MessagesBundle msgBundle : localeBundles.values()) {
-        	msgBundle.removeMessage(key);
-        }
-    }
-    
-    /**
-     * Sets whether messages matching the <code>key</code> are active or not.
-     * @param key key of messages
-     */
-    public void setMessagesActive(String key, boolean active) {
-        for (MessagesBundle msgBundle : localeBundles.values()) {
-            Message entry = msgBundle.getMessage(key);
-            if (entry != null) {
-                entry.setActive(active);
-            }
-        }
-    }
-    
-    /**
-     * Duplicates each messages matching the <code>sourceKey</code> to
-     * the <code>newKey</code>.
-     * @param sourceKey original key
-     * @param targetKey new key
-     * @throws MessageException if a target key already exists
-     */
-    public void duplicateMessages(String sourceKey, String targetKey) {
-        if (sourceKey.equals(targetKey)) {
-            return;
-        }
-        for (MessagesBundle msgBundle : localeBundles.values()) {
-        	msgBundle.duplicateMessage(
-            		sourceKey, targetKey);
-        }
-    }
-    
-    /**
-     * Returns a collection of all bundles in this group.
-     * @return the bundles in this group
-     */
-    public Collection<MessagesBundle> getMessagesBundles() {
-        return localeBundles.values();
-    }
-    
-    /**
-     * Gets all keys from all messages bundles.
-     * @return all keys from all messages bundles
-     */
-    public String[] getMessageKeys() {
-        return keys.toArray(BabelUtils.EMPTY_STRINGS);
-    }
-    
-    /**
-     * Whether the given key is found in this messages bundle group.
-     * @param key the key to find
-     * @return <code>true</code> if the key exists in this bundle group.
-     */
-    public boolean isMessageKey(String key) {
-        return keys.contains(key);
-    }
-    
-    /**
-     * Gets the number of messages bundles in this group.
-     * @return the number of messages bundles in this group
-     */
-    public int getMessagesBundleCount() {
-        return localeBundles.size();
-    }
-    
-    /**
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
-    public boolean equals(Object obj) {
-        if (!(obj instanceof MessagesBundleGroup)) {
-            return false;
-        }
-        MessagesBundleGroup messagesBundleGroup = (MessagesBundleGroup) obj;
-        return equals(localeBundles, messagesBundleGroup.localeBundles);
-    }    
-    
-    public final synchronized void addMessagesBundleGroupListener(
-            final IMessagesBundleGroupListener listener) {
-        addPropertyChangeListener(listener);
-    }
-    public final synchronized void removeMessagesBundleGroupListener(
-            final IMessagesBundleGroupListener listener) {
-        removePropertyChangeListener(listener);
-    }
-    public final synchronized IMessagesBundleGroupListener[] 
-                getMessagesBundleGroupListeners() {
-        //TODO find more efficient way to avoid class cast.
-        return Arrays.asList(
-                getPropertyChangeListeners()).toArray(
-                        EMPTY_GROUP_LISTENERS);
-    }
-    
-    
-    private void fireKeyAdded(String key) {
-        IMessagesBundleGroupListener[] listeners =
-                getMessagesBundleGroupListeners();
-        for (int i = 0; i < listeners.length; i++) {
-            IMessagesBundleGroupListener listener = listeners[i];
-            listener.keyAdded(key);
-        }
-    }
-    private void fireKeyRemoved(String key) {
-        IMessagesBundleGroupListener[] listeners =
-                getMessagesBundleGroupListeners();
-        for (int i = 0; i < listeners.length; i++) {
-            IMessagesBundleGroupListener listener = listeners[i];
-            listener.keyRemoved(key);
-        }
-    }
-    private void fireMessagesBundleAdded(MessagesBundle messagesBundle) {
-        IMessagesBundleGroupListener[] listeners =
-                getMessagesBundleGroupListeners();
-        for (int i = 0; i < listeners.length; i++) {
-            IMessagesBundleGroupListener listener = listeners[i];
-            listener.messagesBundleAdded(messagesBundle);
-        }
-    }
-    private void fireMessagesBundleRemoved(MessagesBundle messagesBundle) {
-        IMessagesBundleGroupListener[] listeners =
-                getMessagesBundleGroupListeners();
-        for (int i = 0; i < listeners.length; i++) {
-            IMessagesBundleGroupListener listener = listeners[i];
-            listener.messagesBundleRemoved(messagesBundle);
-        }
-    }
-    
-    
-    /**
-     * Class listening for changes in underlying messages bundle and 
-     * relays them to the listeners for MessagesBundleGroup.
-     */
-    private class MessagesBundleListener implements IMessagesBundleListener {
-        public void messageAdded(MessagesBundle messagesBundle,
-                Message message) {
-            int oldCount = keys.size();
-            IMessagesBundleGroupListener[] listeners =
-                    getMessagesBundleGroupListeners();
-            for (int i = 0; i < listeners.length; i++) {
-                IMessagesBundleGroupListener listener = listeners[i];
-                listener.messageAdded(messagesBundle, message);
-                if (getMessages(message.getKey()).length == 1) {
-                    keys.add(message.getKey());
-                    firePropertyChange(
-                            PROPERTY_KEY_COUNT, oldCount, keys.size());
-                    fireKeyAdded(message.getKey());
-                }
-            }
-        }
-        public void messageRemoved(MessagesBundle messagesBundle,
-                Message message) {
-            int oldCount = keys.size();
-            IMessagesBundleGroupListener[] listeners =
-                    getMessagesBundleGroupListeners();
-            for (int i = 0; i < listeners.length; i++) {
-                IMessagesBundleGroupListener listener = listeners[i];
-                listener.messageRemoved(messagesBundle, message);
-                int keyMessagesCount = getMessages(message.getKey()).length;
-                if (keyMessagesCount == 0 && keys.contains(message.getKey())) {
-                    keys.remove(message.getKey());
-                    firePropertyChange(
-                            PROPERTY_KEY_COUNT, oldCount, keys.size());
-                    fireKeyRemoved(message.getKey());
-                }
-            }
-        }
-        public void messageChanged(MessagesBundle messagesBundle,
-                PropertyChangeEvent changeEvent) {
-            IMessagesBundleGroupListener[] listeners =
-                    getMessagesBundleGroupListeners();
-            for (int i = 0; i < listeners.length; i++) {
-                IMessagesBundleGroupListener listener = listeners[i];
-                listener.messageChanged(messagesBundle, changeEvent);
-            }
-        }
-        // MessagesBundle property changes:
-        public void propertyChange(PropertyChangeEvent evt) {
-            MessagesBundle bundle = (MessagesBundle) evt.getSource();
-            IMessagesBundleGroupListener[] listeners =
-                    getMessagesBundleGroupListeners();
-            for (int i = 0; i < listeners.length; i++) {
-                IMessagesBundleGroupListener listener = listeners[i];
-                listener.messagesBundleChanged(bundle, evt);
-            }
-        }
-    }
-}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleGroupAdapter.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleGroupAdapter.java
deleted file mode 100644
index 4900e72..0000000
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleGroupAdapter.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.eclipse.babel.core.message;
-
-import java.beans.PropertyChangeEvent;
-
-/**
- * An adapter class for a {@link IMessagesBundleGroupListener}.  Methods 
- * implementation do nothing.
- * @author Pascal Essiembre (pascal@essiembre.com)
- */
-public class MessagesBundleGroupAdapter
-        implements IMessagesBundleGroupListener {
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleGroupListener#
-     *              keyAdded(java.lang.String)
-     */
-    public void keyAdded(String key) {
-        // do nothing
-    }
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleGroupListener#
-     *              keyRemoved(java.lang.String)
-     */
-    public void keyRemoved(String key) {
-        // do nothing
-    }
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleGroupListener#
-     *      messagesBundleAdded(org.eclipse.babel.core.message.MessagesBundle)
-     */
-    public void messagesBundleAdded(MessagesBundle messagesBundle) {
-        // do nothing
-    }
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleGroupListener#
-     *      messagesBundleChanged(org.eclipse.babel.core.message.MessagesBundle,
-     *                            java.beans.PropertyChangeEvent)
-     */
-    public void messagesBundleChanged(MessagesBundle messagesBundle,
-            PropertyChangeEvent changeEvent) {
-        // do nothing
-    }
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleGroupListener
-     *     #messagesBundleRemoved(org.eclipse.babel.core.message.MessagesBundle)
-     */
-    public void messagesBundleRemoved(MessagesBundle messagesBundle) {
-        // do nothing
-    }
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleListener#messageAdded(
-     *              org.eclipse.babel.core.message.MessagesBundle,
-     *              org.eclipse.babel.core.message.Message)
-     */
-    public void messageAdded(MessagesBundle messagesBundle, Message message) {
-        // do nothing
-    }
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleListener#
-     *      messageChanged(org.eclipse.babel.core.message.MessagesBundle,
-     *                     java.beans.PropertyChangeEvent)
-     */
-    public void messageChanged(MessagesBundle messagesBundle,
-            PropertyChangeEvent changeEvent) {
-        // do nothing
-    }
-    /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleListener#
-     *      messageRemoved(org.eclipse.babel.core.message.MessagesBundle,
-     *                     org.eclipse.babel.core.message.Message)
-     */
-    public void messageRemoved(MessagesBundle messagesBundle, Message message) {
-        // do nothing
-    }
-    /**
-     * @see java.beans.PropertyChangeListener#propertyChange(
-     *           java.beans.PropertyChangeEvent)
-     */
-    public void propertyChange(PropertyChangeEvent evt) {
-        // do nothing
-    }
-}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/IMessageCheck.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/IMessageCheck.java
index 764aa65..6258638 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/IMessageCheck.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/IMessageCheck.java
@@ -10,8 +10,10 @@
  ******************************************************************************/
 package org.eclipse.babel.core.message.checks;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.Message;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
 
 /**
  * All purpose {@link Message} testing.   Use this interface to establish 
@@ -27,5 +29,5 @@
 	 * @param message the message being tested
 	 * @return <code>true</code> if condition is successfully tested
 	 */
-    boolean checkKey(MessagesBundleGroup messagesBundleGroup, Message message);
+    boolean checkKey(IMessagesBundleGroup messagesBundleGroup, IMessage message);
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/DuplicateValueCheck.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/DuplicateValueCheck.java
similarity index 79%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/DuplicateValueCheck.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/DuplicateValueCheck.java
index 051b4a7..2cf96dc 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/DuplicateValueCheck.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/DuplicateValueCheck.java
@@ -8,14 +8,15 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.checks;
+package org.eclipse.babel.core.message.checks.internal;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundle;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.checks.IMessageCheck;
 import org.eclipse.babel.core.util.BabelUtils;
 
 /**
@@ -41,12 +42,12 @@
     }
 
     public boolean checkKey(
-            MessagesBundleGroup messagesBundleGroup, Message message) {
+            IMessagesBundleGroup messagesBundleGroup, IMessage message) {
         Collection<String> keys = new ArrayList<String>();
         if (message != null) {
-            MessagesBundle messagesBundle =
+            IMessagesBundle messagesBundle =
             		messagesBundleGroup.getMessagesBundle(message.getLocale());
-            for (Message duplicateEntry : messagesBundle.getMessages()) {
+            for (IMessage duplicateEntry : messagesBundle.getMessages()) {
                 if (!message.getKey().equals(duplicateEntry.getKey())
                             && BabelUtils.equals(message.getValue(),
                                     duplicateEntry.getValue())) {
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/MissingValueCheck.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/MissingValueCheck.java
similarity index 69%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/MissingValueCheck.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/MissingValueCheck.java
index 7c79c56..e5a5295 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/MissingValueCheck.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/MissingValueCheck.java
@@ -8,10 +8,11 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.checks;
+package org.eclipse.babel.core.message.checks.internal;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.checks.IMessageCheck;
 
 /**
  * Visitor for finding if a key has at least one corresponding bundle entry
@@ -31,12 +32,12 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.checks.IMessageCheck#checkKey(
-     * 	        org.eclipse.babel.core.message.MessagesBundleGroup,
-     * 		    org.eclipse.babel.core.message.Message)
+     * @see org.eclipse.babel.core.message.internal.checks.IMessageCheck#checkKey(
+     * 	        org.eclipse.babel.core.message.internal.MessagesBundleGroup,
+     * 		    org.eclipse.babel.core.message.internal.Message)
      */
     public boolean checkKey(
-            MessagesBundleGroup messagesBundleGroup, Message message) {
+            IMessagesBundleGroup messagesBundleGroup, IMessage message) {
         if (message == null || message.getValue() == null
                 || message.getValue().length() == 0) {
             return true;
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/SimilarValueCheck.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/SimilarValueCheck.java
similarity index 77%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/SimilarValueCheck.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/SimilarValueCheck.java
index 9986cf7..be333ca 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/SimilarValueCheck.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/checks/internal/SimilarValueCheck.java
@@ -8,14 +8,15 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.checks;
+package org.eclipse.babel.core.message.checks.internal;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundle;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.checks.IMessageCheck;
 import org.eclipse.babel.core.message.checks.proximity.IProximityAnalyzer;
 import org.eclipse.babel.core.util.BabelUtils;
 
@@ -38,19 +39,19 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.checks.IMessageCheck#checkKey(
-     * 			org.eclipse.babel.core.message.MessagesBundleGroup,
-     *			org.eclipse.babel.core.message.Message)
+     * @see org.eclipse.babel.core.message.internal.checks.IMessageCheck#checkKey(
+     * 			org.eclipse.babel.core.message.internal.MessagesBundleGroup,
+     *			org.eclipse.babel.core.message.internal.Message)
      */
     public boolean checkKey(
-            MessagesBundleGroup messagesBundleGroup, Message message) {
+            IMessagesBundleGroup messagesBundleGroup, IMessage message) {
         Collection<String> keys = new ArrayList<String>();
         if (message != null) {
             //TODO have case as preference
             String value1 = message.getValue().toLowerCase();
-            MessagesBundle messagesBundle =
+            IMessagesBundle messagesBundle =
             		messagesBundleGroup.getMessagesBundle(message.getLocale());
-            for (Message similarEntry : messagesBundle.getMessages()) {
+            for (IMessage similarEntry : messagesBundle.getMessages()) {
                 if (!message.getKey().equals(similarEntry.getKey())) {
                     String value2 = similarEntry.getValue().toLowerCase();
                     //TODO have preference to report identical as similar
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/AbstractIFileChangeListener.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/AbstractIFileChangeListener.java
similarity index 97%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/AbstractIFileChangeListener.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/AbstractIFileChangeListener.java
index f751e69..83179c9 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/AbstractIFileChangeListener.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/AbstractIFileChangeListener.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IResourceChangeEvent;
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/AbstractMessageModel.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/AbstractMessageModel.java
similarity index 94%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/AbstractMessageModel.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/AbstractMessageModel.java
index 19a410d..ee50712 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/AbstractMessageModel.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/AbstractMessageModel.java
@@ -7,14 +7,16 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapJI integration -> DirtyHack
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.io.Serializable;
 
+import org.eclipse.babel.core.configuration.DirtyHack;
 import org.eclipse.babel.core.util.BabelUtils;
 
 
@@ -95,7 +97,7 @@
             final String propertyName,
             final Object oldValue,
             final Object newValue) {
-        if (changeSupport == null) {
+        if (changeSupport == null || !DirtyHack.isFireEnabled()) {
             return;
         }
         changeSupport.firePropertyChange(propertyName, oldValue, newValue);
@@ -115,7 +117,7 @@
             final String propertyName,
             final boolean oldValue,
             final boolean newValue) {
-        if (changeSupport == null) {
+        if (changeSupport == null || !DirtyHack.isFireEnabled()) {
             return;
         }
         changeSupport.firePropertyChange(propertyName, oldValue, newValue);
@@ -131,7 +133,7 @@
      */
     protected final void firePropertyChange(
             final PropertyChangeEvent event) {
-        if (changeSupport == null) {
+        if (changeSupport == null || !DirtyHack.isFireEnabled()) {
             return;
         }
         changeSupport.firePropertyChange(event);
@@ -187,7 +189,7 @@
             final String propertyName,
             final int oldValue,
             final int newValue) {
-        if (changeSupport == null) {
+        if (changeSupport == null || !DirtyHack.isFireEnabled()) {
             return;
         }
         changeSupport.firePropertyChange(propertyName, oldValue, newValue);
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleGroupListener.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/IMessagesBundleGroupListener.java
similarity index 96%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleGroupListener.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/IMessagesBundleGroupListener.java
index 0a85fba..7fb97c5 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleGroupListener.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/IMessagesBundleGroupListener.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 import java.beans.PropertyChangeEvent;
 
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleListener.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/IMessagesBundleListener.java
similarity index 96%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleListener.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/IMessagesBundleListener.java
index 932e2e3..108601b 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/IMessagesBundleListener.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/IMessagesBundleListener.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/Message.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/Message.java
similarity index 87%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/Message.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/Message.java
index a07f894..90eac41 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/Message.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/Message.java
@@ -7,12 +7,15 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapJI integration
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 import java.beans.PropertyChangeListener;
 import java.util.Locale;
 
+import org.eclipse.babel.core.message.IMessage;
+
 /**
  * A single entry in a <code>MessagesBundle</code>.
  * 
@@ -20,7 +23,7 @@
  * @see MessagesBundle
  * @see MessagesBundleGroup
  */
-public final class Message extends AbstractMessageModel {
+public final class Message extends AbstractMessageModel implements IMessage {
 
     /** For serialisation. */
     private static final long serialVersionUID = 1160670351341655427L;
@@ -62,6 +65,14 @@
         this.comment = comment;
         firePropertyChange(PROPERTY_COMMENT, oldValue, comment);
     }
+    
+    public void setComment(String comment, boolean silent) {
+        Object oldValue = this.comment;
+        this.comment = comment;
+        if (!silent) {
+        	firePropertyChange(PROPERTY_COMMENT, oldValue, comment);
+        }
+    }
 
     /**
      * Sets whether the message is active or not.  An inactive message is
@@ -86,6 +97,14 @@
         this.text = text;
         firePropertyChange(PROPERTY_TEXT, oldValue, text);
     }
+    
+    public void setText(String text, boolean silent) {
+        Object oldValue = this.text;
+        this.text = text;
+        if (!silent) {
+        	firePropertyChange(PROPERTY_TEXT, oldValue, text);
+        }
+    }
 
     /**
      * Gets the comment associated with this message (<code>null</code> if
@@ -133,7 +152,7 @@
      * message key and locale.
      * @param message
      */
-    protected void copyFrom(Message message) {
+    protected void copyFrom(IMessage message) {
         setComment(message.getComment());
         setActive(message.isActive());
         setText(message.getValue());
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessageException.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessageException.java
similarity index 96%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessageException.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessageException.java
index 0083747..242b902 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessageException.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessageException.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 /**
  * Exception thrown when a message-related operation raised a problem. 
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundle.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundle.java
similarity index 81%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundle.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundle.java
index 1cf42c0..ef7f249 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundle.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundle.java
@@ -7,8 +7,10 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapJI integration, correct dispose
+ *    Matthias Lettmayer - added removeMessageAddParentKey() (fixed issue 41)
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
@@ -19,8 +21,10 @@
 import java.util.Locale;
 import java.util.Map;
 
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.IMessagesResourceChangeListener;
 import org.eclipse.babel.core.message.resource.IMessagesResource;
-import org.eclipse.babel.core.message.resource.IMessagesResourceChangeListener;
 import org.eclipse.babel.core.util.BabelUtils;
 
 /**
@@ -28,7 +32,7 @@
  * @author Pascal Essiembre (pascal@essiembre.com)
  */
 public class MessagesBundle extends AbstractMessageModel
-		implements IMessagesResourceChangeListener {
+		implements IMessagesResourceChangeListener, IMessagesBundle {
 
     private static final long serialVersionUID = -331515196227475652L;
 
@@ -39,7 +43,7 @@
     private static final IMessagesBundleListener[] EMPTY_MSG_BUNDLE_LISTENERS =
         new IMessagesBundleListener[] {};
     private final Collection<String> orderedKeys = new ArrayList<String>();
-    private final Map<String, Message> keyedMessages = new HashMap<String, Message>();
+    private final Map<String, IMessage> keyedMessages = new HashMap<String, IMessage>();
 
     private final IMessagesResource resource;
     
@@ -82,7 +86,7 @@
      * Called before this object will be discarded.
      */
     public void dispose() {
-    	
+    	this.resource.dispose();
     }
     
     /**
@@ -127,7 +131,7 @@
     /**
      * @see org.eclipse.babel.core.message.resource
      * 		.IMessagesResourceChangeListener#resourceChanged(
-     * 				org.eclipse.babel.core.message.resource.IMessagesResource)
+     * 				org.eclipse.babel.core.message.internal.resource.IMessagesResource)
      */
     public void resourceChanged(IMessagesResource changedResource) {
         this.resource.deserialize(this);
@@ -138,21 +142,22 @@
      * its properties are updated and no new message is added.
      * @param message the message to add
      */
-    public void addMessage(Message message) {
+    public void addMessage(IMessage message) {
+        Message m = (Message) message;
         int oldCount = getMessagesCount();
-        if (!orderedKeys.contains(message.getKey())) {
-            orderedKeys.add(message.getKey());
+        if (!orderedKeys.contains(m.getKey())) {
+            orderedKeys.add(m.getKey());
         }
-        if (!keyedMessages.containsKey(message.getKey())) {
-            keyedMessages.put(message.getKey(), message);
-            message.addMessageListener(messageListener);
+        if (!keyedMessages.containsKey(m.getKey())) {
+            keyedMessages.put(m.getKey(), m);
+            m.addMessageListener(messageListener);
             firePropertyChange(
                     PROPERTY_MESSAGES_COUNT, oldCount, getMessagesCount());
-            fireMessageAdded(message);
+            fireMessageAdded(m);
         } else {
             // Entry already exists, update it.
-            Message matchingEntry = keyedMessages.get(message.getKey());
-            matchingEntry.copyFrom(message);
+            Message matchingEntry = (Message) keyedMessages.get(m.getKey());
+            matchingEntry.copyFrom(m);
         }
     }
     /**
@@ -162,7 +167,7 @@
     public void removeMessage(String messageKey) {
         int oldCount = getMessagesCount();
         orderedKeys.remove(messageKey);
-        Message message = keyedMessages.get(messageKey);
+        Message message = (Message) keyedMessages.get(messageKey);
         if (message != null) {
             message.removePropertyChangeListener(messageListener);
             keyedMessages.remove(messageKey);
@@ -171,6 +176,23 @@
             fireMessageRemoved(message);
         }
     }
+    
+    /**
+     * Removes a message from this messages bundle and adds it's parent key to bundle.
+     * E.g.: key = a.b.c gets deleted, a.b gets added with a default message
+     * @param messageKey the key of the message to remove
+     */
+    public void removeMessageAddParentKey(String messageKey) {
+    	removeMessage(messageKey);   	
+            
+        // add parent key
+        int index = messageKey.lastIndexOf(".");
+        messageKey = (index == -1 ? "" : messageKey.substring(0, index));
+        
+        if (! messageKey.isEmpty())
+        	addMessage(new Message(messageKey, getLocale()));        
+    }
+    
     /**
      * Removes messages from this messages bundle.
      * @param messageKeys the keys of the messages to remove
@@ -192,7 +214,7 @@
             throw new MessageException(
             		"Cannot rename: target key already exists."); //$NON-NLS-1$
         }
-        Message sourceEntry = getMessage(sourceKey);
+        IMessage sourceEntry = getMessage(sourceKey);
         if (sourceEntry != null) {
             Message targetEntry = new Message(targetKey, getLocale());
             targetEntry.copyFrom(sourceEntry);
@@ -211,7 +233,7 @@
             throw new MessageException(
             	"Cannot duplicate: target key already exists."); //$NON-NLS-1$
         }
-        Message sourceEntry = getMessage(sourceKey);
+        IMessage sourceEntry = getMessage(sourceKey);
         if (sourceEntry != null) {
             Message targetEntry = new Message(targetKey, getLocale());
             targetEntry.copyFrom(sourceEntry);
@@ -224,7 +246,7 @@
      * @param key a message key
      * @return a message
      */
-    public Message getMessage(String key) {
+    public IMessage getMessage(String key) {
         return keyedMessages.get(key);
     }
 
@@ -248,7 +270,7 @@
      * Obtains the set of <code>Message</code> objects in this bundle.
      * @return a collection of <code>Message</code> objects in this bundle
      */
-    public Collection<Message> getMessages() {
+    public Collection<IMessage> getMessages() {
         return keyedMessages.values();
     }
 
@@ -259,7 +281,7 @@
         String str = "MessagesBundle=[[locale=" + getLocale() //$NON-NLS-1$
                    + "][comment=" + comment //$NON-NLS-1$
                    + "][entries="; //$NON-NLS-1$
-        for (Message message : getMessages()) {
+        for (IMessage message : getMessages()) {
             str += message.toString();
         }
         str += "]]"; //$NON-NLS-1$
@@ -341,4 +363,14 @@
             listener.messageChanged(this, event);
         }
     }
+    
+    /**
+     * Returns the value to the given key, if the key exists.
+     * Otherwise may throw a NPE.
+     * @param key, the key of a message.
+     * @return The value to the given key.
+     */
+    public String getValue(String key) {
+        return getMessage(key).getValue();
+    }
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleAdapter.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleAdapter.java
similarity index 68%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleAdapter.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleAdapter.java
index 7bd04e5..d33d6c3 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/MessagesBundleAdapter.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleAdapter.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message;
+package org.eclipse.babel.core.message.internal;
 
 import java.beans.PropertyChangeEvent;
 
@@ -20,16 +20,16 @@
 public class MessagesBundleAdapter implements IMessagesBundleListener {
 
     /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleListener#messageAdded(
-     *              org.eclipse.babel.core.message.MessagesBundle,
-     *              org.eclipse.babel.core.message.Message)
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleListener#messageAdded(
+     *              org.eclipse.babel.core.message.internal.MessagesBundle,
+     *              org.eclipse.babel.core.message.internal.Message)
      */
     public void messageAdded(MessagesBundle messagesBundle, Message message) {
         // do nothing
     }
     /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleListener
-     *      #messageChanged(org.eclipse.babel.core.message.MessagesBundle,
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleListener
+     *      #messageChanged(org.eclipse.babel.core.message.internal.MessagesBundle,
      *                      java.beans.PropertyChangeEvent)
      */
     public void messageChanged(MessagesBundle messagesBundle,
@@ -37,9 +37,9 @@
         // do nothing
     }
     /**
-     * @see org.eclipse.babel.core.message.IMessagesBundleListener
-     *      #messageRemoved(org.eclipse.babel.core.message.MessagesBundle,
-     *                      org.eclipse.babel.core.message.Message)
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleListener
+     *      #messageRemoved(org.eclipse.babel.core.message.internal.MessagesBundle,
+     *                      org.eclipse.babel.core.message.internal.Message)
      */
     public void messageRemoved(MessagesBundle messagesBundle, Message message) {
         // do nothing
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleGroup.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleGroup.java
new file mode 100644
index 0000000..4cc1040
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleGroup.java
@@ -0,0 +1,615 @@
+/*******************************************************************************
+ * 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
+ *    Alexej Strelzow - TapJI integration
+ *    Matthias Lettmayer - added removeMessagesAddParentKey() (fixed issue 41)
+ ******************************************************************************/
+package org.eclipse.babel.core.message.internal;
+
+import java.beans.PropertyChangeEvent;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.manager.RBManager;
+import org.eclipse.babel.core.message.resource.IMessagesResource;
+import org.eclipse.babel.core.message.strategy.IMessagesBundleGroupStrategy;
+import org.eclipse.babel.core.message.strategy.PropertiesFileGroupStrategy;
+import org.eclipse.babel.core.util.BabelUtils;
+
+/**
+ * Grouping of all messages bundle of the same kind.
+ * 
+ * @author Pascal Essiembre (pascal@essiembre.com)
+ */
+public class MessagesBundleGroup extends AbstractMessageModel implements
+	IMessagesBundleGroup {
+
+    private String projectName;
+
+    private static final IMessagesBundleGroupListener[] EMPTY_GROUP_LISTENERS = new IMessagesBundleGroupListener[] {};
+    private static final Message[] EMPTY_MESSAGES = new Message[] {};
+
+    public static final String PROPERTY_MESSAGES_BUNDLE_COUNT = "messagesBundleCount"; //$NON-NLS-1$
+    public static final String PROPERTY_KEY_COUNT = "keyCount"; //$NON-NLS-1$
+
+    /** For serialization. */
+    private static final long serialVersionUID = -1977849534191384324L;
+    /** Bundles forming the group (key=Locale; value=MessagesBundle). */
+    private final Map<Locale, IMessagesBundle> localeBundles = new HashMap<Locale, IMessagesBundle>();
+    private final Set<String> keys = new TreeSet<String>();
+    private final IMessagesBundleListener messagesBundleListener = new MessagesBundleListener();
+
+    private final IMessagesBundleGroupStrategy groupStrategy;
+    private static final Locale[] EMPTY_LOCALES = new Locale[] {};
+    private final String name;
+    private final String resourceBundleId;
+
+    /**
+     * Creates a new messages bundle group.
+     * 
+     * @param groupStrategy
+     *            a IMessagesBundleGroupStrategy instance
+     */
+    public MessagesBundleGroup(IMessagesBundleGroupStrategy groupStrategy) {
+	super();
+	this.groupStrategy = groupStrategy;
+	this.name = groupStrategy.createMessagesBundleGroupName();
+	this.resourceBundleId = groupStrategy.createMessagesBundleId();
+
+	this.projectName = groupStrategy.getProjectName();
+
+	MessagesBundle[] bundles = groupStrategy.loadMessagesBundles();
+	if (bundles != null) {
+	    for (int i = 0; i < bundles.length; i++) {
+		addMessagesBundle(bundles[i]);
+	    }
+	}
+
+	if (this.projectName != null) {
+	    RBManager.getInstance(this.projectName)
+		    .notifyMessagesBundleGroupCreated(this);
+	}
+    }
+
+    /**
+     * Called before this object will be discarded. Disposes the underlying
+     * MessageBundles
+     */
+    @Override
+    public void dispose() {
+	for (IMessagesBundle mb : getMessagesBundles()) {
+	    try {
+		mb.dispose();
+	    } catch (Throwable t) {
+		// FIXME: remove debug:
+		System.err.println("Error disposing message-bundle "
+			+ ((MessagesBundle) mb).getResource()
+				.getResourceLocationLabel());
+		// disregard crashes: this is a best effort to dispose things.
+	    }
+	}
+
+	RBManager.getInstance(this.projectName)
+		.notifyMessagesBundleGroupDeleted(this);
+    }
+
+    /**
+     * Gets the messages bundle matching given locale.
+     * 
+     * @param locale
+     *            locale of bundle to retreive
+     * @return a bundle
+     */
+    @Override
+    public IMessagesBundle getMessagesBundle(Locale locale) {
+	return localeBundles.get(locale);
+    }
+
+    /**
+     * Gets the messages bundle matching given source object. A source object
+     * being a context-specific concrete underlying implementation of a
+     * <code>MessagesBundle</code> as per defined in
+     * <code>IMessageResource</code>.
+     * 
+     * @param source
+     *            the source object to match
+     * @return a messages bundle
+     * @see IMessagesResource
+     */
+    public MessagesBundle getMessagesBundle(Object source) {
+	for (IMessagesBundle messagesBundle : getMessagesBundles()) {
+	    if (equals(source, ((MessagesBundle) messagesBundle).getResource()
+		    .getSource())) {
+		return (MessagesBundle) messagesBundle;
+	    }
+	}
+	return null;
+    }
+
+    /**
+     * Adds an empty <code>MessagesBundle</code> to this group for the given
+     * locale.
+     * 
+     * @param locale
+     *            locale for the new bundle added
+     */
+    public void addMessagesBundle(Locale locale) {
+	addMessagesBundle(groupStrategy.createMessagesBundle(locale));
+    }
+
+    /**
+     * Gets all locales making up this messages bundle group.
+     */
+    public Locale[] getLocales() {
+	return localeBundles.keySet().toArray(EMPTY_LOCALES);
+    }
+
+    /**
+     * Gets all messages associated with the given message key.
+     * 
+     * @param key
+     *            a message key
+     * @return messages
+     */
+    @Override
+    public IMessage[] getMessages(String key) {
+	List<IMessage> messages = new ArrayList<IMessage>();
+	for (IMessagesBundle messagesBundle : getMessagesBundles()) {
+	    IMessage message = messagesBundle.getMessage(key);
+	    if (message != null) {
+		messages.add(message);
+	    }
+	}
+	return messages.toArray(EMPTY_MESSAGES);
+    }
+
+    /**
+     * Gets the message matching given key and locale.
+     * 
+     * @param locale
+     *            locale for which to retrieve the message
+     * @param key
+     *            key matching entry to retrieve the message
+     * @return a message
+     */
+    @Override
+    public IMessage getMessage(String key, Locale locale) {
+	IMessagesBundle messagesBundle = getMessagesBundle(locale);
+	if (messagesBundle != null) {
+	    return messagesBundle.getMessage(key);
+	}
+	return null;
+    }
+
+    /**
+     * Adds a messages bundle to this group.
+     * 
+     * @param messagesBundle
+     *            bundle to add
+     * @throws MessageException
+     *             if a messages bundle for the same locale already exists.
+     */
+    public void addMessagesBundle(IMessagesBundle messagesBundle) {
+	addMessagesBundle(messagesBundle.getLocale(), messagesBundle);
+    }
+
+    /**
+     * Adds a messages bundle to this group.
+     * 
+     * @param locale
+     *            The locale of the bundle
+     * @param messagesBundle
+     *            bundle to add
+     * @throws MessageException
+     *             if a messages bundle for the same locale already exists.
+     */
+    @Override
+    public void addMessagesBundle(Locale locale, IMessagesBundle messagesBundle) {
+	MessagesBundle mb = (MessagesBundle) messagesBundle;
+	if (localeBundles.get(mb.getLocale()) != null) {
+	    throw new MessageException(
+		    "A bundle with the same locale already exists."); //$NON-NLS-1$
+	}
+
+	int oldBundleCount = localeBundles.size();
+	localeBundles.put(mb.getLocale(), mb);
+
+	firePropertyChange(PROPERTY_MESSAGES_BUNDLE_COUNT, oldBundleCount,
+		localeBundles.size());
+	fireMessagesBundleAdded(mb);
+
+	String[] bundleKeys = mb.getKeys();
+	for (int i = 0; i < bundleKeys.length; i++) {
+	    String key = bundleKeys[i];
+	    if (!keys.contains(key)) {
+		int oldKeyCount = keys.size();
+		keys.add(key);
+		firePropertyChange(PROPERTY_KEY_COUNT, oldKeyCount, keys.size());
+		fireKeyAdded(key);
+	    }
+	}
+	mb.addMessagesBundleListener(messagesBundleListener);
+
+    }
+
+    /**
+     * Removes the {@link IMessagesBundle} from the group.
+     * 
+     * @param messagesBundle
+     *            The bundle to remove.
+     */
+    @Override
+    public void removeMessagesBundle(IMessagesBundle messagesBundle) {
+	Locale locale = messagesBundle.getLocale();
+
+	if (localeBundles.containsKey(locale)) {
+	    localeBundles.remove(locale);
+	}
+
+	// which keys should I not remove?
+	Set<String> keysNotToRemove = new TreeSet<String>();
+
+	for (String key : messagesBundle.getKeys()) {
+	    for (IMessagesBundle bundle : localeBundles.values()) {
+		if (bundle.getMessage(key) != null) {
+		    keysNotToRemove.add(key);
+		}
+	    }
+	}
+
+	// remove keys
+	for (String keyToRemove : messagesBundle.getKeys()) {
+	    if (!keysNotToRemove.contains(keyToRemove)) { // we can remove
+		keys.remove(keyToRemove);
+	    }
+	}
+    }
+
+    /**
+     * Gets this messages bundle group name. That is the name, which is used for
+     * the tab of the MultiPageEditorPart
+     * 
+     * @return bundle group name
+     */
+    @Override
+    public String getName() {
+	return name;
+    }
+
+    /**
+     * Adds an empty message to every messages bundle of this group with the
+     * given.
+     * 
+     * @param key
+     *            message key
+     */
+    @Override
+    public void addMessages(String key) {
+	for (IMessagesBundle msgBundle : localeBundles.values()) {
+	    ((MessagesBundle) msgBundle).addMessage(key);
+	}
+    }
+
+    /**
+     * Renames a key in all messages bundles forming this group.
+     * 
+     * @param sourceKey
+     *            the message key to rename
+     * @param targetKey
+     *            the new message name
+     */
+    public void renameMessageKeys(String sourceKey, String targetKey) {
+	for (IMessagesBundle msgBundle : localeBundles.values()) {
+	    msgBundle.renameMessageKey(sourceKey, targetKey);
+	}
+    }
+
+    /**
+     * Removes messages matching the given key from all messages bundle.
+     * 
+     * @param key
+     *            key of messages to remove
+     */
+    @Override
+    public void removeMessages(String key) {
+	for (IMessagesBundle msgBundle : localeBundles.values()) {
+	    msgBundle.removeMessage(key);
+	}
+    }
+
+    /**
+     * Removes messages matching the given key from all messages bundle and add
+     * it's parent key to bundles.
+     * 
+     * @param key
+     *            key of messages to remove
+     */
+    @Override
+    public void removeMessagesAddParentKey(String key) {
+	for (IMessagesBundle msgBundle : localeBundles.values()) {
+	    msgBundle.removeMessageAddParentKey(key);
+	}
+    }
+
+    /**
+     * Sets whether messages matching the <code>key</code> are active or not.
+     * 
+     * @param key
+     *            key of messages
+     */
+    public void setMessagesActive(String key, boolean active) {
+	for (IMessagesBundle msgBundle : localeBundles.values()) {
+	    IMessage entry = msgBundle.getMessage(key);
+	    if (entry != null) {
+		entry.setActive(active);
+	    }
+	}
+    }
+
+    /**
+     * Duplicates each messages matching the <code>sourceKey</code> to the
+     * <code>newKey</code>.
+     * 
+     * @param sourceKey
+     *            original key
+     * @param targetKey
+     *            new key
+     * @throws MessageException
+     *             if a target key already exists
+     */
+    public void duplicateMessages(String sourceKey, String targetKey) {
+	if (sourceKey.equals(targetKey)) {
+	    return;
+	}
+	for (IMessagesBundle msgBundle : localeBundles.values()) {
+	    msgBundle.duplicateMessage(sourceKey, targetKey);
+	}
+    }
+
+    /**
+     * Returns a collection of all bundles in this group.
+     * 
+     * @return the bundles in this group
+     */
+    @Override
+    public Collection<IMessagesBundle> getMessagesBundles() {
+	return localeBundles.values();
+    }
+
+    /**
+     * Gets all keys from all messages bundles.
+     * 
+     * @return all keys from all messages bundles
+     */
+    @Override
+    public String[] getMessageKeys() {
+	return keys.toArray(BabelUtils.EMPTY_STRINGS);
+    }
+
+    /**
+     * Whether the given key is found in this messages bundle group.
+     * 
+     * @param key
+     *            the key to find
+     * @return <code>true</code> if the key exists in this bundle group.
+     */
+    @Override
+    public boolean isMessageKey(String key) {
+	return keys.contains(key);
+    }
+
+    /**
+     * Gets the number of messages bundles in this group.
+     * 
+     * @return the number of messages bundles in this group
+     */
+    @Override
+    public int getMessagesBundleCount() {
+	return localeBundles.size();
+    }
+
+    /**
+     * @see java.lang.Object#equals(java.lang.Object)
+     */
+    @Override
+    public boolean equals(Object obj) {
+	if (!(obj instanceof MessagesBundleGroup)) {
+	    return false;
+	}
+	MessagesBundleGroup messagesBundleGroup = (MessagesBundleGroup) obj;
+	return equals(localeBundles, messagesBundleGroup.localeBundles);
+    }
+
+    public final synchronized void addMessagesBundleGroupListener(
+	    final IMessagesBundleGroupListener listener) {
+	addPropertyChangeListener(listener);
+    }
+
+    public final synchronized void removeMessagesBundleGroupListener(
+	    final IMessagesBundleGroupListener listener) {
+	removePropertyChangeListener(listener);
+    }
+
+    public final synchronized IMessagesBundleGroupListener[] getMessagesBundleGroupListeners() {
+	// TODO find more efficient way to avoid class cast.
+	return Arrays.asList(getPropertyChangeListeners()).toArray(
+		EMPTY_GROUP_LISTENERS);
+    }
+
+    private void fireKeyAdded(String key) {
+	IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	for (int i = 0; i < listeners.length; i++) {
+	    IMessagesBundleGroupListener listener = listeners[i];
+	    listener.keyAdded(key);
+	}
+    }
+
+    private void fireKeyRemoved(String key) {
+	IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	for (int i = 0; i < listeners.length; i++) {
+	    IMessagesBundleGroupListener listener = listeners[i];
+	    listener.keyRemoved(key);
+	}
+    }
+
+    private void fireMessagesBundleAdded(MessagesBundle messagesBundle) {
+	IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	for (int i = 0; i < listeners.length; i++) {
+	    IMessagesBundleGroupListener listener = listeners[i];
+	    listener.messagesBundleAdded(messagesBundle);
+	}
+    }
+
+    private void fireMessagesBundleRemoved(MessagesBundle messagesBundle) {
+	IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	for (int i = 0; i < listeners.length; i++) {
+	    IMessagesBundleGroupListener listener = listeners[i];
+	    listener.messagesBundleRemoved(messagesBundle);
+	}
+    }
+
+    /**
+     * Returns true if the supplied key is already existing in this group.
+     * 
+     * @param key
+     *            The key that shall be tested.
+     * 
+     * @return true <=> The key is already existing.
+     */
+    @Override
+    public boolean containsKey(String key) {
+	for (Locale locale : localeBundles.keySet()) {
+	    IMessagesBundle messagesBundle = localeBundles.get(locale);
+	    for (String k : messagesBundle.getKeys()) {
+		if (k.equals(key)) {
+		    return true;
+		} else {
+		    continue;
+		}
+	    }
+	}
+	return false;
+    }
+
+    /**
+     * Is the given key found in this bundle group.
+     * 
+     * @param key
+     *            the key to find
+     * @return <code>true</code> if the key exists in this bundle group.
+     */
+    @Override
+    public boolean isKey(String key) {
+	return keys.contains(key);
+    }
+
+    /**
+     * Gets the unique id of the bundle group. That is usually:
+     * <directory>"."<default-filename>. The default filename is without the
+     * suffix (e.g. _en, or _en_GB).
+     * 
+     * @return The unique identifier for the resource bundle group
+     */
+    @Override
+    public String getResourceBundleId() {
+	return resourceBundleId;
+    }
+
+    /**
+     * Gets the name of the project, the resource bundle group is in.
+     * 
+     * @return The project name
+     */
+    @Override
+    public String getProjectName() {
+	return this.projectName;
+    }
+
+    /**
+     * Class listening for changes in underlying messages bundle and relays them
+     * to the listeners for MessagesBundleGroup.
+     */
+    private class MessagesBundleListener implements IMessagesBundleListener {
+	@Override
+	public void messageAdded(MessagesBundle messagesBundle, Message message) {
+	    int oldCount = keys.size();
+	    IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	    for (int i = 0; i < listeners.length; i++) {
+		IMessagesBundleGroupListener listener = listeners[i];
+		listener.messageAdded(messagesBundle, message);
+		if (getMessages(message.getKey()).length == 1) {
+		    keys.add(message.getKey());
+		    firePropertyChange(PROPERTY_KEY_COUNT, oldCount,
+			    keys.size());
+		    fireKeyAdded(message.getKey());
+		}
+	    }
+	}
+
+	@Override
+	public void messageRemoved(MessagesBundle messagesBundle,
+		Message message) {
+	    int oldCount = keys.size();
+	    IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	    for (int i = 0; i < listeners.length; i++) {
+		IMessagesBundleGroupListener listener = listeners[i];
+		listener.messageRemoved(messagesBundle, message);
+		int keyMessagesCount = getMessages(message.getKey()).length;
+		if (keyMessagesCount == 0 && keys.contains(message.getKey())) {
+		    keys.remove(message.getKey());
+		    firePropertyChange(PROPERTY_KEY_COUNT, oldCount,
+			    keys.size());
+		    fireKeyRemoved(message.getKey());
+		}
+	    }
+	}
+
+	@Override
+	public void messageChanged(MessagesBundle messagesBundle,
+		PropertyChangeEvent changeEvent) {
+	    IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	    for (int i = 0; i < listeners.length; i++) {
+		IMessagesBundleGroupListener listener = listeners[i];
+		listener.messageChanged(messagesBundle, changeEvent);
+	    }
+	}
+
+	// MessagesBundle property changes:
+	@Override
+	public void propertyChange(PropertyChangeEvent evt) {
+	    MessagesBundle bundle = (MessagesBundle) evt.getSource();
+	    IMessagesBundleGroupListener[] listeners = getMessagesBundleGroupListeners();
+	    for (int i = 0; i < listeners.length; i++) {
+		IMessagesBundleGroupListener listener = listeners[i];
+		listener.messagesBundleChanged(bundle, evt);
+	    }
+	}
+    }
+
+    /**
+     * @return <code>true</code> if the bundle group has
+     *         {@link PropertiesFileGroupStrategy} as strategy, else
+     *         <code>false</code>. This is the case, when only TapiJI edits the
+     *         resource bundles and no have been opened.
+     */
+    @Override
+    public boolean hasPropertiesFileGroupStrategy() {
+	return groupStrategy instanceof PropertiesFileGroupStrategy;
+    }
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleGroupAdapter.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleGroupAdapter.java
new file mode 100644
index 0000000..0a1a696
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/internal/MessagesBundleGroupAdapter.java
@@ -0,0 +1,81 @@
+package org.eclipse.babel.core.message.internal;
+
+import java.beans.PropertyChangeEvent;
+
+/**
+ * An adapter class for a {@link IMessagesBundleGroupListener}.  Methods 
+ * implementation do nothing.
+ * @author Pascal Essiembre (pascal@essiembre.com)
+ */
+public class MessagesBundleGroupAdapter
+        implements IMessagesBundleGroupListener {
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleGroupListener#
+     *              keyAdded(java.lang.String)
+     */
+    public void keyAdded(String key) {
+        // do nothing
+    }
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleGroupListener#
+     *              keyRemoved(java.lang.String)
+     */
+    public void keyRemoved(String key) {
+        // do nothing
+    }
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleGroupListener#
+     *      messagesBundleAdded(org.eclipse.babel.core.message.internal.MessagesBundle)
+     */
+    public void messagesBundleAdded(MessagesBundle messagesBundle) {
+        // do nothing
+    }
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleGroupListener#
+     *      messagesBundleChanged(org.eclipse.babel.core.message.internal.MessagesBundle,
+     *                            java.beans.PropertyChangeEvent)
+     */
+    public void messagesBundleChanged(MessagesBundle messagesBundle,
+            PropertyChangeEvent changeEvent) {
+        // do nothing
+    }
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleGroupListener
+     *     #messagesBundleRemoved(org.eclipse.babel.core.message.internal.MessagesBundle)
+     */
+    public void messagesBundleRemoved(MessagesBundle messagesBundle) {
+        // do nothing
+    }
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleListener#messageAdded(
+     *              org.eclipse.babel.core.message.internal.MessagesBundle,
+     *              org.eclipse.babel.core.message.internal.Message)
+     */
+    public void messageAdded(MessagesBundle messagesBundle, Message message) {
+        // do nothing
+    }
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleListener#
+     *      messageChanged(org.eclipse.babel.core.message.internal.MessagesBundle,
+     *                     java.beans.PropertyChangeEvent)
+     */
+    public void messageChanged(MessagesBundle messagesBundle,
+            PropertyChangeEvent changeEvent) {
+        // do nothing
+    }
+    /**
+     * @see org.eclipse.babel.core.message.internal.IMessagesBundleListener#
+     *      messageRemoved(org.eclipse.babel.core.message.internal.MessagesBundle,
+     *                     org.eclipse.babel.core.message.internal.Message)
+     */
+    public void messageRemoved(MessagesBundle messagesBundle, Message message) {
+        // do nothing
+    }
+    /**
+     * @see java.beans.PropertyChangeListener#propertyChange(
+     *           java.beans.PropertyChangeEvent)
+     */
+    public void propertyChange(PropertyChangeEvent evt) {
+        // do nothing
+    }
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/IMessagesEditorListener.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/IMessagesEditorListener.java
new file mode 100644
index 0000000..a3d04c5
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/IMessagesEditorListener.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.message.manager;
+
+import org.eclipse.babel.core.message.IMessagesBundle;
+
+/**
+ * Used to sync TapiJI with Babel and vice versa.
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public interface IMessagesEditorListener {
+
+	/**
+	 * Should only be called when the editor performs save!
+	 */
+	void onSave();
+	
+	/**
+	 * Can be called when the Editor changes.
+	 */
+	void onModify();
+	
+	/**
+	 * Called when a {@link IMessagesBundle} changed.
+	 * @param bundle
+	 */
+	void onResourceChanged(IMessagesBundle bundle);
+	// TODO: Get rid of this method, maybe merge with onModify()
+	
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/IResourceDeltaListener.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/IResourceDeltaListener.java
new file mode 100644
index 0000000..fba2d0f
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/IResourceDeltaListener.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.message.manager;
+
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.core.resources.IResource;
+
+
+/**
+ * Used to update TapiJI (ResourceBundleManager) when bundles have been removed.
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public interface IResourceDeltaListener {
+
+	/**
+	 * Called when a resource (= bundle) has been removed
+	 * @param resourceBundleId The {@link IMessagesBundleGroup} which contains the bundle
+	 * @param resource The resource itself
+	 */
+	public void onDelete(String resourceBundleId, IResource resource);
+	
+	/**
+	 * Called when a {@link IMessagesBundleGroup} has been removed
+	 * @param bundleGroup The removed bundle group
+	 */
+	public void onDelete(IMessagesBundleGroup bundleGroup);
+	
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/RBManager.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/RBManager.java
new file mode 100644
index 0000000..0cb5378
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/RBManager.java
@@ -0,0 +1,561 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.message.manager;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.eclipse.babel.core.configuration.DirtyHack;
+import org.eclipse.babel.core.factory.MessagesBundleGroupFactory;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.Message;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.util.FileUtils;
+import org.eclipse.babel.core.util.NameUtils;
+import org.eclipse.babel.core.util.PDEUtils;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * Manages all {@link MessagesBundleGroup}s. That is: <li>Hold map with projects
+ * and their RBManager (1 RBManager per project)</li> <li>Hold up-to-date map
+ * with resource bundles (= {@link MessagesBundleGroup})</li> <li>Hold
+ * {@link IMessagesEditorListener}, which can be used to keep systems in sync</li>
+ * <br>
+ * <br>
+ * 
+ * @author Alexej Strelzow
+ */
+public class RBManager {
+
+    private static Map<IProject, RBManager> managerMap = new HashMap<IProject, RBManager>();
+
+    /** <package>.<resourceBundleName> , IMessagesBundleGroup */
+    private Map<String, IMessagesBundleGroup> resourceBundles;
+
+    private static RBManager INSTANCE;
+
+    private List<IMessagesEditorListener> editorListeners;
+
+    private List<IResourceDeltaListener> resourceListeners;
+
+    private IProject project;
+
+    private static final String TAPIJI_NATURE = "org.eclipse.babel.tapiji.tools.core.ui.nature";
+
+    private static Logger logger = Logger.getLogger(RBManager.class
+	    .getSimpleName());
+
+    private RBManager() {
+	resourceBundles = new HashMap<String, IMessagesBundleGroup>();
+	editorListeners = new ArrayList<IMessagesEditorListener>(3);
+	resourceListeners = new ArrayList<IResourceDeltaListener>(2);
+    }
+
+    /**
+     * @param resourceBundleId
+     *            <package>.<resourceBundleName>
+     * @return {@link IMessagesBundleGroup} if found, else <code>null</code>
+     */
+    public IMessagesBundleGroup getMessagesBundleGroup(String resourceBundleId) {
+	if (!resourceBundles.containsKey(resourceBundleId)) {
+	    logger.log(Level.SEVERE,
+		    "getMessagesBundleGroup with non-existing Id: "
+			    + resourceBundleId);
+	    return null;
+	} else {
+	    return resourceBundles.get(resourceBundleId);
+	}
+    }
+
+    /**
+     * @return All the names of the <code>resourceBundles</code> in the format:
+     *         <projectName>/<resourceBundleId>
+     */
+    public List<String> getMessagesBundleGroupNames() {
+	List<String> bundleGroupNames = new ArrayList<String>();
+
+	for (String key : resourceBundles.keySet()) {
+	    bundleGroupNames.add(project.getName() + "/" + key);
+	}
+	return bundleGroupNames;
+    }
+
+    /**
+     * @return All the {@link #getMessagesBundleGroupNames()} of all the
+     *         projects.
+     */
+    public static List<String> getAllMessagesBundleGroupNames() {
+	List<String> bundleGroupNames = new ArrayList<String>();
+
+	for (IProject project : getAllSupportedProjects()) {
+	    RBManager manager = getInstance(project);
+	    for (String name : manager.getMessagesBundleGroupNames()) {
+		if (!bundleGroupNames.contains(name)) {
+		    bundleGroupNames.add(name);
+		}
+	    }
+	}
+	return bundleGroupNames;
+    }
+
+    /**
+     * Notification, that a {@link IMessagesBundleGroup} has been created and
+     * needs to be managed by the {@link RBManager}.
+     * 
+     * @param bundleGroup
+     *            The new {@link IMessagesBundleGroup}
+     */
+    public void notifyMessagesBundleGroupCreated(
+	    IMessagesBundleGroup bundleGroup) {
+	if (resourceBundles.containsKey(bundleGroup.getResourceBundleId())) {
+	    IMessagesBundleGroup oldbundleGroup = resourceBundles
+		    .get(bundleGroup.getResourceBundleId());
+
+	    // not the same object
+	    if (!equalHash(oldbundleGroup, bundleGroup)) {
+		// we need to distinguish between 2 kinds of resources:
+		// 1) Property-File
+		// 2) Eclipse-Editor
+		// When first 1) is used, and some operations where made, we
+		// need to
+		// sync 2) when it appears!
+		boolean oldHasPropertiesStrategy = oldbundleGroup
+			.hasPropertiesFileGroupStrategy();
+		boolean newHasPropertiesStrategy = bundleGroup
+			.hasPropertiesFileGroupStrategy();
+
+		// in this case, the old one is only writing to the property
+		// file, not the editor
+		// we have to sync them and store the bundle with the editor as
+		// resource
+		if (oldHasPropertiesStrategy && !newHasPropertiesStrategy) {
+
+		    syncBundles(bundleGroup, oldbundleGroup);
+		    resourceBundles.put(bundleGroup.getResourceBundleId(),
+			    bundleGroup);
+
+		    logger.log(
+			    Level.INFO,
+			    "sync: " + bundleGroup.getResourceBundleId()
+				    + " with "
+				    + oldbundleGroup.getResourceBundleId());
+
+		    oldbundleGroup.dispose();
+
+		} else if ((oldHasPropertiesStrategy && newHasPropertiesStrategy)
+			|| (!oldHasPropertiesStrategy && !newHasPropertiesStrategy)) {
+
+		    // syncBundles(oldbundleGroup, bundleGroup); do not need
+		    // that, because we take the new one
+		    // and we do that, because otherwise we cache old
+		    // Text-Editor instances, which we
+		    // do not need -> read only phenomenon
+		    resourceBundles.put(bundleGroup.getResourceBundleId(),
+			    bundleGroup);
+
+		    logger.log(
+			    Level.INFO,
+			    "replace: " + bundleGroup.getResourceBundleId()
+				    + " with "
+				    + oldbundleGroup.getResourceBundleId());
+
+		    oldbundleGroup.dispose();
+		} else {
+		    // in this case our old resource has an EditorSite, but not
+		    // the new one
+		    logger.log(Level.INFO,
+			    "dispose: " + bundleGroup.getResourceBundleId());
+
+		    bundleGroup.dispose();
+		}
+	    }
+	} else {
+	    resourceBundles.put(bundleGroup.getResourceBundleId(), bundleGroup);
+
+	    logger.log(Level.INFO, "add: " + bundleGroup.getResourceBundleId());
+	}
+    }
+
+    /**
+     * Notification, that a {@link IMessagesBundleGroup} has been deleted!
+     * 
+     * @param bundleGroup
+     *            The {@link IMessagesBundleGroup} to remove
+     */
+    public void notifyMessagesBundleGroupDeleted(
+	    IMessagesBundleGroup bundleGroup) {
+	if (resourceBundles.containsKey(bundleGroup.getResourceBundleId())) {
+	    if (equalHash(
+		    resourceBundles.get(bundleGroup.getResourceBundleId()),
+		    bundleGroup)) {
+		resourceBundles.remove(bundleGroup.getResourceBundleId());
+
+		for (IResourceDeltaListener deltaListener : resourceListeners) {
+		    deltaListener.onDelete(bundleGroup);
+		}
+	    }
+	}
+    }
+
+    /**
+     * Notification, that a resource bundle (= {@link MessagesBundle}) have been
+     * removed.
+     * 
+     * @param resourceBundle
+     *            The removed {@link MessagesBundle}
+     */
+    public void notifyResourceRemoved(IResource resourceBundle) {
+	String resourceBundleId = NameUtils.getResourceBundleId(resourceBundle);
+
+	IMessagesBundleGroup bundleGroup = resourceBundles
+		.get(resourceBundleId);
+
+	if (bundleGroup != null) {
+	    Locale locale = NameUtils.getLocaleByName(
+		    NameUtils.getResourceBundleName(resourceBundle),
+		    resourceBundle.getName());
+	    IMessagesBundle messagesBundle = bundleGroup
+		    .getMessagesBundle(locale);
+	    if (messagesBundle != null) {
+		bundleGroup.removeMessagesBundle(messagesBundle);
+	    }
+
+	    for (IResourceDeltaListener deltaListener : resourceListeners) {
+		deltaListener.onDelete(resourceBundleId, resourceBundle);
+	    }
+
+	    if (bundleGroup.getMessagesBundleCount() == 0) {
+		notifyMessagesBundleGroupDeleted(bundleGroup);
+	    }
+	}
+
+	// TODO: maybe save and reinit the editor?
+
+    }
+
+    /**
+     * Because BABEL-Builder does not work correctly (adds 1 x and removes 2 x
+     * the SAME {@link MessagesBundleGroup}!)
+     * 
+     * @param oldBundleGroup
+     *            {@link IMessagesBundleGroup}
+     * @param newBundleGroup
+     *            {@link IMessagesBundleGroup}
+     * @return <code>true</code> if same {@link IMessagesBundleGroup}, else
+     *         <code>false</code>
+     */
+    private boolean equalHash(IMessagesBundleGroup oldBundleGroup,
+	    IMessagesBundleGroup newBundleGroup) {
+	return oldBundleGroup.hashCode() == newBundleGroup.hashCode();
+    }
+
+    /**
+     * Has only one use case. If we worked with property-file as resource and
+     * afterwards the messages editor pops open, we need to sync them, so that
+     * the information of the property-file won't get lost.
+     * 
+     * @param oldBundleGroup
+     *            The prior {@link IMessagesBundleGroup}
+     * @param newBundleGroup
+     *            The replacement
+     */
+    private void syncBundles(IMessagesBundleGroup oldBundleGroup,
+	    IMessagesBundleGroup newBundleGroup) {
+	List<IMessagesBundle> bundlesToRemove = new ArrayList<IMessagesBundle>();
+	List<IMessage> keysToRemove = new ArrayList<IMessage>();
+
+	DirtyHack.setFireEnabled(false); // hebelt AbstractMessageModel aus
+	// sonst m�ssten wir in setText von EclipsePropertiesEditorResource
+	// ein
+	// asyncExec zulassen
+
+	for (IMessagesBundle newBundle : newBundleGroup.getMessagesBundles()) {
+	    IMessagesBundle oldBundle = oldBundleGroup
+		    .getMessagesBundle(newBundle.getLocale());
+	    if (oldBundle == null) { // it's a new one
+		oldBundleGroup.addMessagesBundle(newBundle.getLocale(),
+			newBundle);
+	    } else { // check keys
+		for (IMessage newMsg : newBundle.getMessages()) {
+		    if (oldBundle.getMessage(newMsg.getKey()) == null) {
+			// new entry, create new message
+			oldBundle.addMessage(new Message(newMsg.getKey(),
+				newMsg.getLocale()));
+		    } else { // update old entries
+			IMessage oldMsg = oldBundle.getMessage(newMsg.getKey());
+			if (oldMsg == null) { // it's a new one
+			    oldBundle.addMessage(newMsg);
+			} else { // check value
+			    oldMsg.setComment(newMsg.getComment());
+			    oldMsg.setText(newMsg.getValue());
+			}
+		    }
+		}
+	    }
+	}
+
+	// check keys
+	for (IMessagesBundle oldBundle : oldBundleGroup.getMessagesBundles()) {
+	    IMessagesBundle newBundle = newBundleGroup
+		    .getMessagesBundle(oldBundle.getLocale());
+	    if (newBundle == null) { // we have an old one
+		bundlesToRemove.add(oldBundle);
+	    } else {
+		for (IMessage oldMsg : oldBundle.getMessages()) {
+		    if (newBundle.getMessage(oldMsg.getKey()) == null) {
+			keysToRemove.add(oldMsg);
+		    }
+		}
+	    }
+	}
+
+	for (IMessagesBundle bundle : bundlesToRemove) {
+	    oldBundleGroup.removeMessagesBundle(bundle);
+	}
+
+	for (IMessage msg : keysToRemove) {
+	    IMessagesBundle mb = oldBundleGroup.getMessagesBundle(msg
+		    .getLocale());
+	    if (mb != null) {
+		mb.removeMessage(msg.getKey());
+	    }
+	}
+
+	DirtyHack.setFireEnabled(true);
+
+    }
+
+    /**
+     * If TapiJI needs to delete sth.
+     * 
+     * @param resourceBundleId
+     *            The resourceBundleId
+     */
+    public void deleteMessagesBundleGroup(String resourceBundleId) {
+	// TODO: Try to unify it some time
+	if (resourceBundles.containsKey(resourceBundleId)) {
+	    resourceBundles.remove(resourceBundleId);
+	} else {
+	    logger.log(Level.SEVERE,
+		    "deleteMessagesBundleGroup with non-existing Id: "
+			    + resourceBundleId);
+	}
+    }
+
+    /**
+     * @param resourceBundleId
+     *            The resourceBundleId
+     * @return <code>true</code> if the manager knows the
+     *         {@link MessagesBundleGroup} with the id resourceBundleId
+     */
+    public boolean containsMessagesBundleGroup(String resourceBundleId) {
+	return resourceBundles.containsKey(resourceBundleId);
+    }
+
+    /**
+     * @param project
+     *            The project, which is managed by the {@link RBManager}
+     * @return The corresponding {@link RBManager} to the project
+     */
+    public static RBManager getInstance(IProject project) {
+	// set host-project
+	if (PDEUtils.isFragment(project)) {
+	    project = PDEUtils.getFragmentHost(project);
+	}
+
+	INSTANCE = managerMap.get(project);
+
+	if (INSTANCE == null) {
+	    INSTANCE = new RBManager();
+	    INSTANCE.project = project;
+	    managerMap.put(project, INSTANCE);
+	    INSTANCE.detectResourceBundles();
+	}
+
+	return INSTANCE;
+    }
+
+    /**
+     * @param projectName
+     *            The name of the project, which is managed by the
+     *            {@link RBManager}
+     * @return The corresponding {@link RBManager} to the project
+     */
+    public static RBManager getInstance(String projectName) {
+	for (IProject project : getAllWorkspaceProjects(true)) {
+	    if (project.getName().equals(projectName)) {
+		// check if the projectName is a fragment and return the manager
+		// for the host
+		if (PDEUtils.isFragment(project)) {
+		    return getInstance(PDEUtils.getFragmentHost(project));
+		} else {
+		    return getInstance(project);
+		}
+	    }
+	}
+	return null;
+    }
+
+    /**
+     * @param ignoreNature
+     *            <code>true</code> if the internationalization nature should be
+     *            ignored, else <code>false</code>
+     * @return A set of projects, which have the nature (ignoreNature == false)
+     *         or not.
+     */
+    public static Set<IProject> getAllWorkspaceProjects(boolean ignoreNature) {
+	IProject[] projects = ResourcesPlugin.getWorkspace().getRoot()
+		.getProjects();
+	Set<IProject> projs = new HashSet<IProject>();
+
+	for (IProject p : projects) {
+	    try {
+		if (p.isOpen() && (ignoreNature || p.hasNature(TAPIJI_NATURE))) {
+		    projs.add(p);
+		}
+	    } catch (CoreException e) {
+		logger.log(Level.SEVERE,
+			"getAllWorkspaceProjects(...): hasNature failed!", e);
+	    }
+	}
+	return projs;
+    }
+
+    /**
+     * @return All supported projects, those who have the correct nature.
+     */
+    public static Set<IProject> getAllSupportedProjects() {
+	return getAllWorkspaceProjects(false);
+    }
+
+    /**
+     * @param listener
+     *            {@link IMessagesEditorListener} to add
+     */
+    public void addMessagesEditorListener(IMessagesEditorListener listener) {
+	this.editorListeners.add(listener);
+    }
+
+    /**
+     * @param listener
+     *            {@link IMessagesEditorListener} to remove
+     */
+    public void removeMessagesEditorListener(IMessagesEditorListener listener) {
+	this.editorListeners.remove(listener);
+    }
+
+    /**
+     * @param listener
+     *            {@link IResourceDeltaListener} to add
+     */
+    public void addResourceDeltaListener(IResourceDeltaListener listener) {
+	this.resourceListeners.add(listener);
+    }
+
+    /**
+     * @param listener
+     *            {@link IResourceDeltaListener} to remove
+     */
+    public void removeResourceDeltaListener(IResourceDeltaListener listener) {
+	this.resourceListeners.remove(listener);
+    }
+
+    /**
+     * Fire: MessagesEditor has been saved
+     */
+    public void fireEditorSaved() {
+	for (IMessagesEditorListener listener : this.editorListeners) {
+	    listener.onSave();
+	}
+	logger.log(Level.INFO, "fireEditorSaved");
+    }
+
+    /**
+     * Fire: MessagesEditor has been modified
+     */
+    public void fireEditorChanged() {
+	for (IMessagesEditorListener listener : this.editorListeners) {
+	    listener.onModify();
+	}
+	logger.log(Level.INFO, "fireEditorChanged");
+    }
+
+    /**
+     * Fire: {@link IMessagesBundle} has been edited
+     */
+    public void fireResourceChanged(IMessagesBundle bundle) {
+	for (IMessagesEditorListener listener : this.editorListeners) {
+	    listener.onResourceChanged(bundle);
+	    logger.log(Level.INFO, "fireResourceChanged"
+		    + bundle.getResource().getResourceLocationLabel());
+	}
+    }
+
+    /**
+     * Detects all resource bundles, which we want to work with.
+     */
+    protected void detectResourceBundles() {
+	try {
+	    project.accept(new ResourceBundleDetectionVisitor(this));
+
+	    IProject[] fragments = PDEUtils.lookupFragment(project);
+	    if (fragments != null) {
+		for (IProject p : fragments) {
+		    p.accept(new ResourceBundleDetectionVisitor(this));
+		}
+
+	    }
+	} catch (CoreException e) {
+	    logger.log(Level.SEVERE, "detectResourceBundles: accept failed!", e);
+	}
+    }
+
+    // passive loading -> see detectResourceBundles
+    /**
+     * Invoked by {@link #detectResourceBundles()}.
+     */
+    public void addBundleResource(IResource resource) {
+	// create it with MessagesBundleFactory or read from resource!
+	// we can optimize that, now we create a bundle group for each bundle
+	// we should create a bundle group only once!
+
+	String resourceBundleId = NameUtils.getResourceBundleId(resource);
+	if (!resourceBundles.containsKey(resourceBundleId)) {
+	    // if we do not have this condition, then you will be doomed with
+	    // resource out of syncs, because here we instantiate
+	    // PropertiesFileResources, which have an evil setText-Method
+	    MessagesBundleGroupFactory.createBundleGroup(resource);
+
+	    logger.log(Level.INFO, "addBundleResource (passive loading): "
+		    + resource.getName());
+	}
+    }
+
+    public void writeToFile(IMessagesBundleGroup bundleGroup) {
+	for (IMessagesBundle bundle : bundleGroup.getMessagesBundles()) {
+	    FileUtils.writeToFile(bundle);
+	    fireResourceChanged(bundle);
+	}
+    }
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/ResourceBundleDetectionVisitor.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/ResourceBundleDetectionVisitor.java
new file mode 100644
index 0000000..125c34a
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/manager/ResourceBundleDetectionVisitor.java
@@ -0,0 +1,160 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer, Alexej Strelzow.
+ * 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:
+ *     Martin Reiterer - initial API and implementation
+ *     Alexej Strelzow - detection if isResourceBundleFile
+ ******************************************************************************/
+
+package org.eclipse.babel.core.message.manager;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import org.eclipse.babel.core.configuration.ConfigurationManager;
+import org.eclipse.babel.core.configuration.IConfiguration;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.runtime.CoreException;
+
+public class ResourceBundleDetectionVisitor implements IResourceVisitor,
+	IResourceDeltaVisitor {
+
+    private RBManager manager = null;
+
+    public ResourceBundleDetectionVisitor(RBManager manager) {
+	this.manager = manager;
+    }
+
+    public boolean visit(IResource resource) throws CoreException {
+	try {
+	    if (isResourceBundleFile(resource)) {
+		manager.addBundleResource(resource);
+		return false;
+	    } else
+		return true;
+	} catch (Exception e) {
+	    e.printStackTrace();
+	    return false;
+	}
+    }
+
+    public boolean visit(IResourceDelta delta) throws CoreException {
+	IResource resource = delta.getResource();
+
+	if (isResourceBundleFile(resource)) {
+	    // ResourceBundleManager.getManager(resource.getProject()).bundleResourceModified(delta);
+	    return false;
+	}
+
+	return true;
+    }
+
+    private final String RB_MARKER_ID = "org.eclipse.babel.tapiji.tools.core.ResourceBundleAuditMarker";
+
+    private boolean isResourceBundleFile(IResource file) {
+	boolean isValied = false;
+
+	if (file != null && file instanceof IFile && !file.isDerived()
+		&& file.getFileExtension() != null
+		&& file.getFileExtension().equalsIgnoreCase("properties")) {
+	    isValied = true;
+
+	    List<CheckItem> list = getBlacklistItems();
+	    for (CheckItem item : list) {
+		if (item.getChecked()
+			&& file.getFullPath().toString()
+				.matches(item.getName())) {
+		    isValied = false;
+
+		    // if properties-file is not RB-file and has
+		    // ResouceBundleMarker, deletes all ResouceBundleMarker of
+		    // the file
+		    if (hasResourceBundleMarker(file))
+			try {
+			    file.deleteMarkers(RB_MARKER_ID, true,
+				    IResource.DEPTH_INFINITE);
+			} catch (CoreException e) {
+			}
+		}
+	    }
+	}
+
+	return isValied;
+    }
+
+    private List<CheckItem> getBlacklistItems() {
+	IConfiguration configuration = ConfigurationManager.getInstance()
+		.getConfiguration();
+	if (configuration != null) {
+	    return convertStringToList(configuration.getNonRbPattern());
+	} else {
+	    return new ArrayList<CheckItem>();
+	}
+    }
+
+    private static final String DELIMITER = ";";
+    private static final String ATTRIBUTE_DELIMITER = ":";
+
+    private List<CheckItem> convertStringToList(String string) {
+	StringTokenizer tokenizer = new StringTokenizer(string, DELIMITER);
+	int tokenCount = tokenizer.countTokens();
+	List<CheckItem> elements = new LinkedList<CheckItem>();
+
+	for (int i = 0; i < tokenCount; i++) {
+	    StringTokenizer attribute = new StringTokenizer(
+		    tokenizer.nextToken(), ATTRIBUTE_DELIMITER);
+	    String name = attribute.nextToken();
+	    boolean checked;
+	    if (attribute.nextToken().equals("true"))
+		checked = true;
+	    else
+		checked = false;
+
+	    elements.add(new CheckItem(name, checked));
+	}
+	return elements;
+    }
+
+    /**
+     * Checks whether a RB-file has a problem-marker
+     */
+    public boolean hasResourceBundleMarker(IResource r) {
+	try {
+	    if (r.findMarkers(RB_MARKER_ID, true, IResource.DEPTH_INFINITE).length > 0)
+		return true;
+	    else
+		return false;
+	} catch (CoreException e) {
+	    return false;
+	}
+    }
+
+    private class CheckItem {
+	boolean checked;
+	String name;
+
+	public CheckItem(String item, boolean checked) {
+	    this.name = item;
+	    this.checked = checked;
+	}
+
+	public String getName() {
+	    return name;
+	}
+
+	public boolean getChecked() {
+	    return checked;
+	}
+    }
+
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/IMessagesResource.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/IMessagesResource.java
index 74b5e3f..ca16df4 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/IMessagesResource.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/IMessagesResource.java
@@ -12,56 +12,75 @@
 
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.IMessagesResourceChangeListener;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 
 /**
  * Class abstracting the underlying native storage mechanism for persisting
- * internationalised text messages.  
+ * internationalised text messages.
+ * 
  * @author Pascal Essiembre
  */
 public interface IMessagesResource {
 
 	/**
 	 * Gets the resource locale.
+	 * 
 	 * @return locale
 	 */
-    Locale getLocale();
-    /**
-     * Gets the underlying object abstracted by this resource (e.g. a File).
-     * @return source object
-     */
-    Object getSource();
-    /**
-     * Serializes a {@link MessagesBundle} instance to its native format.
-     * @param messagesBundle the MessagesBundle to serialize
-     */
-    void serialize(MessagesBundle messagesBundle);
-    /**
-     * Deserializes a {@link MessagesBundle} instance from its native format.
-     * @param messagesBundle the MessagesBundle to deserialize
-     */
-    void deserialize(MessagesBundle messagesBundle);
-    /**
-     * Adds a messages resource listener.  Implementors are required to notify
-     * listeners of changes within the native implementation.
-     * @param listener the listener
-     */
-    void addMessagesResourceChangeListener(
-    		IMessagesResourceChangeListener listener);
-    /**
-     * Removes a messages resource listener.
-     * @param listener the listener
-     */
-    void removeMessagesResourceChangeListener(
-    		IMessagesResourceChangeListener listener);
-    /**
-     * @return The resource location label. or null if unknown.
-     */
-    String getResourceLocationLabel();
-    
-    /**
-     * Called when the group it belongs to is disposed.
-     */
-    void dispose();
-    
+	Locale getLocale();
+
+	/**
+	 * Gets the underlying object abstracted by this resource (e.g. a File).
+	 * 
+	 * @return source object
+	 */
+	Object getSource();
+
+	/**
+	 * Serializes a {@link MessagesBundle} instance to its native format.
+	 * 
+	 * @param messagesBundle
+	 *            the MessagesBundle to serialize
+	 */
+	void serialize(IMessagesBundle messagesBundle);
+
+	/**
+	 * Deserializes a {@link MessagesBundle} instance from its native format.
+	 * 
+	 * @param messagesBundle
+	 *            the MessagesBundle to deserialize
+	 */
+	void deserialize(IMessagesBundle messagesBundle);
+
+	/**
+	 * Adds a messages resource listener. Implementors are required to notify
+	 * listeners of changes within the native implementation.
+	 * 
+	 * @param listener
+	 *            the listener
+	 */
+	void addMessagesResourceChangeListener(
+	        IMessagesResourceChangeListener listener);
+
+	/**
+	 * Removes a messages resource listener.
+	 * 
+	 * @param listener
+	 *            the listener
+	 */
+	void removeMessagesResourceChangeListener(
+	        IMessagesResourceChangeListener listener);
+
+	/**
+	 * @return The resource location label. or null if unknown.
+	 */
+	String getResourceLocationLabel();
+
+	/**
+	 * Called when the group it belongs to is disposed.
+	 */
+	void dispose();
+
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesFileResource.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesFileResource.java
deleted file mode 100644
index 8ca977c..0000000
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesFileResource.java
+++ /dev/null
@@ -1,160 +0,0 @@
-/*******************************************************************************
- * 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.core.message.resource;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.Locale;
-
-import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
-import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
-import org.eclipse.babel.core.util.FileChangeListener;
-import org.eclipse.babel.core.util.FileMonitor;
-
-
-/**
- * Properties file, where the underlying storage is a regular {@link File}.
- * For files referenced through Eclipse workspace, implementors should
- * use {@link PropertiesIFileResource}.
- * 
- * @author Pascal Essiembre
- * @see PropertiesIFileResource
- */
-public class PropertiesFileResource extends AbstractPropertiesResource {
-
-    private File file;
-    
-    /**
-     * Constructor.
-     * @param locale the resource locale
-     * @param serializer resource serializer
-     * @param deserializer resource deserializer
-     * @param file the underlying file
-     * @throws FileNotFoundException 
-     */
-    public PropertiesFileResource(
-            Locale locale,
-            PropertiesSerializer serializer,
-            PropertiesDeserializer deserializer,
-            File file) throws FileNotFoundException {
-        super(locale, serializer, deserializer);
-        this.file = file;
-        FileMonitor.getInstance().addFileChangeListener(new FileChangeListener() {
-            public void fileChanged(final File changedFile) {
-                fireResourceChange(PropertiesFileResource.this);
-            }
-        }, file, 2000);  //TODO make file scan delay configurable
-    }
-
-    
-    /**
-     * @see org.eclipse.babel.core.message.resource.AbstractPropertiesResource
-     * 			#getText()
-     */
-    public String getText() {
-        FileReader inputStream = null;
-        StringWriter outputStream = null;
-        try {
-            inputStream = new FileReader(file);
-            outputStream = new StringWriter();
-            int c;
-            while ((c = inputStream.read()) != -1) {
-                outputStream.write(c);
-            }
-        } catch (IOException e) {
-            //TODO handle better.
-            throw new RuntimeException(
-                    "Cannot get properties file text. Handle better.", e);
-        } finally {
-            closeReader(inputStream);
-            closeWriter(outputStream);
-        }
-        return outputStream.toString();
-    }
-
-    /**
-     * @see org.eclipse.babel.core.message.resource.AbstractPropertiesResource
-     * 		#setText(java.lang.String)
-     */
-    public void setText(String content) {
-        StringReader inputStream = null;
-        FileWriter outputStream = null;
-        try {
-            inputStream = new StringReader(content);
-            outputStream = new FileWriter(file);
-            int c;
-            while ((c = inputStream.read()) != -1) {
-                outputStream.write(c);
-            }
-        } catch (IOException e) {
-            //TODO handle better.
-            throw new RuntimeException(
-                    "Cannot get properties file text. Handle better.", e);
-        } finally {
-            closeReader(inputStream);
-            closeWriter(outputStream);
-        }
-    }
-
-    /**
-     * @see org.eclipse.babel.core.message.resource
-     * 			.IMessagesResource#getSource()
-     */
-    public Object getSource() {
-        return file;
-    }
-    
-    /**
-     * @return The resource location label. or null if unknown.
-     */
-    public String getResourceLocationLabel() {
-    	return file.getAbsolutePath();
-    }
-    
-    //TODO move to util class for convinience???
-    private void closeWriter(Writer writer) {
-        if (writer != null) {
-            try {
-                writer.close();
-            } catch (IOException e) {
-                //TODO handle better.
-                throw new RuntimeException("Cannot close writer stream.", e);
-            }
-        }
-    }
-    
-    //TODO move to util class for convinience???
-    public void closeReader(Reader reader) {
-        if (reader != null) {
-            try {
-                reader.close();
-            } catch (IOException e) {
-                //TODO handle better.
-                throw new RuntimeException("Cannot close reader.", e);
-            }
-        }
-    }
-    
-    /**
-     * Called before this object will be discarded.
-     * Nothing to do: we were not listening to changes to this file.
-     */
-    public void dispose() {
-    	//nothing to do.
-    }
-}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/AbstractMessagesResource.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/AbstractMessagesResource.java
similarity index 83%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/AbstractMessagesResource.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/AbstractMessagesResource.java
index d5249af..3f18992 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/AbstractMessagesResource.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/AbstractMessagesResource.java
@@ -8,12 +8,15 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.resource;
+package org.eclipse.babel.core.message.resource.internal;
 
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
 
+import org.eclipse.babel.core.message.IMessagesResourceChangeListener;
+import org.eclipse.babel.core.message.resource.IMessagesResource;
+
 /**
  * Base implementation of a {@link IMessagesResource} bound to a locale
  * and providing ways to add and remove {@link IMessagesResourceChangeListener}
@@ -42,7 +45,7 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.resource.IMessagesResource#
+     * @see org.eclipse.babel.core.message.internal.resource.IMessagesResource#
      *          addMessagesResourceChangeListener(
      *          		org.eclipse.babel.core.message.resource
      *                  		.IMessagesResourceChangeListener)
@@ -52,10 +55,9 @@
         listeners.add(0, listener);
     }
     /**
-     * @see org.eclipse.babel.core.message.resource.IMessagesResource#
+     * @see org.eclipse.babel.core.message.internal.resource.IMessagesResource#
      *          removeMessagesResourceChangeListener(
-     *          		org.eclipse.babel.core.message
-     *                  		.resource.IMessagesResourceChangeListener)
+     *          		org.eclipse.babel.core.message.resource.IMessagesResourceChangeListener)
      */
     public void removeMessagesResourceChangeListener(
             IMessagesResourceChangeListener listener) {
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/AbstractPropertiesResource.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/AbstractPropertiesResource.java
similarity index 78%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/AbstractPropertiesResource.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/AbstractPropertiesResource.java
index a9865de..ff90add 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/AbstractPropertiesResource.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/AbstractPropertiesResource.java
@@ -8,12 +8,12 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.resource;
+package org.eclipse.babel.core.message.resource.internal;
 
 import java.util.Locale;
 import java.util.Properties;
 
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.IMessagesBundle;
 import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
 import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
 
@@ -47,18 +47,18 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.resource.IMessagesResource#serialize(
-     *              org.eclipse.babel.core.message.MessagesBundle)
+     * @see org.eclipse.babel.core.message.internal.resource.IMessagesResource#serialize(
+     *              org.eclipse.babel.core.message.internal.MessagesBundle)
      */
-    public void serialize(MessagesBundle messagesBundle) {
+    public void serialize(IMessagesBundle messagesBundle) {
         setText(serializer.serialize(messagesBundle));
     }
 
     /**
-     * @see org.eclipse.babel.core.message.resource.IMessagesResource
-     * 		#deserialize(org.eclipse.babel.core.message.MessagesBundle)
+     * @see org.eclipse.babel.core.message.internal.resource.IMessagesResource
+     * 		#deserialize(org.eclipse.babel.core.message.internal.MessagesBundle)
      */
-    public void deserialize(MessagesBundle messagesBundle) {
+    public void deserialize(IMessagesBundle messagesBundle) {
         deserializer.deserialize(messagesBundle, getText());
     }
 
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesFileResource.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesFileResource.java
new file mode 100644
index 0000000..6c3dd58
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesFileResource.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * 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.core.message.resource.internal;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Locale;
+
+import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
+import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
+import org.eclipse.babel.core.util.FileChangeListener;
+import org.eclipse.babel.core.util.FileMonitor;
+
+/**
+ * Properties file, where the underlying storage is a regular {@link File}. For
+ * files referenced through Eclipse workspace, implementors should use
+ * {@link PropertiesIFileResource}.
+ * 
+ * @author Pascal Essiembre
+ * @see PropertiesIFileResource
+ */
+public class PropertiesFileResource extends AbstractPropertiesResource {
+
+    private File file;
+
+    private FileChangeListenerImpl fileChangeListener;
+
+    /**
+     * Constructor.
+     * 
+     * @param locale
+     *            the resource locale
+     * @param serializer
+     *            resource serializer
+     * @param deserializer
+     *            resource deserializer
+     * @param file
+     *            the underlying file
+     * @throws FileNotFoundException
+     */
+    public PropertiesFileResource(Locale locale,
+	    PropertiesSerializer serializer,
+	    PropertiesDeserializer deserializer, File file)
+	    throws FileNotFoundException {
+	super(locale, serializer, deserializer);
+	this.file = file;
+	this.fileChangeListener = new FileChangeListenerImpl();
+
+	FileMonitor.getInstance().addFileChangeListener(
+		this.fileChangeListener, file, 2000); // TODO make file scan
+						      // delay configurable
+    }
+
+    /**
+     * @see org.eclipse.babel.core.message.internal.resource.AbstractPropertiesResource
+     *      #getText()
+     */
+    @Override
+    public String getText() {
+	FileReader inputStream = null;
+	StringWriter outputStream = null;
+	try {
+	    if (!file.exists()) {
+		return "";
+	    }
+	    inputStream = new FileReader(file);
+	    outputStream = new StringWriter();
+	    int c;
+	    while ((c = inputStream.read()) != -1) {
+		outputStream.write(c);
+	    }
+	} catch (IOException e) {
+	    // TODO handle better.
+	    throw new RuntimeException(
+		    "Cannot get properties file text. Handle better.", e);
+	} finally {
+	    closeReader(inputStream);
+	    closeWriter(outputStream);
+	}
+	return outputStream.toString();
+    }
+
+    /**
+     * @see org.eclipse.babel.core.message.internal.resource.AbstractPropertiesResource
+     *      #setText(java.lang.String)
+     */
+    @Override
+    public void setText(String content) {
+	StringReader inputStream = null;
+	FileWriter outputStream = null;
+	try {
+	    inputStream = new StringReader(content);
+	    outputStream = new FileWriter(file);
+	    int c;
+	    while ((c = inputStream.read()) != -1) {
+		outputStream.write(c);
+	    }
+	} catch (IOException e) {
+	    // TODO handle better.
+	    throw new RuntimeException(
+		    "Cannot get properties file text. Handle better.", e);
+	} finally {
+	    closeReader(inputStream);
+	    closeWriter(outputStream);
+
+	    // IFile file =
+	    // ResourcesPlugin.getWorkspace().getRoot().getFileForLocation( new
+	    // Path(getResourceLocationLabel()));
+	    // try {
+	    // file.refreshLocal(IResource.DEPTH_ZERO, null);
+	    // } catch (CoreException e) {
+	    // // TODO Auto-generated catch block
+	    // e.printStackTrace();
+	    // }
+	}
+    }
+
+    /**
+     * @see org.eclipse.babel.core.message.internal.resource
+     *      .IMessagesResource#getSource()
+     */
+    @Override
+    public Object getSource() {
+	return file;
+    }
+
+    /**
+     * @return The resource location label. or null if unknown.
+     */
+    @Override
+    public String getResourceLocationLabel() {
+	return file.getAbsolutePath();
+    }
+
+    // TODO move to util class for convinience???
+    private void closeWriter(Writer writer) {
+	if (writer != null) {
+	    try {
+		writer.close();
+	    } catch (IOException e) {
+		// TODO handle better.
+		throw new RuntimeException("Cannot close writer stream.", e);
+	    }
+	}
+    }
+
+    // TODO move to util class for convinience???
+    public void closeReader(Reader reader) {
+	if (reader != null) {
+	    try {
+		reader.close();
+	    } catch (IOException e) {
+		// TODO handle better.
+		throw new RuntimeException("Cannot close reader.", e);
+	    }
+	}
+    }
+
+    /**
+     * Called before this object will be discarded. Nothing to do: we were not
+     * listening to changes to this file.
+     */
+    @Override
+    public void dispose() {
+	FileMonitor.getInstance().removeFileChangeListener(
+		this.fileChangeListener, file);
+    }
+
+    private class FileChangeListenerImpl implements FileChangeListener {
+
+	@Override
+	public void fileChanged(final File changedFile) {
+	    fireResourceChange(PropertiesFileResource.this);
+	}
+
+    }
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesIFileResource.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesIFileResource.java
similarity index 88%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesIFileResource.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesIFileResource.java
index 53c0703..aec85ff 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesIFileResource.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesIFileResource.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.resource;
+package org.eclipse.babel.core.message.resource.internal;
 
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -16,11 +16,12 @@
 import java.io.InputStream;
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.AbstractIFileChangeListener;
-import org.eclipse.babel.core.message.AbstractIFileChangeListener.IFileChangeListenerRegistry;
+import org.eclipse.babel.core.message.internal.AbstractIFileChangeListener;
+import org.eclipse.babel.core.message.internal.AbstractIFileChangeListener.IFileChangeListenerRegistry;
 import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
 import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IResourceChangeEvent;
 import org.eclipse.core.resources.IResourceChangeListener;
 import org.eclipse.core.runtime.CoreException;
@@ -86,11 +87,12 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.resource.AbstractPropertiesResource
+     * @see org.eclipse.babel.core.message.internal.resource.AbstractPropertiesResource
      * 			#getText()
      */
     public String getText() {
         try {
+            file.refreshLocal(IResource.DEPTH_INFINITE, null);
             InputStream is = file.getContents();
             int byteCount = is.available();
             byte[] b = new byte[byteCount];
@@ -105,7 +107,7 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.resource.TextResource#setText(
+     * @see org.eclipse.babel.core.message.internal.resource.TextResource#setText(
      *              java.lang.String)
      */
     public void setText(String text) {
@@ -114,6 +116,7 @@
         	ByteArrayInputStream is = new ByteArrayInputStream(
         			text.getBytes(charset));
             file.setContents(is, IFile.KEEP_HISTORY, null);
+            file.refreshLocal(IResource.DEPTH_ZERO, null);
         } catch (Exception e) {
             //TODO handle better
             throw new RuntimeException(
@@ -122,7 +125,7 @@
     }
     
     /**
-     * @see org.eclipse.babel.core.message.resource.IMessagesResource
+     * @see org.eclipse.babel.core.message.internal.resource.IMessagesResource
      * 		#getSource()
      */
     public Object getSource() {
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesReadOnlyResource.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesReadOnlyResource.java
similarity index 89%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesReadOnlyResource.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesReadOnlyResource.java
index 1997182..beabf0e 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/PropertiesReadOnlyResource.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/internal/PropertiesReadOnlyResource.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.resource;
+package org.eclipse.babel.core.message.resource.internal;
 
 import java.util.Locale;
 
@@ -52,7 +52,7 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.resource.AbstractPropertiesResource
+     * @see org.eclipse.babel.core.message.internal.resource.AbstractPropertiesResource
      * 			#getText()
      */
     public String getText() {
@@ -61,7 +61,7 @@
 
     /**
      * Unsupported here. This is read-only.
-     * @see org.eclipse.babel.core.message.resource.TextResource#setText(
+     * @see org.eclipse.babel.core.message.internal.resource.TextResource#setText(
      *              java.lang.String)
      */
     public void setText(String text) {
@@ -70,7 +70,7 @@
     }
     
     /**
-     * @see org.eclipse.babel.core.message.resource.IMessagesResource
+     * @see org.eclipse.babel.core.message.internal.resource.IMessagesResource
      * 		#getSource()
      */
     public Object getSource() {
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesDeserializerConfig.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesDeserializerConfig.java
index 8e63a20..f231509 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesDeserializerConfig.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesDeserializerConfig.java
@@ -1,5 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
 package org.eclipse.babel.core.message.resource.ser;
 
+/**
+ * Interface for the deserialization process.
+ * 
+ * @author Alexej Strelzow
+ */
 public interface IPropertiesDeserializerConfig {
 
     /**
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesSerializerConfig.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesSerializerConfig.java
index 50b309f..469e6ce 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesSerializerConfig.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/IPropertiesSerializerConfig.java
@@ -1,5 +1,20 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
 package org.eclipse.babel.core.message.resource.ser;
 
+/**
+ * Interface for the serialization process.
+ * 
+ * @author Alexej Strelzow
+ */
 public interface IPropertiesSerializerConfig {
 
     /** New Line Type: Default. */
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesDeserializer.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesDeserializer.java
index 07eea98..2fe4273 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesDeserializer.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesDeserializer.java
@@ -16,8 +16,10 @@
 import java.util.Locale;
 import java.util.Properties;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.internal.Message;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 import org.eclipse.babel.core.util.BabelUtils;
 
 /**
@@ -52,8 +54,9 @@
      * @param messagesBundle the target {@link MessagesBundle}
      * @param properties the string containing the properties to parse
      */
-    public void deserialize(MessagesBundle messagesBundle, String properties) {
+    public void deserialize(IMessagesBundle messagesBundle, String properties) {
         Locale locale = messagesBundle.getLocale();
+        
         Collection<String> oldKeys =
         		new ArrayList<String>(Arrays.asList(messagesBundle.getKeys()));
         Collection<String> newKeys = new ArrayList<String>();
@@ -114,7 +117,7 @@
                     value = value.substring(1);
                 }
                 
-                if (config.isUnicodeUnescapeEnabled()) {
+                if (this.config != null && config.isUnicodeUnescapeEnabled()) {
                     key = convertEncodedToUnicode(key);
                     value = convertEncodedToUnicode(value);
                 } else {
@@ -123,7 +126,7 @@
                     value = value.replaceAll(
                             "\\\\n", "\n");  //$NON-NLS-1$//$NON-NLS-2$
                 }
-                Message entry = messagesBundle.getMessage(key);
+                IMessage entry = messagesBundle.getMessage(key);
                 if (entry == null) {
                     entry = new Message(key, locale);
                     messagesBundle.addMessage(entry);
@@ -249,4 +252,5 @@
         }
         return buf.toString();
     }
+    
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesSerializer.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesSerializer.java
index 04e53b2..420c4ad 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesSerializer.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/resource/ser/PropertiesSerializer.java
@@ -13,8 +13,9 @@
 import java.util.Arrays;
 import java.util.Properties;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 
 /**
  * Class responsible for serializing a {@link MessagesBundle} into
@@ -71,7 +72,7 @@
      * @param messagesBundle the bundle used to generate the string
      * @return the generated string
      */
-    public String serialize(MessagesBundle messagesBundle) {
+    public String serialize(IMessagesBundle messagesBundle) {
         String lineBreak = SYSTEM_LINE_SEP;
         int numOfLineBreaks = config.getGroupSepBlankLineCount();
         StringBuffer text = new StringBuffer();
@@ -96,7 +97,7 @@
         }
         for (int i = 0; i < keys.length; i++) {
 			String key = keys[i];
-            Message message = messagesBundle.getMessage(key);
+            IMessage message = messagesBundle.getMessage(key);
             String value = message.getValue(); 
             String comment = message.getComment();    
             
@@ -356,7 +357,7 @@
      * @return position
      */
     private int getEqualIndex(
-    		String key, String group, MessagesBundle messagesBundle) {
+    		String key, String group, IMessagesBundle messagesBundle) {
         int equalIndex = -1;
         boolean alignEquals = config.isAlignEqualsEnabled();
         boolean groupKeys = config.isGroupKeysEnabled();
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/IMessagesBundleGroupStrategy.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/IMessagesBundleGroupStrategy.java
index 9a52a38..57de739 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/IMessagesBundleGroupStrategy.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/IMessagesBundleGroupStrategy.java
@@ -7,13 +7,14 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapJI integration, messagesBundleId
  ******************************************************************************/
 package org.eclipse.babel.core.message.strategy;
 
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.MessageException;
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.internal.MessageException;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 import org.eclipse.babel.core.message.resource.IMessagesResource;
 
 
@@ -38,6 +39,8 @@
      */
     String createMessagesBundleGroupName();
     
+    String createMessagesBundleId();
+    
     /**
      * Load all bundles making up a messages bundle group from the underlying
      * source.
@@ -57,5 +60,6 @@
      * @throws MessageException problem creating a new messages bundle
      */
     MessagesBundle createMessagesBundle(Locale locale) throws MessageException;
-        
+    
+    String getProjectName();
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/PropertiesFileGroupStrategy.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/PropertiesFileGroupStrategy.java
index 7d795af..04f6723 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/PropertiesFileGroupStrategy.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/strategy/PropertiesFileGroupStrategy.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapJI integration, messagesBundleId
  ******************************************************************************/
 package org.eclipse.babel.core.message.strategy;
 
@@ -16,29 +17,33 @@
 import java.util.Collection;
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.MessageException;
-import org.eclipse.babel.core.message.MessagesBundle;
-import org.eclipse.babel.core.message.resource.PropertiesFileResource;
+import org.eclipse.babel.core.message.internal.MessageException;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
+import org.eclipse.babel.core.message.resource.internal.PropertiesFileResource;
 import org.eclipse.babel.core.message.resource.ser.IPropertiesDeserializerConfig;
 import org.eclipse.babel.core.message.resource.ser.IPropertiesSerializerConfig;
 import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
 import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
 import org.eclipse.babel.core.util.BabelUtils;
-
+import org.eclipse.babel.core.util.NameUtils;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
 
 /**
  * MessagesBundleGroup strategy for standard Java properties file structure.
  * That is, all *.properties files of the same base name within the same
- * directory.  This implementation works on files outside the Eclipse
- * workspace.
+ * directory. This implementation works on files outside the Eclipse workspace.
+ * 
  * @author Pascal Essiembre
  */
-public class PropertiesFileGroupStrategy implements IMessagesBundleGroupStrategy {
+public class PropertiesFileGroupStrategy implements
+	IMessagesBundleGroupStrategy {
 
     /** Empty bundle array. */
-    private static final MessagesBundle[] EMPTY_MESSAGES =
-    		new MessagesBundle[] {};
-    
+    private static final MessagesBundle[] EMPTY_MESSAGES = new MessagesBundle[] {};
+
     /** File being open, triggering the creation of a bundle group. */
     private File file;
     /** MessagesBundle group base name. */
@@ -51,103 +56,153 @@
     private final IPropertiesSerializerConfig serializerConfig;
     /** Properties file deserializer configuration. */
     private final IPropertiesDeserializerConfig deserializerConfig;
-    
-    
+
     /**
      * Constructor.
-     * @param file file from which to derive the group
+     * 
+     * @param file
+     *            file from which to derive the group
      */
-    public PropertiesFileGroupStrategy(
-            File file,
-            IPropertiesSerializerConfig serializerConfig,
-            IPropertiesDeserializerConfig deserializerConfig) {
-        super();
-        this.serializerConfig = serializerConfig;
-        this.deserializerConfig = deserializerConfig;
-        this.file = file;
-        this.fileExtension = file.getName().replaceFirst(
-                "(.*\\.)(.*)", "$2"); //$NON-NLS-1$ //$NON-NLS-2$
+    public PropertiesFileGroupStrategy(File file,
+	    IPropertiesSerializerConfig serializerConfig,
+	    IPropertiesDeserializerConfig deserializerConfig) {
+	super();
+	this.serializerConfig = serializerConfig;
+	this.deserializerConfig = deserializerConfig;
+	this.file = file;
+	this.fileExtension = file.getName().replaceFirst("(.*\\.)(.*)", "$2"); //$NON-NLS-1$ //$NON-NLS-2$
 
-        String patternCore =
-                "((_[a-z]{2,3})|(_[a-z]{2,3}_[A-Z]{2})" //$NON-NLS-1$
-              + "|(_[a-z]{2,3}_[A-Z]{2}_\\w*))?(\\." //$NON-NLS-1$
-              + fileExtension + ")$"; //$NON-NLS-1$
+	String patternCore = "((_[a-z]{2,3})|(_[a-z]{2,3}_[A-Z]{2})" //$NON-NLS-1$
+		+ "|(_[a-z]{2,3}_[A-Z]{2}_\\w*))?(\\." //$NON-NLS-1$
+		+ fileExtension + ")$"; //$NON-NLS-1$
 
-        // Compute and cache name
-        String namePattern = "^(.*?)" + patternCore; //$NON-NLS-1$
-        this.baseName = file.getName().replaceFirst(
-                namePattern, "$1"); //$NON-NLS-1$
-        
-        // File matching pattern
-        this.fileMatchPattern =
-                "^(" + baseName + ")" + patternCore;  //$NON-NLS-1$//$NON-NLS-2$
+	// Compute and cache name
+	String namePattern = "^(.*?)" + patternCore; //$NON-NLS-1$
+	this.baseName = file.getName().replaceFirst(namePattern, "$1"); //$NON-NLS-1$
+
+	// File matching pattern
+	this.fileMatchPattern = "^(" + baseName + ")" + patternCore; //$NON-NLS-1$//$NON-NLS-2$
     }
 
     /**
      * @see org.eclipse.babel.core.bundle.IMessagesBundleGroupStrategy
-     * 			#getMessagesBundleGroupName()
+     *      #getMessagesBundleGroupName()
      */
     public String createMessagesBundleGroupName() {
-        return baseName + "[...]." + fileExtension; //$NON-NLS-1$
+	return baseName + "[...]." + fileExtension; //$NON-NLS-1$
     }
 
     /**
      * @see org.eclipse.babel.core.bundle.IMessagesBundleGroupStrategy
-     *          #loadMessagesBundles()
+     *      #loadMessagesBundles()
      */
     public MessagesBundle[] loadMessagesBundles() throws MessageException {
-        File[] resources = null;
-        File parentDir = file.getParentFile();
-        if (parentDir != null) {
-            resources = parentDir.listFiles();
-        }
-        Collection<MessagesBundle> bundles = new ArrayList<MessagesBundle>();
-        if (resources != null) {
-            for (int i = 0; i < resources.length; i++) {
-                File resource = resources[i];
-                String resourceName = resource.getName();
-                if (resource.isFile()
-                        && resourceName.matches(fileMatchPattern)) {
-                    // Build local title
-                    String localeText = resourceName.replaceFirst(
-                            fileMatchPattern, "$2"); //$NON-NLS-1$
-                    Locale locale = BabelUtils.parseLocale(localeText);
-                    bundles.add(createBundle(locale, resource));
-                }
-            }
-        }
-        return bundles.toArray(EMPTY_MESSAGES);
+	File[] resources = null;
+	File parentDir = file.getParentFile();
+	if (parentDir != null) {
+	    resources = parentDir.listFiles();
+	}
+	Collection<MessagesBundle> bundles = new ArrayList<MessagesBundle>();
+	if (resources != null) {
+	    for (int i = 0; i < resources.length; i++) {
+		File resource = resources[i];
+		String resourceName = resource.getName();
+		if (resource.isFile() && resourceName.matches(fileMatchPattern)) {
+		    // Build local title
+		    String localeText = resourceName.replaceFirst(
+			    fileMatchPattern, "$2"); //$NON-NLS-1$
+		    Locale locale = BabelUtils.parseLocale(localeText);
+		    bundles.add(createBundle(locale, resource));
+		}
+	    }
+	}
+	return bundles.toArray(EMPTY_MESSAGES);
     }
 
     /**
      * @see org.eclipse.babel.core.bundle.IBundleGroupStrategy
-     *          #createBundle(java.util.Locale)
+     *      #createBundle(java.util.Locale)
      */
     public MessagesBundle createMessagesBundle(Locale locale) {
-        // TODO Implement me (code exists in SourceForge version)
-        return null;
+	// TODO Implement me (code exists in SourceForge version)
+	return null;
     }
-    
+
     /**
      * Creates a resource bundle for an existing resource.
-     * @param locale locale for which to create a bundle
-     * @param resource resource used to create bundle
+     * 
+     * @param locale
+     *            locale for which to create a bundle
+     * @param resource
+     *            resource used to create bundle
      * @return an initialized bundle
      */
     protected MessagesBundle createBundle(Locale locale, File resource)
-            throws MessageException {
-        try {
-            //TODO have the text de/serializer tied to Eclipse preferences,
-            //singleton per project, and listening for changes
-            return new MessagesBundle(new PropertiesFileResource(
-                    locale,
-                    new PropertiesSerializer(serializerConfig),
-                    new PropertiesDeserializer(deserializerConfig),
-                    resource));
-        } catch (FileNotFoundException e) {
-            throw new MessageException(
-                    "Cannot create bundle for locale " //$NON-NLS-1$
-                  + locale + " and resource " + resource, e); //$NON-NLS-1$
-        }
+	    throws MessageException {
+	try {
+	    // TODO have the text de/serializer tied to Eclipse preferences,
+	    // singleton per project, and listening for changes
+	    return new MessagesBundle(new PropertiesFileResource(locale,
+		    new PropertiesSerializer(serializerConfig),
+		    new PropertiesDeserializer(deserializerConfig), resource));
+	} catch (FileNotFoundException e) {
+	    throw new MessageException("Cannot create bundle for locale " //$NON-NLS-1$
+		    + locale + " and resource " + resource, e); //$NON-NLS-1$
+	}
     }
+
+    public String createMessagesBundleId() {
+	String path = file.getAbsolutePath();
+	int index = path.indexOf("src");
+	String pathBeforeSrc = path.substring(0, index - 1);
+	int lastIndexOf = pathBeforeSrc.lastIndexOf(File.separatorChar);
+	String projectName = path.substring(lastIndexOf + 1, index - 1);
+	String relativeFilePath = path.substring(index, path.length());
+
+	IFile f = ResourcesPlugin.getWorkspace().getRoot()
+		.getProject(projectName).getFile(relativeFilePath);
+
+	return NameUtils.getResourceBundleId(f);
+    }
+
+    public String getProjectName() {
+	IPath path = ResourcesPlugin.getWorkspace().getRoot().getLocation();
+	IPath fullPath = null;
+	if (this.file.getAbsolutePath().contains(path.toOSString())) {
+	    fullPath = new Path(this.file.getAbsolutePath());
+	} else {
+	    fullPath = new Path(path.toOSString() + this.file.getAbsolutePath());
+	}
+
+	IFile file = ResourcesPlugin.getWorkspace().getRoot()
+		.getFileForLocation(fullPath);
+
+	if (file != null) {
+	    return ResourcesPlugin.getWorkspace().getRoot()
+		    .getProject(file.getFullPath().segments()[0]).getName();
+	} else {
+	    return null;
+	}
+	
+    }
+
+    // public static String getResourceBundleId (IResource resource) {
+    // String packageFragment = "";
+    //
+    // IJavaElement propertyFile = JavaCore.create(resource.getParent());
+    // if (propertyFile != null && propertyFile instanceof IPackageFragment)
+    // packageFragment = ((IPackageFragment) propertyFile).getElementName();
+    //
+    // return (packageFragment.length() > 0 ? packageFragment + "." : "") +
+    // getResourceBundleName(resource);
+    // }
+    //
+    // public static String getResourceBundleName(IResource res) {
+    // String name = res.getName();
+    //    	String regex = "^(.*?)" //$NON-NLS-1$
+    //                + "((_[a-z]{2,3})|(_[a-z]{2,3}_[A-Z]{2})" //$NON-NLS-1$
+    //                + "|(_[a-z]{2,3}_[A-Z]{2}_\\w*))?(\\." //$NON-NLS-1$
+    //                + res.getFileExtension() + ")$"; //$NON-NLS-1$
+    //        return name.replaceFirst(regex, "$1"); //$NON-NLS-1$
+    // }
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IAbstractKeyTreeModel.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IAbstractKeyTreeModel.java
new file mode 100644
index 0000000..632184f
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IAbstractKeyTreeModel.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer.
+ * 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:
+ *     Martin Reiterer - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.message.tree;
+
+
+public interface IAbstractKeyTreeModel {
+
+	IKeyTreeNode[] getChildren(IKeyTreeNode node);
+
+	IKeyTreeNode getChild(String key);
+
+	IKeyTreeNode[] getRootNodes();
+
+	IKeyTreeNode getRootNode();
+
+	IKeyTreeNode getParent(IKeyTreeNode node);
+
+	void accept(IKeyTreeVisitor visitor, IKeyTreeNode node);
+
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeNode.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeNode.java
new file mode 100644
index 0000000..b7b8585
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeNode.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer.
+ * 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:
+ *     Martin Reiterer - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.message.tree;
+
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+
+public interface IKeyTreeNode {
+
+	/**
+	 * Returns the key of the corresponding Resource-Bundle entry.
+	 * 
+	 * @return The key of the Resource-Bundle entry
+	 */
+	String getMessageKey();
+
+	/**
+	 * Returns the set of Resource-Bundle entries of the next deeper hierarchy
+	 * level that share the represented entry as their common parent.
+	 * 
+	 * @return The direct child Resource-Bundle entries
+	 */
+	IKeyTreeNode[] getChildren();
+
+	/**
+	 * The represented Resource-Bundle entry's id without the prefix defined by
+	 * the entry's parent.
+	 * 
+	 * @return The Resource-Bundle entry's display name.
+	 */
+	String getName();
+
+	/**
+	 * Returns the set of Resource-Bundle entries from all deeper hierarchy
+	 * levels that share the represented entry as their common parent.
+	 * 
+	 * @return All child Resource-Bundle entries
+	 */
+	// Collection<? extends IKeyTreeItem> getNestedChildren();
+
+	/**
+	 * Returns whether this Resource-Bundle entry is visible under the given
+	 * filter expression.
+	 * 
+	 * @param filter
+	 *            The filter expression
+	 * @return True if the filter expression matches the represented
+	 *         Resource-Bundle entry
+	 */
+	// boolean applyFilter(String filter);
+
+	/**
+	 * The Resource-Bundle entries parent.
+	 * 
+	 * @return The parent Resource-Bundle entry
+	 */
+	IKeyTreeNode getParent();
+
+	/**
+	 * The Resource-Bundles key representation.
+	 * 
+	 * @return The Resource-Bundle reference, if known
+	 */
+	IMessagesBundleGroup getMessagesBundleGroup();
+
+	boolean isUsedAsKey();
+
+	void setParent(IKeyTreeNode parentNode);
+
+	void addChild(IKeyTreeNode childNode);
+
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/IKeyTreeVisitor.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeVisitor.java
similarity index 74%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/IKeyTreeVisitor.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeVisitor.java
index 0f4ff5f..ac7a535 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/IKeyTreeVisitor.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeVisitor.java
@@ -8,19 +8,21 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.tree.visitor;
+package org.eclipse.babel.core.message.tree;
 
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
 
 /**
  * Objects implementing this interface can act as a visitor to a
  * <code>IKeyTreeModel</code>.
+ * 
  * @author Pascal Essiembre (pascal@essiembre.com)
  */
 public interface IKeyTreeVisitor {
-    /**
-     * Visits a key tree node.
-     * @param item key tree node to visit
-     */
-	void visitKeyTreeNode(KeyTreeNode node);
+	/**
+	 * Visits a key tree node.
+	 * 
+	 * @param item
+	 *            key tree node to visit
+	 */
+	void visitKeyTreeNode(IKeyTreeNode node);
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/TreeType.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/TreeType.java
new file mode 100644
index 0000000..bf833e9
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/TreeType.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.message.tree;
+
+/**
+ * Enum for two tree types. If a tree has the type {@link #Tree}, then it
+ * is displayed as tree. E.g. following key is given: parent.child.grandchild
+ * result: 
+ * <pre>
+ * parent
+ * 	child
+ * 		grandchild
+ * </pre>
+ * If it is {@link #Flat}, it will be displayed as parent.child.grandchild.
+ * 
+ * @author Alexej Strelzow
+ */
+public enum TreeType {
+	Tree, Flat
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/AbstractKeyTreeModel.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/AbstractKeyTreeModel.java
similarity index 76%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/AbstractKeyTreeModel.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/AbstractKeyTreeModel.java
index d88ddc6..74be09b 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/AbstractKeyTreeModel.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/AbstractKeyTreeModel.java
@@ -7,8 +7,9 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Matthias Lettmayer - fixed bug in returnNodeWithKey()
  ******************************************************************************/
-package org.eclipse.babel.core.message.tree;
+package org.eclipse.babel.core.message.tree.internal;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -16,9 +17,11 @@
 import java.util.List;
 import java.util.StringTokenizer;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.MessagesBundleGroupAdapter;
-import org.eclipse.babel.core.message.tree.visitor.IKeyTreeVisitor;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroupAdapter;
+import org.eclipse.babel.core.message.tree.IAbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.IKeyTreeVisitor;
 
 
 /**
@@ -37,12 +40,12 @@
  * 
  * @author Pascal Essiembre
  */
-public class AbstractKeyTreeModel {
+public class AbstractKeyTreeModel implements IAbstractKeyTreeModel {
 
     private List<IKeyTreeModelListener> listeners = new ArrayList<IKeyTreeModelListener>();
-    private Comparator<KeyTreeNode> comparator;
+    private Comparator<IKeyTreeNode> comparator;
     
-    private KeyTreeNode rootNode = new KeyTreeNode(null, null, null);
+    private KeyTreeNode rootNode = new KeyTreeNode(null, null, null, null);
     
     private String delimiter;
     private MessagesBundleGroup messagesBundleGroup;
@@ -133,11 +136,15 @@
      * @param visitor the object to visit
      * @param node the starting key tree node
      */
-    public void accept(IKeyTreeVisitor visitor, KeyTreeNode node) {
+    public void accept(IKeyTreeVisitor visitor, IKeyTreeNode node) {
+        if (node == null) {
+            return;
+        }
+        
         if (node != null) {
             visitor.visitKeyTreeNode(node);
         }
-        KeyTreeNode[] nodes = getChildren(node);
+        IKeyTreeNode[] nodes = getChildren(node);
         for (int i = 0; i < nodes.length; i++) {
             accept(visitor, nodes[i]);
         }
@@ -148,8 +155,12 @@
      * @param node the node from which to get children
      * @return child nodes
      */
-    public KeyTreeNode[] getChildren(KeyTreeNode node) {
-        KeyTreeNode[] nodes = node.getChildren();
+    public IKeyTreeNode[] getChildren(IKeyTreeNode node) {
+        if (node == null) {
+            return null;
+        }
+        
+        IKeyTreeNode[] nodes = node.getChildren();
         if (getComparator() != null) {
             Arrays.sort(nodes, getComparator());
         }
@@ -160,7 +171,7 @@
      * Gets the comparator.
      * @return the comparator
      */
-    public Comparator<KeyTreeNode> getComparator() {
+    public Comparator<IKeyTreeNode> getComparator() {
         return comparator;
     }
 
@@ -168,7 +179,7 @@
      * Sets the node comparator for sorting sibling nodes.
      * @param comparator node comparator
      */
-    public void setComparator(Comparator<KeyTreeNode> comparator) {
+    public void setComparator(Comparator<IKeyTreeNode> comparator) {
         this.comparator = comparator;
     }
     
@@ -180,12 +191,12 @@
      * @param node
      * @return true if this node or one of its descendant is in the filter (ie is displayed)
      */
-    public boolean isBranchFiltered(IKeyTreeNodeLeafFilter filter, KeyTreeNode node) {
-    	if (!node.hasChildren()) {
+    public boolean isBranchFiltered(IKeyTreeNodeLeafFilter filter, IKeyTreeNode node) {
+    	if (!((KeyTreeNode)node).hasChildren()) {
     		return filter.isFilteredLeaf(node);
     	} else {
     		//depth first:
-    		for (KeyTreeNode childNode : node.getChildrenInternal()) {
+    		for (IKeyTreeNode childNode : ((KeyTreeNode)node).getChildrenInternal()) {
     			if (isBranchFiltered(filter, childNode)) {
     				return true;
     			}
@@ -213,11 +224,11 @@
 	 * Gets the key tree root nodes.
 	 * @return key tree root nodes
 	 */
-    public KeyTreeNode[] getRootNodes() {
+    public IKeyTreeNode[] getRootNodes() {
         return getChildren(rootNode);
     }
 
-    public KeyTreeNode getRootNode() {
+    public IKeyTreeNode getRootNode() {
     	return rootNode;
     }
     
@@ -226,7 +237,7 @@
      * @param node node from which to get parent
      * @return parent node
      */
-    public KeyTreeNode getParent(KeyTreeNode node) {
+    public IKeyTreeNode getParent(IKeyTreeNode node) {
         return node.getParent();
     }
     
@@ -240,7 +251,7 @@
     }
 
     private void createTree() {
-        rootNode = new KeyTreeNode(null, null, null);
+        rootNode = new KeyTreeNode(null, null, null, messagesBundleGroup);
         String[] keys = messagesBundleGroup.getMessageKeys();
         for (int i = 0; i < keys.length; i++) {
 			String key = keys[i];
@@ -255,9 +266,9 @@
         while (tokens.hasMoreTokens()) {
             String name = tokens.nextToken();
             bundleKeyPart += name;
-            KeyTreeNode child = node.getChild(name);
+            KeyTreeNode child = (KeyTreeNode) node.getChild(name);
             if (child == null) {
-                child = new KeyTreeNode(node, name, bundleKeyPart);
+                child = new KeyTreeNode(node, name, bundleKeyPart, messagesBundleGroup);
                 fireNodeAdded(child);
             }
             bundleKeyPart += delimiter;
@@ -273,23 +284,23 @@
         KeyTreeNode node = rootNode;
         while (tokens.hasMoreTokens()) {
             String name = tokens.nextToken();
-            node = node.getChild(name);
+            node = (KeyTreeNode) node.getChild(name);
             if (node == null) {
                 System.err.println(
                     "No RegEx node matching bundleKey to remove"); //$NON-NLS-1$
                 return;
             }
         }
-        KeyTreeNode parentNode = node.getParent();
+        KeyTreeNode parentNode = (KeyTreeNode) node.getParent();
         parentNode.removeChild(node);
         fireNodeRemoved(node);
         while (parentNode != rootNode) {
             if (!parentNode.hasChildren() && !messagesBundleGroup.isMessageKey(
                     parentNode.getMessageKey())) {
-                parentNode.getParent().removeChild(parentNode);
+                ((KeyTreeNode)parentNode.getParent()).removeChild(parentNode);
                 fireNodeRemoved(parentNode);
             }
-            parentNode = parentNode.getParent();
+            parentNode = (KeyTreeNode)parentNode.getParent();
         }
     }
     
@@ -299,7 +310,27 @@
     	 * @param leafNode A leaf node. Must not be called if the node has children
     	 * @return true if this node should be filtered.
     	 */
-    	boolean isFilteredLeaf(KeyTreeNode leafNode);
+    	boolean isFilteredLeaf(IKeyTreeNode leafNode);
+    }
+
+    public IKeyTreeNode getChild(String key) {
+        return returnNodeWithKey(key, rootNode);
     }
     
+    private IKeyTreeNode returnNodeWithKey(String key, IKeyTreeNode node) {
+        
+         if (!key.equals(node.getMessageKey())) {
+            for (IKeyTreeNode n : node.getChildren()) {
+                IKeyTreeNode returnNode = returnNodeWithKey(key, n);
+            	if (returnNode == null) {
+                    continue;
+                } else {
+                    return returnNode;
+                }
+            }
+        } else {
+            return node;
+        }
+        return null;
+    }
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeModelListener.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/IKeyTreeModelListener.java
similarity index 94%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeModelListener.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/IKeyTreeModelListener.java
index 46eddac..98bece0 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/IKeyTreeModelListener.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/IKeyTreeModelListener.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.tree;
+package org.eclipse.babel.core.message.tree.internal;
 
 /**
  * Listener notified of changes to a {@link IKeyTreeModel}.
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/KeyTreeNode.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/KeyTreeNode.java
similarity index 73%
rename from org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/KeyTreeNode.java
rename to org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/KeyTreeNode.java
index 0c469db..6b0fd94 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/KeyTreeNode.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/internal/KeyTreeNode.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.core.message.tree;
+package org.eclipse.babel.core.message.tree.internal;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -16,6 +16,8 @@
 import java.util.Map;
 import java.util.TreeMap;
 
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
 import org.eclipse.babel.core.util.BabelUtils;
 
 /**
@@ -23,7 +25,7 @@
  *
  * @author Pascal Essiembre
  */
-public class KeyTreeNode implements Comparable<KeyTreeNode> {
+public class KeyTreeNode implements Comparable<KeyTreeNode>, IKeyTreeNode {
 
     public static final KeyTreeNode[] EMPTY_KEY_TREE_NODES =
             new KeyTreeNode[] {};
@@ -33,7 +35,7 @@
      * the same as this object but with the last component (following the
      * last period) removed
      */
-    private final KeyTreeNode parent;
+    private IKeyTreeNode parent;
     
     /**
      * the name, being the part of the full key that follows the last period
@@ -47,9 +49,11 @@
      */
     private String messageKey;
     
-    private final Map<String, KeyTreeNode> children = new TreeMap<String, KeyTreeNode>();
+    private final Map<String, IKeyTreeNode> children = new TreeMap<String, IKeyTreeNode>();
 
 	private boolean usedAsKey = false;
+	
+	private IMessagesBundleGroup messagesBundleGroup;
     
     /**
      * Constructor.
@@ -58,7 +62,7 @@
      * @param messageKey messages bundle key
      */
     public KeyTreeNode(
-    		KeyTreeNode parent, String name, String messageKey) {
+    		IKeyTreeNode parent, String name, String messageKey, IMessagesBundleGroup messagesBundleGroup) {
         super();
         this.parent = parent;
         this.name = name;
@@ -66,6 +70,7 @@
         if (parent != null) {
             parent.addChild(this);
         }
+        this.messagesBundleGroup = messagesBundleGroup;
     }
 
     /**
@@ -80,7 +85,7 @@
      * the same as this object but with the last component (following the
      * last period) removed
      */
-    public KeyTreeNode getParent() {
+    public IKeyTreeNode getParent() {
         return parent;
     }
 
@@ -97,9 +102,9 @@
      * Gets all notes from root to this node.
      * @return all notes from root to this node
      */
-    /*default*/ KeyTreeNode[] getPath() {
-        List<KeyTreeNode> nodes = new ArrayList<KeyTreeNode>();
-        KeyTreeNode node = this;
+    /*default*/ IKeyTreeNode[] getPath() {
+        List<IKeyTreeNode> nodes = new ArrayList<IKeyTreeNode>();
+        IKeyTreeNode node = this;
         while (node != null && node.getName() != null) {
             nodes.add(0, node);
             node = node.getParent();
@@ -107,20 +112,20 @@
         return nodes.toArray(EMPTY_KEY_TREE_NODES);
     }
 
-    public KeyTreeNode[] getChildren() {
+    public IKeyTreeNode[] getChildren() {
         return children.values().toArray(EMPTY_KEY_TREE_NODES);
     }
     /*default*/ boolean hasChildren() {
         return !children.isEmpty();
     }
-    public KeyTreeNode getChild(String childName) {
+    public IKeyTreeNode getChild(String childName) {
         return children.get(childName);
     }
     
     /**
      * @return the children without creating a new object
      */
-    Collection<KeyTreeNode> getChildrenInternal() {
+    Collection<IKeyTreeNode> getChildrenInternal() {
     	return children.values();
     }
     
@@ -145,7 +150,7 @@
     public boolean equals(Object obj) {
         if (!(obj instanceof KeyTreeNode)) {
             return false;
-        }
+        } 
         KeyTreeNode node = (KeyTreeNode) obj;
         return BabelUtils.equals(name, node.name)
                 && BabelUtils.equals(parent, node.parent);
@@ -155,15 +160,16 @@
      * @see java.lang.Object#toString()
      */
     public String toString() {
-        return "KeyTreeNode=[[parent=" + parent //$NON-NLS-1$
-              + "][name=" + name //$NON-NLS-1$
-              + "][messageKey=" + messageKey + "]]"; //$NON-NLS-1$ //$NON-NLS-2$
+    	return messageKey;
+//        return "KeyTreeNode=[[parent=" + parent //$NON-NLS-1$
+//              + "][name=" + name //$NON-NLS-1$
+//              + "][messageKey=" + messageKey + "]]"; //$NON-NLS-1$ //$NON-NLS-2$
     }
 
-    /*default*/ void addChild(KeyTreeNode childNode) {
+    public void addChild(IKeyTreeNode childNode) {
         children.put(childNode.getName(), childNode);
     }
-    /*default*/ void removeChild(KeyTreeNode childNode) {
+    public void removeChild(KeyTreeNode childNode) {
         children.remove(childNode.getName());
         //TODO remove parent on child node?
     }
@@ -172,17 +178,17 @@
 	public Collection<KeyTreeNode> getBranch() {
         Collection<KeyTreeNode> childNodes = new ArrayList<KeyTreeNode>();
         childNodes.add(this);
-        for (KeyTreeNode childNode : this.getChildren()) {
-            childNodes.addAll(childNode.getBranch());
+        for (IKeyTreeNode childNode : this.getChildren()) {
+            childNodes.addAll(((KeyTreeNode)childNode).getBranch());
         }
         return childNodes;
 	}
 
-	public Collection<KeyTreeNode> getDescendants() {
-		Collection<KeyTreeNode> descendants = new ArrayList<KeyTreeNode>();
-		for (KeyTreeNode child : children.values()) {
+	public Collection<IKeyTreeNode> getDescendants() {
+		Collection<IKeyTreeNode> descendants = new ArrayList<IKeyTreeNode>();
+		for (IKeyTreeNode child : children.values()) {
 			descendants.add(child);
-			descendants.addAll(child.getDescendants());
+			descendants.addAll(((KeyTreeNode)child).getDescendants());
 		}
 		return descendants;
 	}
@@ -207,5 +213,13 @@
 	public boolean isUsedAsKey() {
 		return usedAsKey;
 	}
+	
+	public IMessagesBundleGroup getMessagesBundleGroup() {
+	    return this.messagesBundleGroup;
+	}
+	
+	public void setParent(IKeyTreeNode parentNode) {
+        this.parent = parentNode;
+    }
     
 }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/IKeyCheck.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/IKeyCheck.java
index d5bd607..5a3847e 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/IKeyCheck.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/IKeyCheck.java
@@ -10,7 +10,7 @@
  ******************************************************************************/
 package org.eclipse.babel.core.message.tree.visitor;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
 
 /**
  * All purpose key testing.   Use this interface to establish whether
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/KeyCheckVisitor.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/KeyCheckVisitor.java
index 4a99155..6f92041 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/KeyCheckVisitor.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/KeyCheckVisitor.java
@@ -13,8 +13,10 @@
 import java.util.ArrayList;
 import java.util.Collection;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.IKeyTreeVisitor;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
 
 
 /**
@@ -29,8 +31,8 @@
     private IKeyCheck keyCheck;
     private final MessagesBundleGroup messagesBundleGroup;
     
-    private final Collection<KeyTreeNode> passedNodes = new ArrayList<KeyTreeNode>();
-    private final Collection<KeyTreeNode> failedNodes = new ArrayList<KeyTreeNode>();
+    private final Collection<IKeyTreeNode> passedNodes = new ArrayList<IKeyTreeNode>();
+    private final Collection<IKeyTreeNode> failedNodes = new ArrayList<IKeyTreeNode>();
     
     /**
      * Constructor.
@@ -50,11 +52,11 @@
     }
     
     /**
-     * @see org.eclipse.babel.core.message.tree.visitor.IKeyTreeVisitor
+     * @see org.eclipse.babel.core.message.internal.tree.visitor.IKeyTreeVisitor
      *      #visitKeyTreeNode(
-     *              org.eclipse.babel.core.message.tree.KeyTreeNode)
+     *              org.eclipse.babel.core.message.internal.tree.internal.KeyTreeNode)
      */
-    public void visitKeyTreeNode(KeyTreeNode node) {
+    public void visitKeyTreeNode(IKeyTreeNode node) {
         if (keyCheck == null) {
             return;
         }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/NodePathRegexVisitor.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/NodePathRegexVisitor.java
index 876dffa..9035243 100644
--- a/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/NodePathRegexVisitor.java
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/message/tree/visitor/NodePathRegexVisitor.java
@@ -13,7 +13,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.IKeyTreeVisitor;
 
 /**
  * Visitor for finding keys matching the given regular expression.
@@ -22,7 +23,7 @@
 public class NodePathRegexVisitor implements IKeyTreeVisitor {
 
     /** Holder for matching keys. */
-    private List<KeyTreeNode> nodes = new ArrayList<KeyTreeNode>();
+    private List<IKeyTreeNode> nodes = new ArrayList<IKeyTreeNode>();
     private final String regex;
     
     /**
@@ -34,10 +35,10 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.tree.visitor.IKeyTreeVisitor
-     *      #visitKeyTreeNode(org.eclipse.babel.core.message.tree.KeyTreeNode)
+     * @see org.eclipse.babel.core.message.internal.tree.visitor.IKeyTreeVisitor
+     *      #visitKeyTreeNode(org.eclipse.babel.core.message.internal.tree.internal.KeyTreeNode)
      */
-    public void visitKeyTreeNode(KeyTreeNode node) {
+    public void visitKeyTreeNode(IKeyTreeNode node) {
         if (node.getMessageKey().matches(regex)) {
             nodes.add(node);
         }
@@ -47,7 +48,7 @@
      * Gets matching key tree nodes.
      * @return matching key tree nodes
      */
-    public List<KeyTreeNode> getKeyTreeNodes() {
+    public List<IKeyTreeNode> getKeyTreeNodes() {
         return nodes;
     }
 
@@ -57,7 +58,7 @@
      */
     public List<String> getKeyTreeNodePaths() {
         List<String> paths = new ArrayList<String>(nodes.size());
-        for (KeyTreeNode node : nodes) {
+        for (IKeyTreeNode node : nodes) {
             paths.add(node.getMessageKey());
         }
         return paths;
@@ -68,7 +69,7 @@
      * Gets the first item matched.
      * @return first item matched, or <code>null</code> if none was found
      */
-    public KeyTreeNode getKeyTreeNode() {
+    public IKeyTreeNode getKeyTreeNode() {
         if (nodes.size() > 0) {
             return nodes.get(0);
         }
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/util/FileUtils.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/util/FileUtils.java
new file mode 100644
index 0000000..e70a4ab
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/util/FileUtils.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+
+import org.eclipse.babel.core.configuration.ConfigurationManager;
+import org.eclipse.babel.core.configuration.DirtyHack;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.resource.internal.PropertiesFileResource;
+import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.ResourcesPlugin;
+
+/**
+ * Util class for File-I/O operations.
+ * 
+ * @author Alexej Strelzow
+ */
+public class FileUtils {
+	
+	public static void writeToFile(IMessagesBundle bundle) {
+		DirtyHack.setEditorModificationEnabled(false);
+
+		PropertiesSerializer ps = new PropertiesSerializer(ConfigurationManager
+				.getInstance().getSerializerConfig());
+		String editorContent = ps.serialize(bundle);
+		IFile file = getFile(bundle);
+		try {
+			file.refreshLocal(IResource.DEPTH_ZERO, null);
+			file.setContents(
+					new ByteArrayInputStream(editorContent.getBytes()), false,
+					true, null);
+			file.refreshLocal(IResource.DEPTH_ZERO, null);
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			DirtyHack.setEditorModificationEnabled(true);
+		}
+	}
+	
+	public static IFile getFile(IMessagesBundle bundle) {
+		if (bundle.getResource() instanceof PropertiesFileResource) { // different
+			// ResourceLocationLabel
+			String path = bundle.getResource().getResourceLocationLabel(); // P:\Workspace\AST\TEST\src\messages\Messages_de.properties
+			int index = path.indexOf("src");
+			String pathBeforeSrc = path.substring(0, index - 1);
+			int lastIndexOf = pathBeforeSrc.lastIndexOf(File.separatorChar);
+			String projectName = path.substring(lastIndexOf + 1, index - 1);
+			String relativeFilePath = path.substring(index, path.length());
+
+			return ResourcesPlugin.getWorkspace().getRoot()
+					.getProject(projectName).getFile(relativeFilePath);
+		} else {
+			String location = bundle.getResource().getResourceLocationLabel(); // /TEST/src/messages/Messages_en_IN.properties
+			String projectName = location.substring(1, location.indexOf("/", 1));
+			location = location.substring(projectName.length() + 1,
+					location.length());
+			return ResourcesPlugin.getWorkspace().getRoot()
+					.getProject(projectName).getFile(location);
+		}
+	}
+	
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/util/NameUtils.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/util/NameUtils.java
new file mode 100644
index 0000000..e277f54
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/util/NameUtils.java
@@ -0,0 +1,86 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.core.util;
+
+import java.util.Locale;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.JavaCore;
+
+/**
+ * Contains methods, which return names/IDs or Objects by name.
+ * 
+ * @author Alexej Strelzow
+ */
+public class NameUtils {
+
+	
+	public static String getResourceBundleId(IResource resource) {
+		String packageFragment = "";
+
+		IJavaElement propertyFile = JavaCore.create(resource.getParent());
+		if (propertyFile != null && propertyFile instanceof IPackageFragment)
+			packageFragment = ((IPackageFragment) propertyFile)
+					.getElementName();
+
+		return (packageFragment.length() > 0 ? packageFragment + "." : "")
+				+ getResourceBundleName(resource);
+	}
+
+	public static String getResourceBundleName(IResource res) {
+		String name = res.getName();
+		String regex = "^(.*?)" //$NON-NLS-1$
+				+ "((_[a-z]{2,3})|(_[a-z]{2,3}_[A-Z]{2})" //$NON-NLS-1$
+				+ "|(_[a-z]{2,3}_[A-Z]{2}_\\w*))?(\\." //$NON-NLS-1$
+				+ res.getFileExtension() + ")$"; //$NON-NLS-1$
+		return name.replaceFirst(regex, "$1"); //$NON-NLS-1$
+	}
+	
+	public static Locale getLocaleByName(String bundleName, String localeID) {
+		String theBundleName = bundleName;
+		if (theBundleName.contains(".")) {
+			// we entered this method with the rbID and not the name!
+			theBundleName = theBundleName.substring(theBundleName.indexOf(".") + 1);
+		}
+		
+		// Check locale
+		Locale locale = null;
+		localeID = localeID.substring(0,
+				localeID.length() - "properties".length() - 1);
+		if (localeID.length() == theBundleName.length()) {
+			// default locale
+			return null;
+		} else {
+			localeID = localeID.substring(theBundleName.length() + 1);
+			String[] localeTokens = localeID.split("_");
+
+			switch (localeTokens.length) {
+			case 1:
+				locale = new Locale(localeTokens[0]);
+				break;
+			case 2:
+				locale = new Locale(localeTokens[0], localeTokens[1]);
+				break;
+			case 3:
+				locale = new Locale(localeTokens[0], localeTokens[1],
+						localeTokens[2]);
+				break;
+			default:
+				locale = null;
+				break;
+			}
+		}
+
+		return locale;
+	}
+}
diff --git a/org.eclipse.babel.core/src/org/eclipse/babel/core/util/PDEUtils.java b/org.eclipse.babel.core/src/org/eclipse/babel/core/util/PDEUtils.java
new file mode 100644
index 0000000..40eeb48
--- /dev/null
+++ b/org.eclipse.babel.core/src/org/eclipse/babel/core/util/PDEUtils.java
@@ -0,0 +1,245 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Stefan Reiterer.
+ * 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:
+ *     Stefan Reiterer - initial API and implementation
+ ******************************************************************************/
+
+package org.eclipse.babel.core.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.osgi.service.resolver.BundleDescription;
+import org.eclipse.osgi.service.resolver.HostSpecification;
+import org.eclipse.pde.core.plugin.IFragmentModel;
+import org.eclipse.pde.core.plugin.IPluginBase;
+import org.eclipse.pde.core.plugin.IPluginModelBase;
+import org.eclipse.pde.core.plugin.PluginRegistry;
+
+public class PDEUtils {
+
+	// The same as PDE.PLUGIN_NATURE, because the PDE provided constant is not accessible (internal class) 
+	private static final String PLUGIN_NATURE = "org.eclipse.pde.PluginNature";
+
+	/** 
+	 * Get the project's plug-in Id if the given project is an eclipse plug-in.
+	 * 
+	 * @param project the workspace project.
+	 * @return the project's plug-in Id. Null if the project is no plug-in project.
+	 */
+	public static String getPluginId(IProject project) {
+
+		if (project == null || !isPluginProject(project)) {
+			return null;
+		}
+
+		IPluginModelBase pluginModelBase = PluginRegistry.findModel(project);
+		
+		if (pluginModelBase == null) {
+			// plugin not found in registry
+			return null;
+		}
+		
+		IPluginBase pluginBase = pluginModelBase.getPluginBase();
+
+		return pluginBase.getId();
+	}
+
+	/**
+	 * Returns all project containing plugin/fragment of the specified project.
+	 * If the specified project itself is a fragment, then only this is
+	 * returned.
+	 * 
+	 * @param pluginProject
+	 *            the plugin project
+	 * @return the all project containing a fragment or null if none
+	 */
+	public static IProject[] lookupFragment(IProject pluginProject) {
+		if (isFragment(pluginProject) && pluginProject.isOpen()) {
+			return new IProject[] {pluginProject};
+		}
+		
+		IProject[] workspaceProjects = pluginProject.getWorkspace().getRoot().getProjects();
+		String hostPluginId = getPluginId(pluginProject);
+		
+		if (hostPluginId == null) {
+			// project is not a plugin project
+			return null;
+		}
+		
+		List<IProject> fragmentProjects = new ArrayList<IProject>();
+		for (IProject project : workspaceProjects) {
+			if (!project.isOpen() || getFragmentId(project, hostPluginId) == null) {
+				// project is not open or it is no fragment where given project is the host project.
+				continue;
+			}
+			fragmentProjects.add(project);
+		}
+
+		if (fragmentProjects.isEmpty()) {
+			return null;
+		}
+		
+		return fragmentProjects.toArray(new IProject[0]);
+	}
+
+	/** 
+	 * Check if the given plug-in project is a fragment.
+	 * 
+	 * @param pluginProject the plug-in project in the workspace.
+	 * @return true if it is a fragment, otherwise false.
+	 */
+	public static boolean isFragment(IProject pluginProject) {
+		if (pluginProject == null) {
+			return false;
+		}
+		
+		IPluginModelBase pModel = PluginRegistry.findModel(pluginProject);
+		
+		if (pModel == null) {
+			// this project is not a plugin/fragment
+			return false;
+		}
+		
+		return pModel.isFragmentModel();
+	}
+
+	/** 
+	 * Get all fragments for the given host project.
+	 * 
+	 * @param hostProject the host plug-in project in the workspace.
+	 * @return a list of all fragment projects for the given host project which are in the same workspace as the host project.
+	 */
+	public static List<IProject> getFragments(IProject hostProject) {
+		// Check preconditions
+		String hostId = getPluginId(hostProject);
+		if (hostProject == null || hostId == null) {
+			// no valid host project given.
+			return Collections.emptyList();
+		}
+
+		// Get the fragments of the host project
+		IPluginModelBase pModelBase = PluginRegistry.findModel(hostProject);
+		BundleDescription desc = pModelBase.getBundleDescription();
+
+		ArrayList<IPluginModelBase> fragmentModels = new ArrayList<IPluginModelBase>();
+		if (desc == null) {
+			// There is no bundle description for the host project
+			return Collections.emptyList();
+		}
+		
+		BundleDescription[] f = desc.getFragments();
+		for (BundleDescription candidateDesc : f) {
+			IPluginModelBase candidate = PluginRegistry.findModel(candidateDesc);
+			if (candidate instanceof IFragmentModel) {
+				fragmentModels.add(candidate);
+			}
+		}
+		
+		// Get the fragment project which is in the current workspace
+		ArrayList<IProject> fragments = getFragmentsAsWorkspaceProjects(hostProject, fragmentModels);
+		
+		return fragments;
+	}
+
+	/**
+	 * Returns the fragment-id of the project if it is a fragment project with
+	 * the specified host plugin id as host. Else null is returned.
+	 * 
+	 * @param project
+	 *            the project
+	 * @param hostPluginId
+	 *            the host plugin id
+	 * @return the plugin-id or null
+	 */
+	public static String getFragmentId(IProject project, String hostPluginId) {
+		if (!isFragment(project) || hostPluginId == null) {
+			return null;
+		}
+		
+		IPluginModelBase pluginModelBase = PluginRegistry.findModel(project);
+		if (pluginModelBase instanceof IFragmentModel) {
+			IFragmentModel fragmentModel = (IFragmentModel) pluginModelBase;
+			BundleDescription description = fragmentModel.getBundleDescription();
+			HostSpecification hostSpecification = description.getHost();
+
+			if (hostPluginId.equals(hostSpecification.getName())) {
+				return getPluginId(project);
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Returns the host plugin project of the specified project if it contains a
+	 * fragment.
+	 * 
+	 * @param fragment
+	 *            the fragment project
+	 * @return the host plugin project or null
+	 */
+	public static IProject getFragmentHost(IProject fragment) {
+		if (!isFragment(fragment)) {
+			return null;
+		}
+		
+		IPluginModelBase pluginModelBase = PluginRegistry.findModel(fragment);
+		if (pluginModelBase instanceof IFragmentModel) {
+			IFragmentModel fragmentModel = (IFragmentModel) pluginModelBase;
+			BundleDescription description = fragmentModel.getBundleDescription();
+			HostSpecification hostSpecification = description.getHost();
+			
+			IPluginModelBase hostProject = PluginRegistry.findModel(hostSpecification.getName());
+			IProject[] projects = fragment.getWorkspace().getRoot().getProjects();
+			ArrayList<IProject> hostProjects = getPluginProjects(Arrays.asList(hostProject), projects);
+			
+			if (hostProjects.size() != 1) {
+				// hostproject not in workspace
+				return null;
+			} else {
+				return hostProjects.get(0);
+			}
+		}
+		
+		return null;
+	}
+
+	private static ArrayList<IProject> getFragmentsAsWorkspaceProjects(IProject hostProject, ArrayList<IPluginModelBase> fragmentModels) {
+		IProject[] projects = hostProject.getWorkspace().getRoot().getProjects();
+		
+		ArrayList<IProject> fragments = getPluginProjects(fragmentModels, projects);
+		
+		return fragments;
+	}
+
+	private static ArrayList<IProject> getPluginProjects(List<IPluginModelBase> fragmentModels, IProject[] projects) {
+		ArrayList<IProject> fragments = new ArrayList<IProject>();
+		for (IProject project : projects) {
+			IPluginModelBase pModel = PluginRegistry.findModel(project);
+			
+			if (fragmentModels.contains(pModel)) {
+				fragments.add(project);
+			}
+		}
+		
+		return fragments;
+	}
+	
+	private static boolean isPluginProject(IProject project) {
+		try {
+			return project.hasNature(PLUGIN_NATURE);
+		} catch (CoreException ce) {
+			//Logger.logError(ce);
+		}
+		return false;
+	}
+}
\ No newline at end of file
diff --git a/org.eclipse.babel.editor.nls/build.properties b/org.eclipse.babel.editor.nls/build.properties
index c603290..148eb28 100644
--- a/org.eclipse.babel.editor.nls/build.properties
+++ b/org.eclipse.babel.editor.nls/build.properties
@@ -1,6 +1,5 @@
 bin.includes = META-INF/,\
                nl/,\
                plugin_fr.properties
-src.includes = META-INF/,\
-               nl/,\
+src.includes = nl/,\
                plugin_fr.properties
diff --git a/org.eclipse.babel.editor/META-INF/MANIFEST.MF b/org.eclipse.babel.editor/META-INF/MANIFEST.MF
index 25870b8..a65e2f4 100644
--- a/org.eclipse.babel.editor/META-INF/MANIFEST.MF
+++ b/org.eclipse.babel.editor/META-INF/MANIFEST.MF
@@ -16,10 +16,13 @@
  org.eclipse.jdt.core;bundle-version="3.2.0",
  org.eclipse.ltk.core.refactoring,
  org.eclipse.ltk.ui.refactoring,
- org.eclipse.pde.core;bundle-version="3.2.0",
  org.junit;resolution:=optional,
- org.eclipse.babel.core
+ org.eclipse.babel.core;visibility:=reexport,
+ org.eclipse.pde.core;resolution:=optional
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %plugin.provider
-Bundle-RequiredExecutionEnvironment: J2SE-1.5
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
 Bundle-Localization: plugin
+Export-Package: org.eclipse.babel.editor,
+ org.eclipse.babel.editor.api,
+ org.eclipse.babel.editor.wizards
diff --git a/org.eclipse.babel.editor/build.properties b/org.eclipse.babel.editor/build.properties
index d6c8dda..1e98567 100644
--- a/org.eclipse.babel.editor/build.properties
+++ b/org.eclipse.babel.editor/build.properties
@@ -7,10 +7,7 @@
                bin/,\
                plugin.properties,\
                messages.properties
-src.includes = META-INF/,\
-               bin/,\
+src.includes = bin/,\
                icons/,\
                messages.properties,\
-               plugin.properties,\
-               plugin.xml,\
                src/
diff --git a/org.eclipse.babel.editor/icons/missing_translation.gif b/org.eclipse.babel.editor/icons/missing_translation.gif
new file mode 100644
index 0000000..af27508
--- /dev/null
+++ b/org.eclipse.babel.editor/icons/missing_translation.gif
Binary files differ
diff --git a/org.eclipse.babel.editor/icons/missing_translation.png b/org.eclipse.babel.editor/icons/missing_translation.png
index fd40559..7cc7392 100644
--- a/org.eclipse.babel.editor/icons/missing_translation.png
+++ b/org.eclipse.babel.editor/icons/missing_translation.png
Binary files differ
diff --git a/org.eclipse.babel.editor/icons/unused_and_missing_translations.png b/org.eclipse.babel.editor/icons/unused_and_missing_translations.png
index 2bc03e6..19a18b8 100644
--- a/org.eclipse.babel.editor/icons/unused_and_missing_translations.png
+++ b/org.eclipse.babel.editor/icons/unused_and_missing_translations.png
Binary files differ
diff --git a/org.eclipse.babel.editor/icons/unused_translation.png b/org.eclipse.babel.editor/icons/unused_translation.png
index d839c96..d449d03 100644
--- a/org.eclipse.babel.editor/icons/unused_translation.png
+++ b/org.eclipse.babel.editor/icons/unused_translation.png
Binary files differ
diff --git a/org.eclipse.babel.editor/icons/warned_translation.png b/org.eclipse.babel.editor/icons/warned_translation.png
index 2534637..1713d91 100644
--- a/org.eclipse.babel.editor/icons/warned_translation.png
+++ b/org.eclipse.babel.editor/icons/warned_translation.png
Binary files differ
diff --git a/org.eclipse.babel.editor/messages.properties b/org.eclipse.babel.editor/messages.properties
index 573ba76..b2ef016 100644
--- a/org.eclipse.babel.editor/messages.properties
+++ b/org.eclipse.babel.editor/messages.properties
@@ -33,10 +33,16 @@
 editor.wiz.browse           = Browse...
 editor.wiz.bundleName       = &Base Name:
 editor.wiz.creating         = Creating
+editor.wiz.createfolder     = The folder "%s" does not exist. Do you want to create it?
 editor.wiz.desc             = This wizard creates a set of new files with *.properties extension that can be opened by the ResourceBundle editor.
 editor.wiz.error.bundleName = Base name must be specified.
 editor.wiz.error.container  = Files container must be specified.
+editor.wiz.error.locale     = At least one Locale must be added.
 editor.wiz.error.extension  = You can't specify an extension.  It will be appended for you.
+editor.wiz.error.projectnotexist = Project "%s" does not exist.
+editor.wiz.error.invalidpath = You have specified an invalid path.
+editor.wiz.error.couldnotcreatefolder = Error creating folder "%s".
+editor.wiz.error.couldnotcreatefile = Error creating file "%s".
 editor.wiz.folder           = &Folder:
 editor.wiz.opening          = Opening properties files for editing...
 editor.wiz.remove           = <-- Remove
diff --git a/org.eclipse.babel.editor/plugin.xml b/org.eclipse.babel.editor/plugin.xml
index 013f9a3..ea8fa94 100644
--- a/org.eclipse.babel.editor/plugin.xml
+++ b/org.eclipse.babel.editor/plugin.xml
@@ -4,8 +4,8 @@
    <extension
          point="org.eclipse.ui.editors">
       <editor
-            class="org.eclipse.babel.editor.MessagesEditor"
-            contributorClass="org.eclipse.babel.editor.MessagesEditorContributor"
+            class="org.eclipse.babel.editor.internal.MessagesEditor"
+            contributorClass="org.eclipse.babel.editor.internal.MessagesEditorContributor"
             default="true"
             extensions="properties"
             icon="icons/propertiesfile.gif"
@@ -152,9 +152,9 @@
     </category>
     <wizard
           category="org.eclipse.babel.editor.wizards.ResourceBundle"
-          class="org.eclipse.babel.editor.wizards.ResourceBundleWizard"
+          class="org.eclipse.babel.editor.wizards.internal.ResourceBundleWizard"
           icon="icons/resourcebundle.gif"
-          id="org.eclipse.babel.editor.wizards.ResourceBundleWizard"
+          id="org.eclipse.babel.editor.wizards.internal.ResourceBundleWizard"
           name="%wizard.rb.title">
        <description>
           %wizard.rb.description
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/IMessagesEditor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/IMessagesEditor.java
new file mode 100644
index 0000000..8774bc5
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/IMessagesEditor.java
@@ -0,0 +1,17 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Matthias Lettmayer.
+ * 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:
+ *     Matthias Lettmayer - created interface to select a key in an editor (fixed issue 59)
+ ******************************************************************************/
+package org.eclipse.babel.editor;
+
+public interface IMessagesEditor {
+	String getSelectedKey();
+
+	void setSelectedKey(String key);
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/IMessagesEditorChangeListener.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/IMessagesEditorChangeListener.java
index 312542f..d41a0f3 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/IMessagesEditorChangeListener.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/IMessagesEditorChangeListener.java
@@ -10,7 +10,7 @@
  ******************************************************************************/
 package org.eclipse.babel.editor;
 
-import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
 
 
 
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditor.java
deleted file mode 100644
index 0c30b8b..0000000
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditor.java
+++ /dev/null
@@ -1,427 +0,0 @@
-/*******************************************************************************
- * 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;
-
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.Locale;
-
-import org.eclipse.babel.core.message.MessageException;
-import org.eclipse.babel.core.message.MessagesBundle;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.resource.IMessagesResource;
-import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
-import org.eclipse.babel.editor.builder.ToggleNatureAction;
-import org.eclipse.babel.editor.bundle.MessagesBundleGroupFactory;
-import org.eclipse.babel.editor.i18n.I18NPage;
-import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
-import org.eclipse.babel.editor.preferences.MsgEditorPreferences;
-import org.eclipse.babel.editor.resource.EclipsePropertiesEditorResource;
-import org.eclipse.babel.editor.util.UIUtils;
-import org.eclipse.babel.editor.views.MessagesBundleGroupOutline;
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IMarker;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.IProgressMonitor;
-import org.eclipse.jface.dialogs.ErrorDialog;
-import org.eclipse.jface.util.IPropertyChangeListener;
-import org.eclipse.swt.SWT;
-import org.eclipse.ui.IEditorInput;
-import org.eclipse.ui.IEditorPart;
-import org.eclipse.ui.IEditorReference;
-import org.eclipse.ui.IEditorSite;
-import org.eclipse.ui.IFileEditorInput;
-import org.eclipse.ui.IWorkbenchPage;
-import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.editors.text.TextEditor;
-import org.eclipse.ui.ide.IDE;
-import org.eclipse.ui.ide.IGotoMarker;
-import org.eclipse.ui.part.MultiPageEditorPart;
-import org.eclipse.ui.texteditor.ITextEditor;
-import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
-
-/**
- * Multi-page editor for editing resource bundles.
- */
-public class MessagesEditor extends MultiPageEditorPart
-        implements IGotoMarker {
-
-    /** Editor ID, as defined in plugin.xml. */
-    public static final String EDITOR_ID = 
-       "org.eclilpse.babel.editor.editor.MessagesEditor"; //$NON-NLS-1$
-
-    private String selectedKey;
-    private List<IMessagesEditorChangeListener> changeListeners = new ArrayList<IMessagesEditorChangeListener>(2);
-    
-    /** MessagesBundle group. */
-    private MessagesBundleGroup messagesBundleGroup;
-
-    /** Page with key tree and text fields for all locales. */
-    private I18NPage i18nPage;
-    private final List<Locale> localesIndex = new ArrayList<Locale>();
-    private final List<ITextEditor> textEditorsIndex = new ArrayList<ITextEditor>();
-    
-    private MessagesBundleGroupOutline outline;
-    
-    private MessagesEditorMarkers markers;
-    
-    
-    private AbstractKeyTreeModel keyTreeModel;
-    
-    /**
-     * Creates a multi-page editor example.
-     */
-    public MessagesEditor() {
-        super();
-        outline = new MessagesBundleGroupOutline(this);
-    }
-    
-    public MessagesEditorMarkers getMarkers() {
-        return markers;
-    }
-    
-    private IPropertyChangeListener preferenceListener;
-    
-    /**
-     * The <code>MultiPageEditorExample</code> implementation of this method
-     * checks that the input is an instance of <code>IFileEditorInput</code>.
-     */
-    public void init(IEditorSite site, IEditorInput editorInput)
-        throws PartInitException {
-    	
-    	if (editorInput instanceof IFileEditorInput) {
-            IFile file = ((IFileEditorInput) editorInput).getFile();
-            if (MsgEditorPreferences.getInstance().isBuilderSetupAutomatically()) {
-	            IProject p = file.getProject();
-	            if (p != null && p.isAccessible()) {
-	            	ToggleNatureAction.addOrRemoveNatureOnProject(p, true, true);
-	            }
-            }
-            try {
-                messagesBundleGroup = MessagesBundleGroupFactory.createBundleGroup(site, file);
-            } catch (MessageException e) {
-                throw new PartInitException(
-                        "Cannot create bundle group.", e); //$NON-NLS-1$
-            }
-            markers = new MessagesEditorMarkers(messagesBundleGroup);
-            setPartName(messagesBundleGroup.getName());
-            setTitleImage(UIUtils.getImage(UIUtils.IMAGE_RESOURCE_BUNDLE));
-            closeIfAreadyOpen(site, file);
-            super.init(site, editorInput);
-            //TODO figure out model to use based on preferences
-            keyTreeModel = new AbstractKeyTreeModel(messagesBundleGroup);
-//            markerManager = new RBEMarkerManager(this);
-        } else {
-            throw new PartInitException(
-                    "Invalid Input: Must be IFileEditorInput"); //$NON-NLS-1$
-        }
-    }
-
-//    public RBEMarkerManager getMarkerManager() {
-//        return markerManager;
-//    }
-    
-    /**
-     * Creates the pages of the multi-page editor.
-     */
-    protected void createPages() {
-        // Create I18N page
-        i18nPage = new I18NPage(
-                getContainer(), SWT.NONE, this);
-        int index = addPage(i18nPage);
-        setPageText(index, MessagesEditorPlugin.getString(
-                "editor.properties")); //$NON-NLS-1$
-        setPageImage(index, UIUtils.getImage(UIUtils.IMAGE_RESOURCE_BUNDLE));
-        
-        // Create text editor pages for each locales
-        try {
-            Locale[] locales = messagesBundleGroup.getLocales();
-            //first: sort the locales.
-            UIUtils.sortLocales(locales);
-            //second: filter+sort them according to the filter preferences.
-            locales = UIUtils.filterLocales(locales);
-            for (int i = 0; i < locales.length; i++) {
-            	Locale locale = locales[i];
-                MessagesBundle messagesBundle = messagesBundleGroup.getMessagesBundle(locale);
-                IMessagesResource resource = messagesBundle.getResource();
-                TextEditor textEditor = (TextEditor) resource.getSource();
-                index = addPage(textEditor, textEditor.getEditorInput());
-                setPageText(index, UIUtils.getDisplayName(
-                        messagesBundle.getLocale()));
-                setPageImage(index, 
-                        UIUtils.getImage(UIUtils.IMAGE_PROPERTIES_FILE));
-                localesIndex.add(locale);
-                textEditorsIndex.add(textEditor);
-            } 
-        } catch (PartInitException e) {
-            ErrorDialog.openError(getSite().getShell(), 
-                "Error creating text editor page.", //$NON-NLS-1$
-                null, e.getStatus());
-        }
-    }
-    
-    /**
-     * Called when the editor's pages need to be reloaded.
-     * For example when the filters of locale is changed.
-     * <p>
-     * Currently this only reloads the index page.
-     * TODO: remove and add the new locales? it actually looks quite hard to do.
-     * </p>
-     */
-    public void reloadDisplayedContents() {
-    	super.removePage(0);
-    	int currentlyActivePage = super.getActivePage();
-    	i18nPage.dispose();
-    	i18nPage = new I18NPage(
-                getContainer(), SWT.NONE, this);
-    	super.addPage(0, i18nPage);
-    	if (currentlyActivePage == 0) {
-    		super.setActivePage(currentlyActivePage);
-    	}
-    }
-
-    /**
-     * Saves the multi-page editor's document.
-     */
-    public void doSave(IProgressMonitor monitor) {
-        for (ITextEditor textEditor : textEditorsIndex) {
-            textEditor.doSave(monitor);
-        }
-//        i18nPage.refreshEditorOnChanges();
-//        resourceMediator.save(monitor);
-    }
-    
-    /**
-     * @see org.eclipse.ui.ISaveablePart#doSaveAs()
-     */
-    public void doSaveAs() {
-        // Save As not allowed.
-    }
-    
-    /**
-     * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
-     */
-    public boolean isSaveAsAllowed() {
-        return false;
-    }
-
-    /**
-     * Change current page based on locale.  If there is no editors associated
-     * with current locale, do nothing.
-     * @param locale locale used to identify the page to change to
-     */
-    public void setActivePage(Locale locale) {
-        int index = localesIndex.indexOf(locale);
-        if (index > -1) {
-            setActivePage(index + 1);
-        }
-    }
-
-    /**
-     * @see org.eclipse.ui.ide.IGotoMarker#gotoMarker(
-     *         org.eclipse.core.resources.IMarker)
-     */
-    public void gotoMarker(IMarker marker) {
-//        String key = marker.getAttribute(RBEMarker.KEY, "");
-//        if (key != null && key.length() > 0) {
-//            setActivePage(0);
-//            setSelectedKey(key);
-//            getI18NPage().selectLocale(BabelUtils.parseLocale(
-//                    marker.getAttribute(RBEMarker.LOCALE, "")));
-//        } else {
-            IResource resource = marker.getResource();
-            Locale[] locales = messagesBundleGroup.getLocales();
-            for (int i = 0; i < locales.length; i++) {
-                IMessagesResource messagesResource =
-                        messagesBundleGroup.getMessagesBundle(locales[i]).getResource();
-                if (messagesResource instanceof EclipsePropertiesEditorResource) {
-                    EclipsePropertiesEditorResource propFile =
-                            (EclipsePropertiesEditorResource) messagesResource;
-                    if (resource.equals(propFile.getResource())) {
-                    	//ok we got the locale.
-                    	//try to open the master i18n page and select the corresponding key.
-                    	try {
-	                    	String key = (String) marker.getAttribute(IMarker.LOCATION);
-	                    	if (key != null && key.length() > 0) {
-	                    		getI18NPage().selectLocale(locales[i]);
-	                    		setActivePage(0);
-	                    		setSelectedKey(key);
-	                    		return;
-	                    	}
-                    	} catch (Exception e) {
-                    		e.printStackTrace();//something better.s
-                    	}
-                    	//it did not work... fall back to the text editor.
-                        setActivePage(locales[i]);
-                        IDE.gotoMarker(
-                                (IEditorPart) propFile.getSource(), marker);
-                        break;
-                    }
-                }
-            }
-//        }
-    }
-    
-    /**
-     * Calculates the contents of page GUI page when it is activated.
-     */
-    protected void pageChange(int newPageIndex) {
-        super.pageChange(newPageIndex);
-//        if (newPageIndex == 0) {
-//            resourceMediator.reloadProperties();
-//            i18nPage.refreshTextBoxes();
-//        }
-    }
-
-    
-    /**
-     * Is the given file a member of this resource bundle.
-     * @param file file to test
-     * @return <code>true</code> if file is part of bundle
-     */
-    public boolean isBundleMember(IFile file) {
-//        return resourceMediator.isResource(file);
-        return false;
-    }
-
-    private void closeIfAreadyOpen(IEditorSite site, IFile file) {
-        IWorkbenchPage[] pages = site.getWorkbenchWindow().getPages();
-        for (int i = 0; i < pages.length; i++) {
-            IWorkbenchPage page = pages[i];
-            IEditorReference[] editors = page.getEditorReferences();
-            for (int j = 0; j < editors.length; j++) {
-                IEditorPart editor = editors[j].getEditor(false);
-                if (editor instanceof MessagesEditor) {
-                    MessagesEditor rbe = (MessagesEditor) editor;
-                    if (rbe.isBundleMember(file)) {
-                        page.closeEditor(editor, true);
-                    }
-                }
-            }
-        }
-    }
-
-    
-    
-    /**
-     * @see org.eclipse.ui.IWorkbenchPart#dispose()
-     */
-    public void dispose() {
-        for (IMessagesEditorChangeListener listener : changeListeners) {
-            listener.editorDisposed();
-        }
-        i18nPage.dispose();
-        for (ITextEditor textEditor : textEditorsIndex) {
-            textEditor.dispose();
-        }
-    }
-
-
-    /**
-     * @return Returns the selectedKey.
-     */
-    public String getSelectedKey() {
-        return selectedKey;
-    }
-    /**
-     * @param selectedKey The selectedKey to set.
-     */
-    public void setSelectedKey(String activeKey) {
-        if ((selectedKey == null && activeKey != null)
-                || (selectedKey != null && activeKey == null)
-                || (selectedKey != null && !selectedKey.equals(activeKey))) {
-            String oldKey = this.selectedKey;
-            this.selectedKey = activeKey;
-            for (IMessagesEditorChangeListener listener : changeListeners) {
-                listener.selectedKeyChanged(oldKey, activeKey);
-            }
-        }
-    }
-
-    public void addChangeListener(IMessagesEditorChangeListener listener) {
-        changeListeners.add(0, listener);
-    }
-    
-    public void removeChangeListener(IMessagesEditorChangeListener listener) {
-        changeListeners.remove(listener);
-    }
-    
-    public Collection<IMessagesEditorChangeListener> getChangeListeners() {
-        return changeListeners;
-    }
-    
-    /**
-     * @return Returns the messagesBundleGroup.
-     */
-    public MessagesBundleGroup getBundleGroup() {
-        return messagesBundleGroup;
-    }
-
-    /**
-     * @return Returns the keyTreeModel.
-     */
-    public AbstractKeyTreeModel getKeyTreeModel() {
-        return keyTreeModel;
-    }
-
-    /**
-     * @param keyTreeModel The keyTreeModel to set.
-     */
-    public void setKeyTreeModel(AbstractKeyTreeModel newKeyTreeModel) {
-        if ((this.keyTreeModel == null && newKeyTreeModel != null)
-                || (keyTreeModel != null && newKeyTreeModel == null)
-                || (!keyTreeModel.equals(newKeyTreeModel))) {
-        	AbstractKeyTreeModel oldModel = this.keyTreeModel;
-            this.keyTreeModel = newKeyTreeModel;
-            for (IMessagesEditorChangeListener listener : changeListeners) {
-            	listener.keyTreeModelChanged(oldModel, newKeyTreeModel);
-            }
-        }
-    }
-
-    public I18NPage getI18NPage() {
-        return i18nPage;
-    }
-    
-    /** one of the SHOW_* constants defined in the {@link IMessagesEditorChangeListener} */    
-    private int showOnlyMissingAndUnusedKeys = IMessagesEditorChangeListener.SHOW_ALL;
-    /**
-     * @return true when only unused and missing keys should be displayed. flase by default.
-     */
-    public int isShowOnlyUnusedAndMissingKeys() {
-        return showOnlyMissingAndUnusedKeys;
-    }
-    
-    public void setShowOnlyUnusedMissingKeys(int showFlag) {
-        showOnlyMissingAndUnusedKeys = showFlag;
-        for (IMessagesEditorChangeListener listener : getChangeListeners()) {
-        	listener.showOnlyUnusedAndMissingChanged(showFlag);
-        }
-    }
-
-    public Object getAdapter(Class adapter) {
-        Object obj = super.getAdapter(adapter);
-        if (obj == null) {
-            if (IContentOutlinePage.class.equals(adapter)) {
-                return (outline);
-            }
-        }
-        return (obj);
-    }
-
-    public ITextEditor getTextEditor(Locale locale) {
-        int index = localesIndex.indexOf(locale);
-        return textEditorsIndex.get(index);
-    }
-}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/FilterKeysAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/FilterKeysAction.java
index fc7bea7..2125e32 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/FilterKeysAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/FilterKeysAction.java
@@ -11,12 +11,14 @@
 package org.eclipse.babel.editor.actions;
 
 import org.eclipse.babel.editor.IMessagesEditorChangeListener;
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorChangeAdapter;
-import org.eclipse.babel.editor.MessagesEditorContributor;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorChangeAdapter;
+import org.eclipse.babel.editor.internal.MessagesEditorContributor;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.swt.graphics.Image;
 
 /**
  * 
@@ -73,11 +75,27 @@
     	}
 		setText(getTextInternal());
 		setToolTipText(getTooltipInternal());
-        setImageDescriptor(UIUtils.getImageDescriptor(getImageKey()));
+        setImageDescriptor(ImageDescriptor.createFromImage(getImage()));
 
     }
     
-    public String getImageKey() {
+    public Image getImage() {
+    	switch (flagToSet) {
+    	case IMessagesEditorChangeListener.SHOW_ONLY_MISSING:
+    		//return UIUtils.IMAGE_MISSING_TRANSLATION;
+    		return UIUtils.getMissingTranslationImage();
+    	case IMessagesEditorChangeListener.SHOW_ONLY_MISSING_AND_UNUSED:
+    		//return UIUtils.IMAGE_UNUSED_AND_MISSING_TRANSLATIONS;
+    		return UIUtils.getMissingAndUnusedTranslationsImage();
+    	case IMessagesEditorChangeListener.SHOW_ONLY_UNUSED:
+    		//return UIUtils.IMAGE_UNUSED_TRANSLATION;
+    		return UIUtils.getUnusedTranslationsImage();
+    	case IMessagesEditorChangeListener.SHOW_ALL:
+    	default:
+    		return UIUtils.getImage(UIUtils.IMAGE_KEY); 
+    	}
+    }
+    /*public String getImageKey() {
     	switch (flagToSet) {
     	case IMessagesEditorChangeListener.SHOW_ONLY_MISSING:
     		return UIUtils.IMAGE_MISSING_TRANSLATION;
@@ -89,7 +107,7 @@
     	default:
     		return UIUtils.IMAGE_KEY; 
     	}
-    }
+    }*/
     
     public String getTextInternal() {
     	switch (flagToSet) {
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/KeyTreeVisibleAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/KeyTreeVisibleAction.java
index e5c624b..8853a80 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/KeyTreeVisibleAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/KeyTreeVisibleAction.java
@@ -10,8 +10,8 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.actions;
 
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorChangeAdapter;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorChangeAdapter;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.IAction;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/NewLocaleAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/NewLocaleAction.java
index 0f92c9a..a935550 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/NewLocaleAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/actions/NewLocaleAction.java
@@ -7,12 +7,21 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Matthias Lettmayer - implemented action and created dialog
  ******************************************************************************/
 package org.eclipse.babel.editor.actions;
 
-import org.eclipse.babel.editor.MessagesEditor;
+import java.util.Locale;
+
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.util.UIUtils;
+import org.eclipse.babel.editor.widgets.LocaleSelector;
 import org.eclipse.jface.action.Action;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
 
 /**
  * @author Pascal Essiembre
@@ -27,12 +36,8 @@
      */
     public NewLocaleAction() {
         super("New &Locale...");
-//        setText();
         setToolTipText("Add a new locale to the resource bundle.");
-        setImageDescriptor(UIUtils.getImageDescriptor(UIUtils.IMAGE_NEW_PROPERTIES_FILE));
-        
-        
-        
+        setImageDescriptor(UIUtils.getImageDescriptor(UIUtils.IMAGE_NEW_PROPERTIES_FILE));         
     }
 
     //TODO RBEditor hold such an action registry.  Then move this method to constructor
@@ -44,7 +49,51 @@
      * @see org.eclipse.jface.action.Action#run()
      */
     public void run() {
+    	// created choose locale dialog
+    	Dialog localeDialog = new Dialog(editor.getSite().getShell()) {    		
+    		LocaleSelector selector;
+    		
+    		@Override
+    		protected void configureShell(Shell newShell) {
+    			super.configureShell(newShell);
+    			newShell.setText("Add new local");
+    		}
+    		
+    		@Override
+    		protected Control createDialogArea(Composite parent) {
+    			Composite comp = (Composite) super.createDialogArea(parent);
+    			selector = new LocaleSelector(comp);
+    			return comp;
+    		}
+    		
+    		@Override
+    		protected void okPressed() {
+    			// add local to bundleGroup
+    	    	MessagesBundleGroup bundleGroup = editor.getBundleGroup();  
+    	    	Locale newLocal = selector.getSelectedLocale();
+    	    	
+    	    	// exists local already?
+    	    	boolean existsLocal = false;
+    	    	Locale[] locales = bundleGroup.getLocales();
+    	    	for (Locale locale : locales) {
+    	    		if (locale == null) {
+    	    			if (newLocal == null) {
+    	    				existsLocal = true;
+    	    				break;
+    	    			}
+    	    		} else if (locale.equals(newLocal)) {
+    	    			existsLocal = true;
+    	    			break;
+    	    		}    	    			
+    	    	}
+    	    	
+    	    	if (! existsLocal)
+    	    		bundleGroup.addMessagesBundle(newLocal);
+    	    	
+    			super.okPressed();
+    		}
+		};
+		// open dialog
+    	localeDialog.open();    	
     }
-    
-    
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/AnalyzerFactory.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/AnalyzerFactory.java
new file mode 100644
index 0000000..8804d6d
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/AnalyzerFactory.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.api;
+
+import org.eclipse.babel.core.message.checks.proximity.IProximityAnalyzer;
+import org.eclipse.babel.core.message.checks.proximity.LevenshteinDistanceAnalyzer;
+
+/**
+ * Provides the {@link IProximityAnalyzer}
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public class AnalyzerFactory {
+
+	/**
+	 * @return An instance of the {@link LevenshteinDistanceAnalyzer}
+	 */
+	public static IProximityAnalyzer getLevenshteinDistanceAnalyzer () {
+		return (IProximityAnalyzer) LevenshteinDistanceAnalyzer.getInstance();
+	}
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/EditorUtil.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/EditorUtil.java
new file mode 100644
index 0000000..b00f4b2
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/EditorUtil.java
@@ -0,0 +1,33 @@
+package org.eclipse.babel.editor.api;
+
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.editor.i18n.I18NPage;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ui.IWorkbenchPage;
+
+/**
+ * Util class for editor operations.
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public class EditorUtil {
+	
+	/**
+	 * @param page The {@link IWorkbenchPage}
+	 * @return The selected {@link IKeyTreeNode} of the page.
+	 */
+    public static IKeyTreeNode getSelectedKeyTreeNode (IWorkbenchPage page) {
+        MessagesEditor editor = (MessagesEditor)page.getActiveEditor();
+        if (editor.getSelectedPage() instanceof I18NPage) {
+            I18NPage p = (I18NPage) editor.getSelectedPage();
+            ISelection selection = p.getSelection();
+            if (!selection.isEmpty() && selection instanceof IStructuredSelection) {
+                return (IKeyTreeNode) ((IStructuredSelection) selection).getFirstElement();
+            }
+        }
+        return null;
+    }
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/IValuedKeyTreeNode.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/IValuedKeyTreeNode.java
new file mode 100644
index 0000000..88e53f9
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/IValuedKeyTreeNode.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer.
+ * 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:
+ *     Martin Reiterer - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.api;
+
+import java.util.Collection;
+import java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+
+public interface IValuedKeyTreeNode extends IKeyTreeNode {
+
+	public void initValues(Map<Locale, String> values);
+
+	public void addValue(Locale locale, String value);
+
+	public void setValue(Locale locale, String newValue);
+
+	public String getValue(Locale locale);
+
+	public Collection<String> getValues();
+
+	public void setInfo(Object info);
+
+	public Object getInfo();
+
+	public Collection<Locale> getLocales();
+
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/KeyTreeFactory.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/KeyTreeFactory.java
new file mode 100644
index 0000000..ddc9983
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/KeyTreeFactory.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.api;
+
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.IAbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
+
+
+/**
+ * Factory class for the tree or nodes of the tree.
+ * @see IAbstractKeyTreeModel
+ * @see IValuedKeyTreeNode
+ * <br><br>
+ * 
+ * @author Alexej Strelzow
+ */
+public class KeyTreeFactory {
+
+	/**
+	 * @param messagesBundleGroup Input of the key tree model
+	 * @return The {@link IAbstractKeyTreeModel}
+	 */
+    public static IAbstractKeyTreeModel createModel(IMessagesBundleGroup messagesBundleGroup) {
+        return new AbstractKeyTreeModel((MessagesBundleGroup)messagesBundleGroup);
+    }
+    
+    /**
+     * @param parent The parent node
+     * @param name The name of the node
+     * @param id The id of the node (messages key)
+     * @param bundleGroup The {@link IMessagesBundleGroup} 
+     * @return A new instance of {@link IValuedKeyTreeNode}
+     */
+    public static IValuedKeyTreeNode createKeyTree(IKeyTreeNode parent, String name, String id, 
+    		IMessagesBundleGroup bundleGroup) {
+        return new ValuedKeyTreeNode(parent, name, id, bundleGroup);
+    }
+    
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/ValuedKeyTreeNode.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/ValuedKeyTreeNode.java
new file mode 100644
index 0000000..9571db1
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/api/ValuedKeyTreeNode.java
@@ -0,0 +1,73 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer.
+ * 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:
+ *     Martin Reiterer - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.api;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
+
+
+public class ValuedKeyTreeNode extends KeyTreeNode implements IValuedKeyTreeNode {
+
+    public ValuedKeyTreeNode(IKeyTreeNode parent, String name, String messageKey,
+            IMessagesBundleGroup messagesBundleGroup) {
+        super(parent, name, messageKey, messagesBundleGroup);
+    }
+
+    private Map<Locale, String> values = new HashMap<Locale, String>();
+    private Object info;
+
+    public void initValues (Map<Locale, String> values) {
+        this.values = values;
+    }
+
+    public void addValue (Locale locale, String value) {
+        values.put(locale, value);
+    }
+    
+    public String getValue (Locale locale) {
+        return values.get(locale);
+    }
+    
+    public void setValue(Locale locale, String newValue) {
+    	if (values.containsKey(locale))
+    		values.remove(locale);
+    	addValue(locale, newValue);
+    }
+    
+    public Collection<String> getValues () {
+        return values.values();
+    }
+
+    public void setInfo(Object info) {
+        this.info = info;
+    }
+
+    public Object getInfo() {
+        return info;
+    }
+    
+    public Collection<Locale> getLocales () {
+        List<Locale> locs = new ArrayList<Locale> ();
+        for (Locale loc : values.keySet()) {
+            locs.add(loc);
+        }
+        return locs;
+    }
+    
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/builder/Builder.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/builder/Builder.java
index e8ca2c5..0b081bf 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/builder/Builder.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/builder/Builder.java
@@ -18,8 +18,10 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.eclipse.babel.core.message.MessagesBundle;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.manager.RBManager;
 import org.eclipse.babel.editor.bundle.MessagesBundleGroupFactory;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.babel.editor.resource.validator.FileMarkerStrategy;
@@ -62,6 +64,7 @@
 				break;
 			case IResourceDelta.REMOVED:
                 System.out.println("RBE DELTA Removed"); //$NON-NLS-1$
+                RBManager.getInstance(delta.getResource().getProject()).notifyResourceRemoved(delta.getResource());
 				// handle removed resource
 				break;
 			case IResourceDelta.CHANGED:
@@ -134,7 +137,7 @@
 				if (_alreadBuiltMessageBundle != null) {
 					for (MessagesBundleGroup msgGrp : _alreadBuiltMessageBundle.values()) {
 						try {
-							msgGrp.dispose();
+//							msgGrp.dispose(); // TODO: [alst] do we need this really?
 						} catch (Throwable t) {
 							//FIXME: remove this debugging:
 							System.err.println(
@@ -167,6 +170,8 @@
 	 * @param resource The resource currently validated.
 	 */
 	void checkBundleResource(IResource resource) {
+		if (true)
+		return; // TODO [alst] 
         if (resource instanceof IFile && resource.getName().endsWith(
                 ".properties")) { //$NON-NLS-1$ //TODO have customized?
             IFile file = (IFile) resource;
@@ -190,14 +195,14 @@
             		//cheaper than creating a group for each on of those
             		//files.
             		boolean validateEntireGroup = false;
-                	for (MessagesBundle msgBundle : msgBundleGrp.getMessagesBundles()) {
-            			Object src = msgBundle.getResource().getSource();
+                	for (IMessagesBundle msgBundle : msgBundleGrp.getMessagesBundles()) {
+            			Object src = ((MessagesBundle)msgBundle).getResource().getSource();
             			//System.err.println(src + " -> " + msgBundleGrp);
             			if (src instanceof IFile) {//when it is a read-only thing we don't index it.
 	            			_alreadBuiltMessageBundle.put((IFile)src, msgBundleGrp);
 	            			if (!validateEntireGroup && src == resource) {
-	            				if (msgBundle.getLocale() == null
-	            						|| msgBundle.getLocale().equals(UIUtils.ROOT_LOCALE)) {
+	            				if (((MessagesBundle)msgBundle).getLocale() == null
+	            						|| ((MessagesBundle)msgBundle).getLocale().equals(UIUtils.ROOT_LOCALE)) {
 	            					//ok the default properties have been changed.
 	            					//make sure that all resources in this bundle group
 	            					//are validated too:
@@ -213,8 +218,8 @@
             			}
             		}
             		if (validateEntireGroup) {
-                    	for (MessagesBundle msgBundle : msgBundleGrp.getMessagesBundles()) {
-			    			Object src = msgBundle.getResource().getSource();
+                    	for (IMessagesBundle msgBundle : msgBundleGrp.getMessagesBundles()) {
+			    			Object src = ((MessagesBundle)msgBundle).getResource().getSource();
 			    			_resourcesToValidate.add(src);
                    		}
             		}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/BundleGroupRegistry.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/BundleGroupRegistry.java
index 64d1753..2672d15 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/BundleGroupRegistry.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/BundleGroupRegistry.java
@@ -10,7 +10,7 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.bundle;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
 import org.eclipse.core.resources.IResource;
 
 
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/DefaultBundleGroupStrategy.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/DefaultBundleGroupStrategy.java
index 65d42f0..cb8ae2f 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/DefaultBundleGroupStrategy.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/DefaultBundleGroupStrategy.java
@@ -7,17 +7,19 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapJI integration, messagesBundleId
  ******************************************************************************/
 package org.eclipse.babel.editor.bundle;
 
+import java.io.ByteArrayInputStream;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.MessageException;
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.internal.MessageException;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 import org.eclipse.babel.core.message.resource.IMessagesResource;
-import org.eclipse.babel.core.message.resource.PropertiesIFileResource;
+import org.eclipse.babel.core.message.resource.internal.PropertiesIFileResource;
 import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
 import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
 import org.eclipse.babel.core.message.strategy.IMessagesBundleGroupStrategy;
@@ -29,7 +31,12 @@
 import org.eclipse.core.resources.IContainer;
 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.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IPackageFragment;
+import org.eclipse.jdt.core.JavaCore;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IEditorSite;
 import org.eclipse.ui.PartInitException;
@@ -87,11 +94,35 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.strategy.IMessagesBundleGroupStrategy
+     * @see org.eclipse.babel.core.message.internal.strategy.IMessagesBundleGroupStrategy
      *          #createMessagesBundleGroupName()
      */
     public String createMessagesBundleGroupName() {
-        return baseName + "[...]." + file.getFileExtension(); //$NON-NLS-1$
+    	return getProjectName()+"*.properties";
+    }
+    
+    public String createMessagesBundleId() {
+    	return getResourceBundleId(file);
+    }
+    
+    public static String getResourceBundleId (IResource resource) {
+		String packageFragment = "";
+
+		IJavaElement propertyFile = JavaCore.create(resource.getParent());
+		if (propertyFile != null && propertyFile instanceof IPackageFragment)
+			packageFragment = ((IPackageFragment) propertyFile).getElementName();
+		
+		return (packageFragment.length() > 0 ? packageFragment  + "." : "") + 
+				getResourceBundleName(resource);
+	}
+    
+    public static String getResourceBundleName(IResource res) {
+        String name = res.getName();
+    	String regex = "^(.*?)" //$NON-NLS-1$
+                + "((_[a-z]{2,3})|(_[a-z]{2,3}_[A-Z]{2})" //$NON-NLS-1$
+                + "|(_[a-z]{2,3}_[A-Z]{2}_\\w*))?(\\." //$NON-NLS-1$
+                + res.getFileExtension() + ")$"; //$NON-NLS-1$
+        return name.replaceFirst(regex, "$1"); //$NON-NLS-1$
     }
 
     /**
@@ -138,8 +169,22 @@
      * @see org.eclipse.babel.core.bundle.IBundleGroupStrategy#createBundle(java.util.Locale)
      */
     public MessagesBundle createMessagesBundle(Locale locale) {
-        // TODO Auto-generated method stub
-        return null;
+    	// create new empty locale file
+    	IFile openedFile = getOpenedFile();
+    	IPath path = openedFile.getProjectRelativePath();
+    	String localeStr = locale != null ? "_" + locale.toString() : "";
+    	String newFilename = getBaseName()+localeStr+"."+openedFile.getFileExtension();
+        IFile newFile = openedFile.getProject().getFile(path.removeLastSegments(1).addTrailingSeparator()+newFilename);
+        
+        if (! newFile.exists()) {
+        	try {
+        		// create new ifile with an empty input stream
+				newFile.create(new ByteArrayInputStream(new byte[0]), IResource.NONE, null);
+			} catch (CoreException e) {
+				e.printStackTrace();
+			} 
+        }
+    	return createBundle(locale, newFile);
     }
     
     /**
@@ -160,14 +205,14 @@
             	//site is null during the build.
                 messagesResource = new PropertiesIFileResource(
                         locale,
-                        new PropertiesSerializer(prefs),
-                        new PropertiesDeserializer(prefs),
+                        new PropertiesSerializer(prefs.getSerializerConfig()),
+                        new PropertiesDeserializer(prefs.getDeserializerConfig()),
                         (IFile) resource, MessagesEditorPlugin.getDefault());
             } else {
                 messagesResource = new EclipsePropertiesEditorResource(
                         locale,
-                        new PropertiesSerializer(prefs),
-                        new PropertiesDeserializer(prefs),
+                        new PropertiesSerializer(prefs.getSerializerConfig()),
+                        new PropertiesDeserializer(prefs.getDeserializerConfig()),
                         createEditor(resource, locale));
             }
             return new MessagesBundle(messagesResource);
@@ -191,6 +236,12 @@
         
         TextEditor textEditor = null;
         if (resource != null && resource instanceof IFile) {
+        	try {
+				resource.refreshLocal(IResource.DEPTH_ZERO, null);
+			} catch (CoreException e1) {
+				// TODO Auto-generated catch block
+				e1.printStackTrace();
+			}
             IEditorInput newEditorInput = 
                     new FileEditorInput((IFile) resource);
             textEditor = null;
@@ -214,11 +265,15 @@
     	return file;
     }
 
-    /**
+    /** 
      * @return The base name of the resource bundle.
      */
     protected String getBaseName() {
     	return baseName;
     }
+    
+    public String getProjectName() {
+    	return ResourcesPlugin.getWorkspace().getRoot().getProject(file.getFullPath().segments()[0]).getName();
+    }
         
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/MessagesBundleGroupFactory.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/MessagesBundleGroupFactory.java
index bf0516f..bc28df8 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/MessagesBundleGroupFactory.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/MessagesBundleGroupFactory.java
@@ -18,7 +18,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
 import org.eclipse.babel.editor.preferences.MsgEditorPreferences;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.core.resources.IContainer;
@@ -62,9 +62,11 @@
 
     	//check we are inside an eclipse plugin project where NL is supported at runtime:
 		IProject proj = file.getProject();
-		if (proj == null || !UIUtils.hasNature(proj, UIUtils.PDE_NATURE)) { //$NON-NLS-1$
-			return createDefaultBundleGroup(site, file);
-		}
+		try {
+		    if (proj == null || !proj.hasNature(UIUtils.PDE_NATURE)) { //$NON-NLS-1$
+		    	return createDefaultBundleGroup(site, file);
+		    }
+		} catch (CoreException e) { }
 
     	IFolder nl = getNLFolder(file);
     	
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java
index ef9d134..2248b65 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLFragmentBundleGroupStrategy.java
@@ -25,9 +25,9 @@
 import java.util.jar.JarEntry;
 import java.util.jar.JarFile;
 
-import org.eclipse.babel.core.message.MessagesBundle;
-import org.eclipse.babel.core.message.resource.PropertiesIFileResource;
-import org.eclipse.babel.core.message.resource.PropertiesReadOnlyResource;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
+import org.eclipse.babel.core.message.resource.internal.PropertiesIFileResource;
+import org.eclipse.babel.core.message.resource.internal.PropertiesReadOnlyResource;
 import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
 import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
@@ -134,7 +134,7 @@
     }
 
     /**
-     * @see org.eclipse.babel.core.message.strategy.IMessagesBundleGroupStrategy
+     * @see org.eclipse.babel.core.message.internal.strategy.IMessagesBundleGroupStrategy
      *          #createMessagesBundleGroupName()
      */
     public String createMessagesBundleGroupName() {
@@ -175,8 +175,8 @@
 						return new MessagesBundle(
 						        new PropertiesReadOnlyResource(
 									UIUtils.ROOT_LOCALE, 
-	                                new PropertiesSerializer(prefs),
-	                                new PropertiesDeserializer(prefs),
+	                                new PropertiesSerializer(prefs.getSerializerConfig()),
+	                                new PropertiesDeserializer(prefs.getDeserializerConfig()),
 	                                jarredProps[0], jarredProps[1]));
 					}
 					newEditorInput = new DummyEditorInput(jarredProps[0], 
@@ -195,8 +195,8 @@
 					        MsgEditorPreferences.getInstance();
 					return new MessagesBundle(new PropertiesIFileResource(
 								UIUtils.ROOT_LOCALE, 
-                                new PropertiesSerializer(prefs),
-                                new PropertiesDeserializer(prefs), file,
+                                new PropertiesSerializer(prefs.getSerializerConfig()),
+                                new PropertiesDeserializer(prefs.getDeserializerConfig()), file,
                                 MessagesEditorPlugin.getDefault()));
 				} else {
 					//during the build if the file does not exist. skip.
@@ -250,8 +250,8 @@
 						return new MessagesBundle(
 						        new PropertiesReadOnlyResource(
 									UIUtils.ROOT_LOCALE, 
-	                                new PropertiesSerializer(prefs),
-	                                new PropertiesDeserializer(prefs),
+	                                new PropertiesSerializer(prefs.getSerializerConfig()),
+	                                new PropertiesDeserializer(prefs.getDeserializerConfig()),
 	                                contents, resourceLocationLabel));
 	            	}
 	                newEditorInput = new DummyEditorInput(contents, 
@@ -290,8 +290,8 @@
             
             EclipsePropertiesEditorResource readOnly =
                  new EclipsePropertiesEditorResource(UIUtils.ROOT_LOCALE, 
-                        new PropertiesSerializer(prefs),
-                        new PropertiesDeserializer(prefs), textEditor);
+                        new PropertiesSerializer(prefs.getSerializerConfig()),
+                        new PropertiesDeserializer(prefs.getDeserializerConfig()), textEditor);
             if (resourceLocationLabel != null) {
             	readOnly.setResourceLocationLabel(resourceLocationLabel);
             }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLPluginBundleGroupStrategy.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLPluginBundleGroupStrategy.java
index bf42fbf..2b44d37 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLPluginBundleGroupStrategy.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/bundle/NLPluginBundleGroupStrategy.java
@@ -17,7 +17,7 @@
 import java.util.Set;
 import java.util.StringTokenizer;
 
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 import org.eclipse.babel.core.util.BabelUtils;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.core.resources.IContainer;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/EntryRightBanner.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/EntryRightBanner.java
index 3514cd6..1cd28cb 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/EntryRightBanner.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/EntryRightBanner.java
@@ -17,13 +17,13 @@
 import java.util.Observable;
 import java.util.Observer;
 
-import org.eclipse.babel.core.message.checks.DuplicateValueCheck;
 import org.eclipse.babel.core.message.checks.IMessageCheck;
-import org.eclipse.babel.core.message.checks.MissingValueCheck;
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorChangeAdapter;
+import org.eclipse.babel.core.message.checks.internal.DuplicateValueCheck;
+import org.eclipse.babel.core.message.checks.internal.MissingValueCheck;
 import org.eclipse.babel.editor.i18n.actions.ShowDuplicateAction;
 import org.eclipse.babel.editor.i18n.actions.ShowMissingAction;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorChangeAdapter;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.swt.SWT;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NEntry.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NEntry.java
index 0066f9d..13c789b 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NEntry.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NEntry.java
@@ -7,16 +7,20 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - updateKey
  ******************************************************************************/
 package org.eclipse.babel.editor.i18n;
 
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
+import org.eclipse.babel.core.message.IMessage;
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.IMessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.Message;
+import org.eclipse.babel.core.message.manager.RBManager;
 import org.eclipse.babel.core.util.BabelUtils;
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorChangeAdapter;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorChangeAdapter;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.babel.editor.widgets.NullableText;
 import org.eclipse.swt.SWT;
@@ -40,7 +44,8 @@
 public class I18NEntry extends Composite {
 
     private final MessagesEditor editor;
-    private final MessagesBundleGroup messagesBundleGroup;
+    private final String bundleGroupId;
+    private final String projectName;
     private final Locale locale;
 
     private boolean expanded = true;
@@ -60,7 +65,8 @@
         super(parent, SWT.NONE);
         this.editor = editor;
         this.locale = locale;
-        this.messagesBundleGroup = editor.getBundleGroup();
+        this.bundleGroupId = editor.getBundleGroup().getResourceBundleId();
+        this.projectName = editor.getBundleGroup().getProjectName();
         
         GridLayout gridLayout = new GridLayout(1, false);        
         gridLayout.horizontalSpacing = 0;
@@ -147,12 +153,15 @@
     }
     
     public boolean isEditable() {
-    	return ((TextEditor) messagesBundleGroup.
-        	getMessagesBundle(locale).getResource().getSource()).isEditable();
+    	IMessagesBundleGroup messagesBundleGroup = RBManager.getInstance(projectName).getMessagesBundleGroup(bundleGroupId);
+        IMessagesBundle bundle = messagesBundleGroup.getMessagesBundle(locale);
+    	return ((TextEditor) bundle.getResource().getSource()).isEditable();
     }
     
     public String getResourceLocationLabel() {
-    	return messagesBundleGroup.getMessagesBundle(locale).getResource().getResourceLocationLabel();
+    	IMessagesBundleGroup messagesBundleGroup = RBManager.getInstance(projectName).getMessagesBundleGroup(bundleGroupId);
+    	IMessagesBundle bundle = messagesBundleGroup.getMessagesBundle(locale);
+    	return bundle.getResource().getResourceLocationLabel();
     }
     
 //    /*default*/ Text getTextBox() {
@@ -236,35 +245,43 @@
         
         editor.addChangeListener(new MessagesEditorChangeAdapter() {
             public void selectedKeyChanged(String oldKey, String newKey) {
-                boolean isKey =
-                        newKey != null && messagesBundleGroup.isMessageKey(newKey);
-                textBox.setEnabled(isKey);
-                if (isKey) {
-                    Message entry = messagesBundleGroup.getMessage(
-                            newKey, locale);
-                    if (entry == null || entry.getValue() == null) {
-                        textBox.setText(null);
-//                        commentedCheckbox.setSelection(false);
-                    } else {
-//                        commentedCheckbox.setSelection(bundleEntry.isCommented());
-                        textBox.setText(entry.getValue());
-                    }
-                } else {
-                    textBox.setText(null);
-                }
+            	updateKey(newKey);
             }
         });
 
     }
+    
+	void updateKey(String key) {
+		IMessagesBundleGroup messagesBundleGroup = RBManager.getInstance(
+				projectName).getMessagesBundleGroup(bundleGroupId);
+		boolean isKey = key != null && messagesBundleGroup.isMessageKey(key);
+		textBox.setEnabled(isKey);
+		if (isKey) {
+			IMessage entry = messagesBundleGroup.getMessage(key, locale);
+			if (entry == null || entry.getValue() == null) {
+				textBox.setText(null);
+				// commentedCheckbox.setSelection(false);
+			} else {
+				// commentedCheckbox.setSelection(bundleEntry.isCommented());
+				textBox.setText(entry.getValue());
+			}
+		} else {
+			textBox.setText(null);
+		}
+	}
 
     private void updateModel() {
         if (editor.getSelectedKey() != null) {
             if (!BabelUtils.equals(focusGainedText, textBox.getText())) {
+            	IMessagesBundleGroup messagesBundleGroup = RBManager.getInstance(projectName).getMessagesBundleGroup(bundleGroupId);
                 String key = editor.getSelectedKey();
-                Message entry = messagesBundleGroup.getMessage(key, locale);
+                IMessage entry = messagesBundleGroup.getMessage(key, locale);
                 if (entry == null) {
                     entry = new Message(key, locale);
-                    messagesBundleGroup.getMessagesBundle(locale).addMessage(entry);
+                    IMessagesBundle messagesBundle = messagesBundleGroup.getMessagesBundle(locale);
+                    if (messagesBundle != null) {
+                    	messagesBundle.addMessage(entry);
+                    }
                 }
                 entry.setText(textBox.getText());
             }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NPage.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NPage.java
index cc2bfc8..2efe433 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NPage.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/I18NPage.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapiJI integration, fixed issues 37, 48
  ******************************************************************************/
 package org.eclipse.babel.editor.i18n;
 
@@ -15,10 +16,18 @@
 import java.util.Locale;
 import java.util.Map;
 
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.manager.IMessagesEditorListener;
+import org.eclipse.babel.core.message.manager.RBManager;
 import org.eclipse.babel.editor.IMessagesEditorChangeListener;
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorChangeAdapter;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorChangeAdapter;
 import org.eclipse.babel.editor.util.UIUtils;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionChangedListener;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.SashForm;
 import org.eclipse.swt.custom.ScrolledComposite;
@@ -32,7 +41,7 @@
  * at once for all supported locales.
  * @author Pascal Essiembre
  */
-public class I18NPage extends ScrolledComposite {
+public class I18NPage extends ScrolledComposite implements ISelectionProvider {
 
     /** Minimum height of text fields. */
     private static final int TEXT_MIN_HEIGHT = 90;
@@ -41,6 +50,7 @@
     private final SideNavComposite keysComposite;
     private final Composite valuesComposite;
     private final Map<Locale,I18NEntry> entryComposites = new HashMap<Locale,I18NEntry>(); 
+    private Composite entriesComposite;
     
 //    private Composite parent;
     private boolean keyTreeVisible = true;
@@ -92,7 +102,27 @@
         setExpandHorizontal(true);
         setExpandVertical(true);
         setMinWidth(400);
-
+        
+        RBManager instance = RBManager.getInstance(editor.getBundleGroup().getProjectName());
+        instance.addMessagesEditorListener(new IMessagesEditorListener() {
+			
+			public void onSave() {
+				// TODO Auto-generated method stub
+				
+			}
+			
+			public void onModify() {
+				// TODO Auto-generated method stub
+			}
+			
+			public void onResourceChanged(IMessagesBundle bundle) {
+				I18NEntry i18nEntry = entryComposites.get(bundle.getLocale());
+				if (i18nEntry != null && !getSelection().isEmpty()) {
+					i18nEntry.updateKey(String.valueOf(((IStructuredSelection)getSelection()).getFirstElement()));
+				}
+			}
+			
+		});
     }
     
     /**
@@ -127,7 +157,7 @@
         scrolledComposite.setExpandVertical(true);
         scrolledComposite.setSize(SWT.DEFAULT, 100);
 
-        final Composite entriesComposite =
+        entriesComposite =
                 new Composite(scrolledComposite, SWT.BORDER);
         scrolledComposite.setContent(entriesComposite);
         scrolledComposite.setMinSize(entriesComposite.computeSize(
@@ -141,10 +171,7 @@
         locales = UIUtils.filterLocales(locales);
         for (int i = 0; i < locales.length; i++) {
             Locale locale = locales[i];
-            I18NEntry i18NEntry = new I18NEntry(
-                    entriesComposite, editor, locale);
-//            entryComposite.addFocusListener(localBehaviour);
-            entryComposites.put(locale, i18NEntry);
+            addI18NEntry(editor, locale);
         }
         
         editor.addChangeListener(new MessagesEditorChangeAdapter() {
@@ -160,6 +187,14 @@
         return scrolledComposite;
     }
     
+    public void addI18NEntry(MessagesEditor editor, Locale locale) {
+    	I18NEntry i18NEntry = new I18NEntry(
+                entriesComposite, editor, locale);
+//      entryComposite.addFocusListener(localBehaviour);
+        entryComposites.put(locale, i18NEntry);
+        entriesComposite.layout();
+    }
+    
     public void selectLocale(Locale locale) {
         Collection<Locale> locales = entryComposites.keySet();
         for (Locale entryLocale : locales) {
@@ -176,4 +211,25 @@
 //            }
         }
     }
+
+    public void addSelectionChangedListener(ISelectionChangedListener listener) {
+        keysComposite.getTreeViewer().addSelectionChangedListener(listener);
+        
+    }
+
+    public ISelection getSelection() {
+        return keysComposite.getTreeViewer().getSelection();
+    }
+
+    public void removeSelectionChangedListener(ISelectionChangedListener listener) {
+        keysComposite.getTreeViewer().removeSelectionChangedListener(listener);
+    }
+
+    public void setSelection(ISelection selection) {
+        keysComposite.getTreeViewer().setSelection(selection);
+    }
+    
+    public TreeViewer getTreeViewer() {
+    	return keysComposite.getTreeViewer();
+    }
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavComposite.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavComposite.java
index 4625e9e..86da7ff 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavComposite.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavComposite.java
@@ -10,12 +10,12 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.i18n;
 
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.tree.KeyTreeContributor;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.tree.actions.CollapseAllAction;
 import org.eclipse.babel.editor.tree.actions.ExpandAllAction;
 import org.eclipse.babel.editor.tree.actions.FlatModelAction;
 import org.eclipse.babel.editor.tree.actions.TreeModelAction;
+import org.eclipse.babel.editor.tree.internal.KeyTreeContributor;
 import org.eclipse.jface.action.Separator;
 import org.eclipse.jface.action.ToolBarManager;
 import org.eclipse.jface.viewers.TreeViewer;
@@ -72,13 +72,27 @@
         
         //TODO have two toolbars, one left-align, and one right, with drop
         //down menu
-        
+//        initListener();
         
 //        createTopSection();
         createKeyTree();
         new SideNavTextBoxComposite(this, editor);
     }
 
+//    private void initListener() {
+//        IResourceChangeListener listener = new IResourceChangeListener() {
+//            
+//            public void resourceChanged(IResourceChangeEvent event) {
+//                if (!Boolean.valueOf(System.getProperty("dirty"))) {
+//                    createKeyTree();
+//                }
+//            }
+//        };
+//        
+//        ResourcesPlugin.getWorkspace().addResourceChangeListener(listener, IResourceChangeEvent.PRE_DELETE | IResourceChangeEvent.POST_CHANGE);
+//        
+//    }
+
     /**
      * Gets the tree viewer.
      * @return tree viewer
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavTextBoxComposite.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavTextBoxComposite.java
index f97ace2..02f82e7 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavTextBoxComposite.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/SideNavTextBoxComposite.java
@@ -10,10 +10,10 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.i18n;
 
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
 import org.eclipse.babel.core.message.tree.visitor.NodePathRegexVisitor;
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorChangeAdapter;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorChangeAdapter;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.KeyAdapter;
@@ -93,7 +93,7 @@
                     NodePathRegexVisitor visitor = new NodePathRegexVisitor(
                             "^" + key + ".*");  //$NON-NLS-1$//$NON-NLS-2$
                     editor.getKeyTreeModel().accept(visitor, null);
-                    KeyTreeNode node = visitor.getKeyTreeNode();
+                    IKeyTreeNode node = visitor.getKeyTreeNode();
                     if (node != null) {
                         syncAddTextBox = false;
                         editor.setSelectedKey(node.getMessageKey());
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/actions/ShowDuplicateAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/actions/ShowDuplicateAction.java
index a9586d7..08e5763 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/actions/ShowDuplicateAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/i18n/actions/ShowDuplicateAction.java
@@ -17,51 +17,54 @@
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.swt.widgets.Display;
 
-
 /**
  * @author Pascal Essiembre
- *
+ * 
  */
 public class ShowDuplicateAction extends Action {
 
-    private final String[] keys;
-    private final String key;
-    private final Locale locale;
-    
-    /**
+	private final String[] keys;
+	private final String key;
+	private final Locale locale;
+
+	/**
      * 
      */
-    public ShowDuplicateAction(String[] keys, String key, Locale locale) {
-        super();
-        this.keys = keys;
-        this.key = key;
-        this.locale = locale;
-        setText("Show duplicate keys.");
-        setImageDescriptor(
-                UIUtils.getImageDescriptor("duplicate.gif"));
-        setToolTipText("TODO put something here"); //TODO put tooltip
-    }
+	public ShowDuplicateAction(String[] keys, String key, Locale locale) {
+		super();
+		this.keys = keys;
+		this.key = key;
+		this.locale = locale;
+		setText("Show duplicate keys.");
+		setImageDescriptor(UIUtils.getImageDescriptor(UIUtils.IMAGE_DUPLICATE));
+		setToolTipText("Check duplicate values");
+	}
 
-    /* (non-Javadoc)
-     * @see org.eclipse.jface.action.IAction#run()
-     */
-    public void run() {
-        //TODO have preference for whether to do cross locale checking
-        StringBuffer buf = new StringBuffer("\"" + key + "\" (" + UIUtils.getDisplayName(locale) + ") has the same "
-                + "value as the following key(s): \n\n");
-        for (int i = 0; i < keys.length; i++) {
-            String duplKey = keys[i];
-            if (!key.equals(duplKey)) {
-                buf.append("    · ");
-                buf.append(duplKey);
-                buf.append(" (" + UIUtils.getDisplayName(locale) + ")");
-                buf.append("\n");
-            }
-        }
-        MessageDialog.openInformation(
-                Display.getDefault().getActiveShell(),
-                "Duplicate value",
-                buf.toString());
-    }
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see org.eclipse.jface.action.IAction#run()
+	 */
+	public void run() {
+		// TODO have preference for whether to do cross locale checking
+		StringBuffer buf = new StringBuffer("\"" + key + "\" ("
+				+ UIUtils.getDisplayName(locale) + ") has the same "
+				+ "value as the following key(s): \n\n");
+
+		if (keys != null) { // keys = duplicated values
+			for (int i = 0; i < keys.length; i++) {
+				String duplKey = keys[i];
+				if (!key.equals(duplKey)) {
+					buf.append("    · ");
+					buf.append(duplKey);
+					buf.append(" (" + UIUtils.getDisplayName(locale) + ")");
+					buf.append("\n");
+				}
+			}
+			MessageDialog.openInformation(
+					Display.getDefault().getActiveShell(), "Duplicate value",
+					buf.toString());
+		}
+	}
 
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditor.java
new file mode 100644
index 0000000..bb15e63
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditor.java
@@ -0,0 +1,562 @@
+/*******************************************************************************
+ * 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
+ *    Alexej Strelzow - TapJI integration, bug fixes & enhancements
+ *    				  - issue 35, 36, 48, 73
+ ******************************************************************************/
+package org.eclipse.babel.editor.internal;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Locale;
+
+import org.eclipse.babel.core.message.IMessagesBundle;
+import org.eclipse.babel.core.message.internal.MessageException;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroupAdapter;
+import org.eclipse.babel.core.message.manager.RBManager;
+import org.eclipse.babel.core.message.resource.IMessagesResource;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
+import org.eclipse.babel.editor.IMessagesEditor;
+import org.eclipse.babel.editor.IMessagesEditorChangeListener;
+import org.eclipse.babel.editor.builder.ToggleNatureAction;
+import org.eclipse.babel.editor.bundle.MessagesBundleGroupFactory;
+import org.eclipse.babel.editor.i18n.I18NPage;
+import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
+import org.eclipse.babel.editor.preferences.MsgEditorPreferences;
+import org.eclipse.babel.editor.resource.EclipsePropertiesEditorResource;
+import org.eclipse.babel.editor.util.UIUtils;
+import org.eclipse.babel.editor.views.MessagesBundleGroupOutline;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.ErrorDialog;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.swt.SWT;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IEditorReference;
+import org.eclipse.ui.IEditorSite;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.editors.text.TextEditor;
+import org.eclipse.ui.ide.IDE;
+import org.eclipse.ui.ide.IGotoMarker;
+import org.eclipse.ui.part.FileEditorInput;
+import org.eclipse.ui.part.MultiPageEditorPart;
+import org.eclipse.ui.texteditor.ITextEditor;
+import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
+
+/**
+ * Multi-page editor for editing resource bundles.
+ */
+public class MessagesEditor extends MultiPageEditorPart implements IGotoMarker,
+        IMessagesEditor {
+
+	/** Editor ID, as defined in plugin.xml. */
+	public static final String EDITOR_ID = "org.eclilpse.babel.editor.editor.MessagesEditor"; //$NON-NLS-1$
+
+	private String selectedKey;
+	private List<IMessagesEditorChangeListener> changeListeners = new ArrayList<IMessagesEditorChangeListener>(
+	        2);
+
+	/** MessagesBundle group. */
+	private MessagesBundleGroup messagesBundleGroup;
+
+	/** Page with key tree and text fields for all locales. */
+	private I18NPage i18nPage;
+	private final List<Locale> localesIndex = new ArrayList<Locale>();
+	private final List<ITextEditor> textEditorsIndex = new ArrayList<ITextEditor>();
+
+	private MessagesBundleGroupOutline outline;
+
+	private MessagesEditorMarkers markers;
+
+	private AbstractKeyTreeModel keyTreeModel;
+
+	private IFile file; // init
+
+	private boolean updateSelectedKey;
+
+	/**
+	 * Creates a multi-page editor example.
+	 */
+	public MessagesEditor() {
+		super();
+		outline = new MessagesBundleGroupOutline(this);
+	}
+
+	public MessagesEditorMarkers getMarkers() {
+		return markers;
+	}
+
+	private IPropertyChangeListener preferenceListener;
+
+	/**
+	 * The <code>MultiPageEditorExample</code> implementation of this method
+	 * checks that the input is an instance of <code>IFileEditorInput</code>.
+	 */
+	@Override
+	public void init(IEditorSite site, IEditorInput editorInput)
+	        throws PartInitException {
+
+		if (editorInput instanceof IFileEditorInput) {
+			file = ((IFileEditorInput) editorInput).getFile();
+			if (MsgEditorPreferences.getInstance()
+			        .isBuilderSetupAutomatically()) {
+				IProject p = file.getProject();
+				if (p != null && p.isAccessible()) {
+					ToggleNatureAction
+					        .addOrRemoveNatureOnProject(p, true, true);
+				}
+			}
+			try {
+				messagesBundleGroup = MessagesBundleGroupFactory
+				        .createBundleGroup(site, file);
+			} catch (MessageException e) {
+				throw new PartInitException("Cannot create bundle group.", e); //$NON-NLS-1$
+			}
+			// register bundle group listener to refresh editor when new a bundle is added
+			messagesBundleGroup.addMessagesBundleGroupListener(new MessagesBundleGroupAdapter() {
+				@Override
+				public void messagesBundleAdded(MessagesBundle messagesBundle) {
+					addMessagesBundle(messagesBundle, messagesBundle.getLocale());
+					// refresh i18n page
+					i18nPage.addI18NEntry(MessagesEditor.this, messagesBundle.getLocale());
+				}
+			});
+			markers = new MessagesEditorMarkers(messagesBundleGroup);
+			setPartName(messagesBundleGroup.getName());
+			setTitleImage(UIUtils.getImage(UIUtils.IMAGE_RESOURCE_BUNDLE));
+			closeIfAreadyOpen(site, file);
+			super.init(site, editorInput);
+			// TODO figure out model to use based on preferences
+			keyTreeModel = new AbstractKeyTreeModel(messagesBundleGroup);
+			// markerManager = new RBEMarkerManager(this);
+		} else {
+			throw new PartInitException(
+			        "Invalid Input: Must be IFileEditorInput"); //$NON-NLS-1$
+		}
+	}
+
+	// public RBEMarkerManager getMarkerManager() {
+	// return markerManager;
+	// }
+
+	/**
+	 * Creates the pages of the multi-page editor.
+	 */
+	@Override
+	protected void createPages() {
+		// Create I18N page
+		i18nPage = new I18NPage(getContainer(), SWT.NONE, this);
+		int index = addPage(i18nPage);
+		setPageText(index, MessagesEditorPlugin.getString("editor.properties")); //$NON-NLS-1$
+		setPageImage(index, UIUtils.getImage(UIUtils.IMAGE_RESOURCE_BUNDLE));
+
+		// Create text editor pages for each locales
+		Locale[] locales = messagesBundleGroup.getLocales();
+		// first: sort the locales.
+		UIUtils.sortLocales(locales);
+		// second: filter+sort them according to the filter preferences.
+		locales = UIUtils.filterLocales(locales);
+		for (int i = 0; i < locales.length; i++) {
+			Locale locale = locales[i];
+			MessagesBundle messagesBundle = (MessagesBundle) messagesBundleGroup
+			        .getMessagesBundle(locale);
+			addMessagesBundle(messagesBundle, locale);
+		}
+	}
+
+	/**
+	 * Creates a new text editor for the messages bundle and locale, which gets added to a new page
+	 */
+	private void addMessagesBundle(MessagesBundle messagesBundle, Locale locale) {
+		try {
+			IMessagesResource resource = messagesBundle.getResource();
+			TextEditor textEditor = (TextEditor) resource.getSource();
+			int index = addPage(textEditor, textEditor.getEditorInput());
+			setPageText(index,
+			        UIUtils.getDisplayName(messagesBundle.getLocale()));
+			setPageImage(index,
+			        UIUtils.getImage(UIUtils.IMAGE_PROPERTIES_FILE));
+			localesIndex.add(locale);
+			textEditorsIndex.add(textEditor);
+		} catch (PartInitException e) {
+			ErrorDialog.openError(getSite().getShell(),
+			        "Error creating text editor page.", //$NON-NLS-1$
+			        null, e.getStatus());
+		} 
+	}
+	
+	/**
+	 * Called when the editor's pages need to be reloaded. For example when the
+	 * filters of locale is changed.
+	 * <p>
+	 * Currently this only reloads the index page. TODO: remove and add the new
+	 * locales? it actually looks quite hard to do.
+	 * </p>
+	 */
+	public void reloadDisplayedContents() {
+		super.removePage(0);
+		int currentlyActivePage = super.getActivePage();
+		i18nPage.dispose();
+		i18nPage = new I18NPage(getContainer(), SWT.NONE, this);
+		super.addPage(0, i18nPage);
+		if (currentlyActivePage == 0) {
+			super.setActivePage(currentlyActivePage);
+		}
+	}
+
+	/**
+	 * Saves the multi-page editor's document.
+	 */
+	@Override
+	public void doSave(IProgressMonitor monitor) {
+		for (ITextEditor textEditor : textEditorsIndex) {
+			textEditor.doSave(monitor);
+		}
+
+		try { // [alst] remove in near future
+			Thread.sleep(200);
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+
+		updateSelectedKey = true;
+
+		RBManager instance = RBManager.getInstance(messagesBundleGroup
+		        .getProjectName());
+
+		refreshKeyTreeModel(); // keeps editor and I18NPage in sync
+
+		instance.fireEditorSaved();
+
+		// // maybe new init?
+	}
+
+	private void refreshKeyTreeModel() {
+		String selectedKey = getSelectedKey(); // memorize
+
+		if (messagesBundleGroup == null) {
+			messagesBundleGroup = MessagesBundleGroupFactory.createBundleGroup(
+			        (IEditorSite) getSite(), file);
+		}
+
+		AbstractKeyTreeModel oldModel = this.keyTreeModel;
+		this.keyTreeModel = new AbstractKeyTreeModel(messagesBundleGroup);
+
+		for (IMessagesEditorChangeListener listener : changeListeners) {
+			listener.keyTreeModelChanged(oldModel, this.keyTreeModel);
+		}
+
+		i18nPage.getTreeViewer().expandAll();
+
+		if (selectedKey != null) {
+			setSelectedKey(selectedKey);
+		}
+	}
+
+	/**
+	 * @see org.eclipse.ui.ISaveablePart#doSaveAs()
+	 */
+	@Override
+	public void doSaveAs() {
+		// Save As not allowed.
+	}
+
+	/**
+	 * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
+	 */
+	@Override
+	public boolean isSaveAsAllowed() {
+		return false;
+	}
+
+	/**
+	 * Change current page based on locale. If there is no editors associated
+	 * with current locale, do nothing.
+	 * 
+	 * @param locale
+	 *            locale used to identify the page to change to
+	 */
+	public void setActivePage(Locale locale) {
+		int index = localesIndex.indexOf(locale);
+		if (index > -1) {
+			setActivePage(index + 1);
+		}
+	}
+
+	/**
+	 * @see org.eclipse.ui.ide.IGotoMarker#gotoMarker(org.eclipse.core.resources.IMarker)
+	 */
+	public void gotoMarker(IMarker marker) {
+		// String key = marker.getAttribute(RBEMarker.KEY, "");
+		// if (key != null && key.length() > 0) {
+		// setActivePage(0);
+		// setSelectedKey(key);
+		// getI18NPage().selectLocale(BabelUtils.parseLocale(
+		// marker.getAttribute(RBEMarker.LOCALE, "")));
+		// } else {
+		IResource resource = marker.getResource();
+		Locale[] locales = messagesBundleGroup.getLocales();
+		for (int i = 0; i < locales.length; i++) {
+			IMessagesResource messagesResource = ((MessagesBundle) messagesBundleGroup
+			        .getMessagesBundle(locales[i])).getResource();
+			if (messagesResource instanceof EclipsePropertiesEditorResource) {
+				EclipsePropertiesEditorResource propFile = (EclipsePropertiesEditorResource) messagesResource;
+				if (resource.equals(propFile.getResource())) {
+					// ok we got the locale.
+					// try to open the master i18n page and select the
+					// corresponding key.
+					try {
+						String key = (String) marker
+						        .getAttribute(IMarker.LOCATION);
+						if (key != null && key.length() > 0) {
+							getI18NPage().selectLocale(locales[i]);
+							setActivePage(0);
+							setSelectedKey(key);
+							return;
+						}
+					} catch (Exception e) {
+						e.printStackTrace();// something better.s
+					}
+					// it did not work... fall back to the text editor.
+					setActivePage(locales[i]);
+					IDE.gotoMarker((IEditorPart) propFile.getSource(), marker);
+					break;
+				}
+			}
+		}
+		// }
+	}
+
+	/**
+	 * Calculates the contents of page GUI page when it is activated.
+	 */
+	@Override
+	protected void pageChange(int newPageIndex) {
+		super.pageChange(newPageIndex);
+		if (newPageIndex != 0) { // if we just want the default page -> == 1
+			setSelection(newPageIndex);
+		} else if (newPageIndex == 0 && updateSelectedKey) {
+			// TODO: find better way
+			for (IMessagesBundle bundle : messagesBundleGroup
+			        .getMessagesBundles()) {
+				RBManager.getInstance(messagesBundleGroup.getProjectName())
+				        .fireResourceChanged(bundle);
+			}
+			updateSelectedKey = false;
+		}
+
+		// if (newPageIndex == 0) {
+		// resourceMediator.reloadProperties();
+		// i18nPage.refreshTextBoxes();
+		// }
+	}
+
+	private void setSelection(int newPageIndex) {
+		ITextEditor editor = textEditorsIndex.get(--newPageIndex);
+		String selectedKey = getSelectedKey();
+		if (selectedKey != null) {
+			if (editor.getEditorInput() instanceof FileEditorInput) {
+				FileEditorInput input = (FileEditorInput) editor
+				        .getEditorInput();
+				try {
+					BufferedReader reader = new BufferedReader(
+					        new InputStreamReader(input.getFile().getContents()));
+					String line = "";
+					int selectionIndex = 0;
+					boolean found = false;
+
+					while ((line = reader.readLine()) != null) {
+						int index = line.indexOf('=');
+						if (index != -1) {
+							if (selectedKey.equals(line.substring(0, index)
+							        .trim())) {
+								found = true;
+								break;
+							}
+						}
+						selectionIndex += line.length() + 2; // + \r\n
+					}
+
+					if (found) {
+						editor.selectAndReveal(selectionIndex, 0);
+					}
+				} catch (CoreException e) {
+					e.printStackTrace();
+				} catch (IOException e) {
+					// TODO Auto-generated catch block
+					e.printStackTrace();
+				}
+			}
+		}
+
+	}
+
+	/**
+	 * Is the given file a member of this resource bundle.
+	 * 
+	 * @param file
+	 *            file to test
+	 * @return <code>true</code> if file is part of bundle
+	 */
+	public boolean isBundleMember(IFile file) {
+		// return resourceMediator.isResource(file);
+		return false;
+	}
+
+	private void closeIfAreadyOpen(IEditorSite site, IFile file) {
+		IWorkbenchPage[] pages = site.getWorkbenchWindow().getPages();
+		for (int i = 0; i < pages.length; i++) {
+			IWorkbenchPage page = pages[i];
+			IEditorReference[] editors = page.getEditorReferences();
+			for (int j = 0; j < editors.length; j++) {
+				IEditorPart editor = editors[j].getEditor(false);
+				if (editor instanceof MessagesEditor) {
+					MessagesEditor rbe = (MessagesEditor) editor;
+					if (rbe.isBundleMember(file)) {
+						page.closeEditor(editor, true);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * @see org.eclipse.ui.IWorkbenchPart#dispose()
+	 */
+	@Override
+	public void dispose() {
+		for (IMessagesEditorChangeListener listener : changeListeners) {
+			listener.editorDisposed();
+		}
+		i18nPage.dispose();
+		for (ITextEditor textEditor : textEditorsIndex) {
+			textEditor.dispose();
+		}
+	}
+
+	/**
+	 * @return Returns the selectedKey.
+	 */
+	public String getSelectedKey() {
+		return selectedKey;
+	}
+
+	/**
+	 * @param selectedKey
+	 *            The selectedKey to set.
+	 */
+	public void setSelectedKey(String activeKey) {
+		if ((selectedKey == null && activeKey != null)
+		        || (selectedKey != null && activeKey == null)
+		        || (selectedKey != null && !selectedKey.equals(activeKey))) {
+			String oldKey = this.selectedKey;
+			this.selectedKey = activeKey;
+			for (IMessagesEditorChangeListener listener : changeListeners) {
+				listener.selectedKeyChanged(oldKey, activeKey);
+			}
+		}
+	}
+
+	public void addChangeListener(IMessagesEditorChangeListener listener) {
+		changeListeners.add(0, listener);
+	}
+
+	public void removeChangeListener(IMessagesEditorChangeListener listener) {
+		changeListeners.remove(listener);
+	}
+
+	public Collection<IMessagesEditorChangeListener> getChangeListeners() {
+		return changeListeners;
+	}
+
+	/**
+	 * @return Returns the messagesBundleGroup.
+	 */
+	public MessagesBundleGroup getBundleGroup() {
+		return messagesBundleGroup;
+	}
+
+	/**
+	 * @return Returns the keyTreeModel.
+	 */
+	public AbstractKeyTreeModel getKeyTreeModel() {
+		return keyTreeModel;
+	}
+
+	/**
+	 * @param keyTreeModel
+	 *            The keyTreeModel to set.
+	 */
+	public void setKeyTreeModel(AbstractKeyTreeModel newKeyTreeModel) {
+		if ((this.keyTreeModel == null && newKeyTreeModel != null)
+		        || (keyTreeModel != null && newKeyTreeModel == null)
+		        || (!keyTreeModel.equals(newKeyTreeModel))) {
+			AbstractKeyTreeModel oldModel = this.keyTreeModel;
+			this.keyTreeModel = newKeyTreeModel;
+			for (IMessagesEditorChangeListener listener : changeListeners) {
+				listener.keyTreeModelChanged(oldModel, newKeyTreeModel);
+			}
+		}
+	}
+
+	public I18NPage getI18NPage() {
+		return i18nPage;
+	}
+
+	/**
+	 * one of the SHOW_* constants defined in the
+	 * {@link IMessagesEditorChangeListener}
+	 */
+	private int showOnlyMissingAndUnusedKeys = IMessagesEditorChangeListener.SHOW_ALL;
+
+	/**
+	 * @return true when only unused and missing keys should be displayed. flase
+	 *         by default.
+	 */
+	public int isShowOnlyUnusedAndMissingKeys() {
+		return showOnlyMissingAndUnusedKeys;
+	}
+
+	public void setShowOnlyUnusedMissingKeys(int showFlag) {
+		showOnlyMissingAndUnusedKeys = showFlag;
+		for (IMessagesEditorChangeListener listener : getChangeListeners()) {
+			listener.showOnlyUnusedAndMissingChanged(showFlag);
+		}
+	}
+
+	@Override
+	public Object getAdapter(Class adapter) {
+		Object obj = super.getAdapter(adapter);
+		if (obj == null) {
+			if (IContentOutlinePage.class.equals(adapter)) {
+				return (outline);
+			}
+		}
+		return (obj);
+	}
+
+	public ITextEditor getTextEditor(Locale locale) {
+		int index = localesIndex.indexOf(locale);
+		return textEditorsIndex.get(index);
+	}
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorChangeAdapter.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorChangeAdapter.java
similarity index 83%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorChangeAdapter.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorChangeAdapter.java
index 93f2583..721d120 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorChangeAdapter.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorChangeAdapter.java
@@ -8,9 +8,10 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.editor;
+package org.eclipse.babel.editor.internal;
 
-import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
+import org.eclipse.babel.editor.IMessagesEditorChangeListener;
 
 /**
  * @author Pascal Essiembre
@@ -46,7 +47,7 @@
     }
 
     /* (non-Javadoc)
-     * @see org.eclilpse.babel.editor.editor.IMessagesEditorChangeListener#keyTreeModelChanged(org.eclipse.babel.core.message.tree.IKeyTreeModel, org.eclipse.babel.core.message.tree.IKeyTreeModel)
+     * @see org.eclilpse.babel.editor.editor.IMessagesEditorChangeListener#keyTreeModelChanged(org.eclipse.babel.core.message.internal.tree.internal.IKeyTreeModel, org.eclipse.babel.core.message.internal.tree.internal.IKeyTreeModel)
      */
     public void keyTreeModelChanged(AbstractKeyTreeModel oldModel, AbstractKeyTreeModel newModel) {
         // do nothing
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorContributor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorContributor.java
similarity index 97%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorContributor.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorContributor.java
index 41aa3f0..48bf6bf 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorContributor.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorContributor.java
@@ -8,8 +8,9 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.editor;
+package org.eclipse.babel.editor.internal;
 
+import org.eclipse.babel.editor.IMessagesEditorChangeListener;
 import org.eclipse.babel.editor.actions.FilterKeysAction;
 import org.eclipse.babel.editor.actions.KeyTreeVisibleAction;
 import org.eclipse.babel.editor.actions.NewLocaleAction;
@@ -173,6 +174,7 @@
 			? (MessagesEditor)part : null;
         toggleKeyTreeAction.setEditor(me);
         ((FilterKeysActionGroup) FILTERS).setActiveEditor(part);
+        newLocaleAction.setEditor(me);
     }
     
     /**
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorMarkers.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorMarkers.java
similarity index 87%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorMarkers.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorMarkers.java
index e677ec8..f69c340 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/MessagesEditorMarkers.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/internal/MessagesEditorMarkers.java
@@ -8,7 +8,7 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.editor;
+package org.eclipse.babel.editor.internal;
 
 import java.beans.PropertyChangeEvent;
 import java.util.Collection;
@@ -18,11 +18,12 @@
 import java.util.Map;
 import java.util.Observable;
 
-import org.eclipse.babel.core.message.MessagesBundle;
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.MessagesBundleGroupAdapter;
 import org.eclipse.babel.core.message.checks.IMessageCheck;
-import org.eclipse.babel.core.message.checks.MissingValueCheck;
+import org.eclipse.babel.core.message.checks.internal.DuplicateValueCheck;
+import org.eclipse.babel.core.message.checks.internal.MissingValueCheck;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroupAdapter;
 import org.eclipse.babel.editor.resource.validator.IValidationMarkerStrategy;
 import org.eclipse.babel.editor.resource.validator.MessagesBundleGroupValidator;
 import org.eclipse.babel.editor.resource.validator.ValidationFailureEvent;
@@ -173,6 +174,15 @@
     
     /**
      * @param key
+     * @return true when the key has a missing issue
+     */
+    public boolean isMissingKey(String key) {
+    	Collection<IMessageCheck> markers = getFailedChecks(key);
+    	return markers != null && markersContainMissing(markers);
+    }
+    
+    /**
+     * @param key
      * @param isMissingOrUnused true when it has been assesed already
      * that it is missing or unused
      * @return true when the key is unused
@@ -190,6 +200,21 @@
     	return markers != null && markersContainMissing(markers);
     }
     
+    /**
+     * 
+     * @param key
+     * @return true when the value is a duplicate value
+     */
+    public boolean isDuplicateValue(String key) {
+    	Collection<IMessageCheck> markers = getFailedChecks(key);
+    	for (IMessageCheck marker : markers) {
+    		if (marker instanceof DuplicateValueCheck) {
+    			return true;
+    		}
+    	}
+    	return false;
+    }
+    
     private boolean markersContainMissing(Collection<IMessageCheck> markers) {
     	for (IMessageCheck marker : markers) {
     		if (marker == MissingValueCheck.MISSING_KEY) {
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/plugin/MessagesEditorPlugin.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/plugin/MessagesEditorPlugin.java
index cd71f75..46e6a6e 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/plugin/MessagesEditorPlugin.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/plugin/MessagesEditorPlugin.java
@@ -20,9 +20,10 @@
 import java.util.PropertyResourceBundle;
 import java.util.ResourceBundle;
 import java.util.Set;
+import java.util.Stack;
 
-import org.eclipse.babel.core.message.AbstractIFileChangeListener;
-import org.eclipse.babel.core.message.AbstractIFileChangeListener.IFileChangeListenerRegistry;
+import org.eclipse.babel.core.message.internal.AbstractIFileChangeListener;
+import org.eclipse.babel.core.message.internal.AbstractIFileChangeListener.IFileChangeListenerRegistry;
 import org.eclipse.babel.editor.builder.ToggleNatureAction;
 import org.eclipse.babel.editor.preferences.MsgEditorPreferences;
 import org.eclipse.core.resources.IResource;
@@ -36,6 +37,12 @@
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.pde.nls.internal.ui.model.ResourceBundleModel;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.plugin.AbstractUIPlugin;
 import org.osgi.framework.BundleContext;
 
@@ -77,6 +84,49 @@
 	public MessagesEditorPlugin() {
 		resourceChangeSubscribers = new HashMap<String,Set<AbstractIFileChangeListener>>();
 	}
+	
+    private static class UndoKeyListener implements Listener {
+    
+    	public void handleEvent(Event event) {
+    		Control focusControl = event.display.getFocusControl();
+    		if (event.stateMask == SWT.CONTROL && focusControl instanceof Text) {
+    			
+    			Text txt = (Text) focusControl;
+    			String actText = txt.getText();
+    			Stack<String> undoStack = (Stack<String>) txt.getData("UNDO");
+				Stack<String> redoStack = (Stack<String>) txt.getData("REDO");
+				
+    			if (event.keyCode == 'z' && undoStack != null && redoStack != null) { // Undo
+    				event.doit = false;
+    				
+    				if (undoStack.size() > 0) {
+    					String peek = undoStack.peek();
+    					if (actText != null && !txt.getText().equals(peek)) {
+    						String pop = undoStack.pop();
+	    					txt.setText(pop);
+	    					txt.setSelection(pop.length());
+	    					redoStack.push(actText);
+    					}
+    				}
+    			} else if (event.keyCode == 'y' && undoStack != null && redoStack != null) { // Redo
+    				
+    				event.doit = false;
+    				
+    				if (redoStack.size() > 0) {
+    					String peek = redoStack.peek();
+    					
+    					if (actText != null && !txt.getText().equals(peek)) {
+    						String pop = redoStack.pop();
+	    					txt.setText(pop);
+	    					txt.setSelection(pop.length());
+	    					undoStack.push(actText);
+    					}
+    				}
+    			}
+    		}
+    	}
+    	
+    }
 
 	/**
 	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(
@@ -121,6 +171,14 @@
         	}
         };
         ResourcesPlugin.getWorkspace().addResourceChangeListener(resourceChangeListener);
+        
+        Display.getDefault().asyncExec(new Runnable() {
+			
+			public void run() {
+				Display.getDefault().addFilter(SWT.KeyUp, new UndoKeyListener());
+				
+			}
+		});
 	}
 
 	/**
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/GeneralPrefPage.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/GeneralPrefPage.java
index 0471b3c..194a671 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/GeneralPrefPage.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/GeneralPrefPage.java
@@ -70,7 +70,7 @@
         new Label(field, SWT.NONE).setText(
                 MessagesEditorPlugin.getString("prefs.groupSep")); //$NON-NLS-1$
         keyGroupSeparator = new Text(field, SWT.BORDER);
-        keyGroupSeparator.setText(prefs.getGroupLevelSeparator());
+        keyGroupSeparator.setText(prefs.getSerializerConfig().getGroupLevelSeparator());
 //                prefs.getString(MsgEditorPreferences.GROUP__LEVEL_SEPARATOR));
         keyGroupSeparator.setTextLimit(2);
         
@@ -91,7 +91,7 @@
         field = createFieldComposite(composite);
         convertEncodedToUnicode = new Button(field, SWT.CHECK);
         convertEncodedToUnicode.setSelection(
-                prefs.isUnicodeEscapeEnabled());
+                prefs.getSerializerConfig().isUnicodeEscapeEnabled());
 //                prefs.getBoolean(MsgEditorPreferences.CONVERT_ENCODED_TO_UNICODE));
         new Label(field, SWT.NONE).setText(
                 MessagesEditorPlugin.getString("prefs.convertEncoded")); //$NON-NLS-1$
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/MsgEditorPreferences.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/MsgEditorPreferences.java
index 9757c7b..43d789e 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/MsgEditorPreferences.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/MsgEditorPreferences.java
@@ -7,6 +7,8 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - externalized IPropertiesSerializerConfig and 
+ *    					IPropertiesDeserializerConfig for better reuse
  ******************************************************************************/
 package org.eclipse.babel.editor.preferences;
 
@@ -15,9 +17,9 @@
 import org.eclipse.babel.core.message.resource.ser.IPropertiesDeserializerConfig;
 import org.eclipse.babel.core.message.resource.ser.IPropertiesSerializerConfig;
 import org.eclipse.babel.editor.IMessagesEditorChangeListener;
-import org.eclipse.babel.editor.MessagesEditor;
 import org.eclipse.babel.editor.builder.Builder;
 import org.eclipse.babel.editor.builder.ToggleNatureAction;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.core.resources.ICommand;
 import org.eclipse.core.resources.IProject;
@@ -27,8 +29,8 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.core.runtime.Preferences;
-import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.Preferences.IPropertyChangeListener;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.jface.dialogs.MessageDialog;
 import org.eclipse.ui.IEditorPart;
 import org.eclipse.ui.IEditorReference;
@@ -41,7 +43,7 @@
  * @author Pascal Essiembre (pascal@essiembre.com)
  */
 public final class MsgEditorPreferences
-        implements IPropertiesSerializerConfig, IPropertiesDeserializerConfig, IPropertyChangeListener {
+        implements /*IPropertiesSerializerConfig, IPropertiesDeserializerConfig,*/ IPropertyChangeListener {
    
 	/** the corresponding validation message with such a preference should
 	 * not be generated */
@@ -202,6 +204,10 @@
     private static final MsgEditorPreferences INSTANCE =
                 new MsgEditorPreferences();
     
+    private final IPropertiesSerializerConfig serializerConfig = new PropertiesSerializerConfig();
+    
+    private final IPropertiesDeserializerConfig deserializerConfig = new PropertiesDeserializerConfig();
+    
     private StringMatcher[] cachedCompiledLocaleFilter;
     
     /**
@@ -215,15 +221,16 @@
         return INSTANCE;
     }
     
-    /**
-     * Gets key group separator.
-     * @return key group separator.
-     */
-    public String getGroupLevelSeparator() {
-        return PREFS.getString(GROUP__LEVEL_SEPARATOR);
-    }
+    
+    public IPropertiesSerializerConfig getSerializerConfig() {
+		return serializerConfig;
+	}
 
-    /**
+	public IPropertiesDeserializerConfig getDeserializerConfig() {
+		return deserializerConfig;
+	}
+
+	/**
      * Gets whether pressing tab inserts a tab in a field.
      * @return <code>true</code> if pressing tab inserts a tab in a field
      */
@@ -232,56 +239,6 @@
     }
     
     /**
-     * Gets whether equals signs should be aligned when generating file.
-     * @return <code>true</code> if equals signs should be aligned
-     */
-    public boolean isAlignEqualsEnabled() {
-        return PREFS.getBoolean(ALIGN_EQUALS_ENABLED);
-    }
-
-    /**
-     * Gets whether there should be spaces around equals signs when generating 
-     * file.
-     * @return <code>true</code> there if should be spaces around equals signs
-     */
-    public boolean isSpacesAroundEqualsEnabled() {
-        return PREFS.getBoolean(SPACES_AROUND_EQUALS_ENABLED);
-    }
-
-    /**
-     * Gets whether keys should be grouped when generating file.
-     * @return <code>true</code> if keys should be grouped
-     */
-    public boolean isGroupKeysEnabled() {
-        return PREFS.getBoolean(GROUP_KEYS_ENABLED);
-    }
-
-    /**
-     * Gets how many level deep keys should be grouped when generating file.
-     * @return how many level deep
-     */
-    public int getGroupLevelDepth() {
-        return PREFS.getInt(GROUP_LEVEL_DEEP);
-    }
-    
-    /**
-     * Gets how many blank lines should separate groups when generating file.
-     * @return how many blank lines between groups
-     */
-    public int getGroupSepBlankLineCount() {
-        return PREFS.getInt(GROUP_SEP_BLANK_LINE_COUNT);
-    }
-
-    /**
-     * Gets whether equal signs should be aligned within each groups when
-     * generating file.
-     * @return <code>true</code> if equal signs should be aligned within groups
-     */
-    public boolean isGroupAlignEqualsEnabled() {
-        return PREFS.getBoolean(GROUP_ALIGN_EQUALS_ENABLED);
-    }
-
-    /**
      * Gets whether key tree should be displayed in hiearchical way by default.
      * @return <code>true</code> if hierarchical
      */
@@ -297,14 +254,6 @@
     }
 
     /**
-     * Gets whether to print "Generated By..." comment when generating file.
-     * @return <code>true</code> if we print it
-     */
-    public boolean isShowSupportEnabled() {
-        return PREFS.getBoolean(SHOW_SUPPORT_ENABLED);
-    }
-
-    /**
      * Gets whether to support Eclipse NL directory structure.
      * @return <code>true</code> if supported
      */
@@ -328,14 +277,6 @@
         return PREFS.getBoolean(SUPPORT_FRAGMENTS);
     }
     
-    /**
-     * Gets whether lines should be wrapped if too big when generating file.
-     * @return <code>true</code> if wrapped
-     */
-    public boolean isWrapLinesEnabled() {
-        return PREFS.getBoolean(WRAP_LINES_ENABLED);
-    }
-    
 //    /**
 //     * True iff the I18N editor page should contiain a comment field for the
 //     * default language
@@ -356,14 +297,6 @@
 //        return PREFS.getBoolean(DISPLAY_LANG_COMMENT_FIELDS);
 //    }
 //    
-    /**
-     * Gets the number of character after which lines should be wrapped when
-     * generating file.
-     * @return number of characters
-     */
-    public int getWrapLineLength() {
-        return PREFS.getInt(WRAP_LINE_LENGTH);
-    }
 
     /**
      * @return the filter to apply on the displayed properties.
@@ -382,49 +315,6 @@
     }
 
     /**
-     * Gets whether wrapped lines should be aligned with equal sign when
-     * generating file.
-     * @return <code>true</code> if aligned
-     */
-    public boolean isWrapAlignEqualsEnabled() {
-        return PREFS.getBoolean(WRAP_ALIGN_EQUALS_ENABLED);
-    }
-
-    /**
-     * Gets the number of spaces to use for indentation of wrapped lines when
-     * generating file.
-     * @return number of spaces
-     */
-    public int getWrapIndentLength() {
-        return PREFS.getInt(WRAP_INDENT_LENGTH);
-    }
-
-    /**
-     * Gets whether to convert encoded strings to unicode characters when
-     * reading file.
-     * @return <code>true</code> if converting
-     */
-    public boolean isUnicodeUnescapeEnabled() {
-        return PREFS.getBoolean(UNICODE_UNESCAPE_ENABLED);
-    }
-
-    /**
-     * Gets whether to escape unicode characters when generating file.
-     * @return <code>true</code> if escaping
-     */
-    public boolean isUnicodeEscapeEnabled() {
-        return PREFS.getBoolean(UNICODE_ESCAPE_ENABLED);
-    }
-    /**
-     * Gets whether escaped unicode "alpha" characters should be uppercase
-     * when generating file. 
-     * @return <code>true</code> if uppercase
-     */
-    public boolean isUnicodeEscapeUppercase() {
-        return PREFS.getBoolean(UNICODE_ESCAPE_UPPERCASE);
-    }
-
-    /**
      * Gets whether we want to overwrite system (or Eclipse) default new line
      * type when generating file.
      * @return <code>true</code> if overwriting
@@ -434,24 +324,6 @@
     }
 
     /**
-     * Gets the new line type to use when overwriting system (or Eclipse)
-     * default new line type when generating file.  Use constants to this
-     * effect.
-     * @return new line type
-     */
-    public int getNewLineStyle() {
-        return PREFS.getInt(NEW_LINE_STYLE);
-    }
-    
-    /**
-     * Gets whether new lines are escaped or printed as is when generating file.
-     * @return <code>true</code> if printed as is.
-     */
-    public boolean isNewLineNice() {
-        return PREFS.getBoolean(NEW_LINE_NICE);
-    }
-
-    /**
      * Gets whether to report keys with missing values.
      * @return <code>true</code> if reporting
      */
@@ -555,14 +427,6 @@
     }
 
     /**
-     * Gets whether to sort keys upon serializing them.
-     * @return <code>true</code> if keys are to be sorted.
-     */
-    public boolean isKeySortingEnabled() {
-        return PREFS.getBoolean(SORT_KEYS);
-    }
-    
-    /**
      * @return a comma separated list of locales-string-matchers.
      * <p>
      * Note: StringMatcher is an internal API duplicated in many different places of eclipse.
@@ -701,5 +565,167 @@
 			}
 		}
 	}
-        
+	
+	//###########################################################################################
+	//###############################PropertiesSerializerConfig##################################
+	//###########################################################################################
+	
+//    /**
+//     * Gets whether to escape unicode characters when generating file.
+//     * @return <code>true</code> if escaping
+//     */
+//    public boolean isUnicodeEscapeEnabled() {
+//        return PREFS.getBoolean(UNICODE_ESCAPE_ENABLED);
+//    }
+//	
+//    /**
+//     * Gets the new line type to use when overwriting system (or Eclipse)
+//     * default new line type when generating file.  Use constants to this
+//     * effect.
+//     * @return new line type
+//     */
+//    public int getNewLineStyle() {
+//        return PREFS.getInt(NEW_LINE_STYLE);
+//    }
+//        
+//    /**
+//     * Gets how many blank lines should separate groups when generating file.
+//     * @return how many blank lines between groups
+//     */
+//    public int getGroupSepBlankLineCount() {
+//        return PREFS.getInt(GROUP_SEP_BLANK_LINE_COUNT);
+//    }
+//    
+//    /**
+//     * Gets whether to print "Generated By..." comment when generating file.
+//     * @return <code>true</code> if we print it
+//     */
+//    public boolean isShowSupportEnabled() {
+//        return PREFS.getBoolean(SHOW_SUPPORT_ENABLED);
+//    }
+//    
+//    /**
+//     * Gets whether keys should be grouped when generating file.
+//     * @return <code>true</code> if keys should be grouped
+//     */
+//    public boolean isGroupKeysEnabled() {
+//        return PREFS.getBoolean(GROUP_KEYS_ENABLED);
+//    }
+//    
+//    /**
+//     * Gets whether escaped unicode "alpha" characters should be uppercase
+//     * when generating file. 
+//     * @return <code>true</code> if uppercase
+//     */
+//    public boolean isUnicodeEscapeUppercase() {
+//        return PREFS.getBoolean(UNICODE_ESCAPE_UPPERCASE);
+//    }
+//    
+//    /**
+//     * Gets the number of character after which lines should be wrapped when
+//     * generating file.
+//     * @return number of characters
+//     */
+//    public int getWrapLineLength() {
+//        return PREFS.getInt(WRAP_LINE_LENGTH);
+//    }
+//    
+//    /**
+//     * Gets whether lines should be wrapped if too big when generating file.
+//     * @return <code>true</code> if wrapped
+//     */
+//    public boolean isWrapLinesEnabled() {
+//        return PREFS.getBoolean(WRAP_LINES_ENABLED);
+//    }
+//    
+//    /**
+//     * Gets whether wrapped lines should be aligned with equal sign when
+//     * generating file.
+//     * @return <code>true</code> if aligned
+//     */
+//    public boolean isWrapAlignEqualsEnabled() {
+//        return PREFS.getBoolean(WRAP_ALIGN_EQUALS_ENABLED);
+//    }
+//    
+//    /**
+//     * Gets the number of spaces to use for indentation of wrapped lines when
+//     * generating file.
+//     * @return number of spaces
+//     */
+//    public int getWrapIndentLength() {
+//        return PREFS.getInt(WRAP_INDENT_LENGTH);
+//    }
+//    
+//    /**
+//     * Gets whether there should be spaces around equals signs when generating 
+//     * file.
+//     * @return <code>true</code> there if should be spaces around equals signs
+//     */
+//    public boolean isSpacesAroundEqualsEnabled() {
+//        return PREFS.getBoolean(SPACES_AROUND_EQUALS_ENABLED);
+//    }
+//    
+//    /**
+//     * Gets whether new lines are escaped or printed as is when generating file.
+//     * @return <code>true</code> if printed as is.
+//     */
+//    public boolean isNewLineNice() {
+//        return PREFS.getBoolean(NEW_LINE_NICE);
+//    }
+//    
+//    /**
+//     * Gets how many level deep keys should be grouped when generating file.
+//     * @return how many level deep
+//     */
+//    public int getGroupLevelDepth() {
+//        return PREFS.getInt(GROUP_LEVEL_DEEP);
+//    }
+// 
+//    /**
+//     * Gets key group separator.
+//     * @return key group separator.
+//     */
+//    public String getGroupLevelSeparator() {
+//        return PREFS.getString(GROUP__LEVEL_SEPARATOR);
+//    }
+//    
+//    /**
+//     * Gets whether equals signs should be aligned when generating file.
+//     * @return <code>true</code> if equals signs should be aligned
+//     */
+//    public boolean isAlignEqualsEnabled() {
+//        return PREFS.getBoolean(ALIGN_EQUALS_ENABLED);
+//    }
+//    
+//    /**
+//     * Gets whether equal signs should be aligned within each groups when
+//     * generating file.
+//     * @return <code>true</code> if equal signs should be aligned within groups
+//     */
+//    public boolean isGroupAlignEqualsEnabled() {
+//        return PREFS.getBoolean(GROUP_ALIGN_EQUALS_ENABLED);
+//    }
+//    
+//    /**
+//     * Gets whether to sort keys upon serializing them.
+//     * @return <code>true</code> if keys are to be sorted.
+//     */
+//    public boolean isKeySortingEnabled() {
+//        return PREFS.getBoolean(SORT_KEYS);
+//    }
+    
+	//###########################################################################################
+	//###############################PropertiesSerializerConfig##################################
+	//###########################################################################################
+    
+    
+//    /**
+//     * Gets whether to convert encoded strings to unicode characters when
+//     * reading file.
+//     * @return <code>true</code> if converting
+//     */
+//    public boolean isUnicodeUnescapeEnabled() {
+//        return PREFS.getBoolean(UNICODE_UNESCAPE_ENABLED);
+//    }
+    
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PreferenceInitializer.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PreferenceInitializer.java
index 78a82c6..e2ad589 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PreferenceInitializer.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PreferenceInitializer.java
@@ -67,7 +67,7 @@
         prefs.setDefault(MsgEditorPreferences.WRAP_INDENT_LENGTH, 8);
 
         prefs.setDefault(MsgEditorPreferences.NEW_LINE_STYLE, 
-                MsgEditorPreferences.NEW_LINE_UNIX);
+                MsgEditorPreferences.getInstance().getSerializerConfig().NEW_LINE_UNIX);
 
         prefs.setDefault(MsgEditorPreferences.KEEP_EMPTY_FIELDS, false);
         prefs.setDefault(MsgEditorPreferences.SORT_KEYS, true);
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PropertiesDeserializerConfig.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PropertiesDeserializerConfig.java
new file mode 100644
index 0000000..56b8fc1
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PropertiesDeserializerConfig.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * 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
+ *    Alexej Strelzow - moved code to here
+ ******************************************************************************/
+package org.eclipse.babel.editor.preferences;
+
+import org.eclipse.babel.core.configuration.ConfigurationManager;
+import org.eclipse.babel.core.message.resource.ser.IPropertiesDeserializerConfig;
+import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
+import org.eclipse.core.runtime.Preferences;
+
+/**
+ * The concrete implementation of {@link IPropertiesDeserializerConfig}.
+ * 
+ * @author Alexej Strelzow
+ */
+public class PropertiesDeserializerConfig implements
+		IPropertiesDeserializerConfig { //  Moved from MsgEditorPreferences, to make it more flexible.
+
+    /** MsgEditorPreferences. */
+    private static final Preferences PREFS = 
+            MessagesEditorPlugin.getDefault().getPluginPreferences();
+
+    PropertiesDeserializerConfig() {
+    	ConfigurationManager.getInstance().setDeserializerConfig(this);
+    }
+    
+    /**
+     * Gets whether to convert encoded strings to unicode characters when
+     * reading file.
+     * @return <code>true</code> if converting
+     */
+    public boolean isUnicodeUnescapeEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.UNICODE_UNESCAPE_ENABLED);
+    }
+
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PropertiesSerializerConfig.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PropertiesSerializerConfig.java
new file mode 100644
index 0000000..fd3b339
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/preferences/PropertiesSerializerConfig.java
@@ -0,0 +1,179 @@
+/*******************************************************************************
+ * 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
+ *    Alexej Strelzow - moved code to here
+ ******************************************************************************/
+package org.eclipse.babel.editor.preferences;
+
+import org.eclipse.babel.core.configuration.ConfigurationManager;
+import org.eclipse.babel.core.message.resource.ser.IPropertiesSerializerConfig;
+import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
+import org.eclipse.core.runtime.Preferences;
+
+/**
+ * The concrete implementation of {@link IPropertiesSerializerConfig}.
+ * 
+ * @author Alexej Strelzow
+ */
+public class PropertiesSerializerConfig implements IPropertiesSerializerConfig {
+	//  Moved from MsgEditorPreferences, to make it more flexible.
+
+    /** MsgEditorPreferences. */
+    private static final Preferences PREFS = 
+            MessagesEditorPlugin.getDefault().getPluginPreferences();
+	
+    PropertiesSerializerConfig() {
+    	ConfigurationManager.getInstance().setSerializerConfig(this);
+    }
+    
+    /**
+     * Gets whether to escape unicode characters when generating file.
+     * @return <code>true</code> if escaping
+     */
+    public boolean isUnicodeEscapeEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.UNICODE_ESCAPE_ENABLED);
+    }
+
+    /**
+     * Gets the new line type to use when overwriting system (or Eclipse)
+     * default new line type when generating file.  Use constants to this
+     * effect.
+     * @return new line type
+     */
+    public int getNewLineStyle() {
+        return PREFS.getInt(MsgEditorPreferences.NEW_LINE_STYLE);
+    }
+
+    /**
+     * Gets how many blank lines should separate groups when generating file.
+     * @return how many blank lines between groups
+     */
+    public int getGroupSepBlankLineCount() {
+        return PREFS.getInt(MsgEditorPreferences.GROUP_SEP_BLANK_LINE_COUNT);
+    }
+
+    /**
+     * Gets whether to print "Generated By..." comment when generating file.
+     * @return <code>true</code> if we print it
+     */
+    public boolean isShowSupportEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.SHOW_SUPPORT_ENABLED);
+    }
+
+    /**
+     * Gets whether keys should be grouped when generating file.
+     * @return <code>true</code> if keys should be grouped
+     */
+    public boolean isGroupKeysEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.GROUP_KEYS_ENABLED);
+    }
+
+    /**
+     * Gets whether escaped unicode "alpha" characters should be uppercase
+     * when generating file. 
+     * @return <code>true</code> if uppercase
+     */
+    public boolean isUnicodeEscapeUppercase() {
+        return PREFS.getBoolean(MsgEditorPreferences.UNICODE_ESCAPE_UPPERCASE);
+    }
+
+    /**
+     * Gets the number of character after which lines should be wrapped when
+     * generating file.
+     * @return number of characters
+     */
+    public int getWrapLineLength() {
+        return PREFS.getInt(MsgEditorPreferences.WRAP_LINE_LENGTH);
+    }
+
+    /**
+     * Gets whether lines should be wrapped if too big when generating file.
+     * @return <code>true</code> if wrapped
+     */
+    public boolean isWrapLinesEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.WRAP_LINES_ENABLED);
+    }
+
+    /**
+     * Gets whether wrapped lines should be aligned with equal sign when
+     * generating file.
+     * @return <code>true</code> if aligned
+     */
+    public boolean isWrapAlignEqualsEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.WRAP_ALIGN_EQUALS_ENABLED);
+    }
+
+    /**
+     * Gets the number of spaces to use for indentation of wrapped lines when
+     * generating file.
+     * @return number of spaces
+     */
+    public int getWrapIndentLength() {
+        return PREFS.getInt(MsgEditorPreferences.WRAP_INDENT_LENGTH);
+    }
+
+    /**
+     * Gets whether there should be spaces around equals signs when generating 
+     * file.
+     * @return <code>true</code> there if should be spaces around equals signs
+     */
+    public boolean isSpacesAroundEqualsEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.SPACES_AROUND_EQUALS_ENABLED);
+    }
+
+    /**
+     * Gets whether new lines are escaped or printed as is when generating file.
+     * @return <code>true</code> if printed as is.
+     */
+    public boolean isNewLineNice() {
+        return PREFS.getBoolean(MsgEditorPreferences.NEW_LINE_NICE);
+    }
+
+    /**
+     * Gets how many level deep keys should be grouped when generating file.
+     * @return how many level deep
+     */
+    public int getGroupLevelDepth() {
+        return PREFS.getInt(MsgEditorPreferences.GROUP_LEVEL_DEEP);
+    }
+
+    /**
+     * Gets key group separator.
+     * @return key group separator.
+     */
+    public String getGroupLevelSeparator() {
+        return PREFS.getString(MsgEditorPreferences.GROUP__LEVEL_SEPARATOR);
+    }
+
+    /**
+     * Gets whether equals signs should be aligned when generating file.
+     * @return <code>true</code> if equals signs should be aligned
+     */
+    public boolean isAlignEqualsEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.ALIGN_EQUALS_ENABLED);
+    }
+
+    /**
+     * Gets whether equal signs should be aligned within each groups when
+     * generating file.
+     * @return <code>true</code> if equal signs should be aligned within groups
+     */
+    public boolean isGroupAlignEqualsEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.GROUP_ALIGN_EQUALS_ENABLED);
+    }
+
+    /**
+     * Gets whether to sort keys upon serializing them.
+     * @return <code>true</code> if keys are to be sorted.
+     */
+    public boolean isKeySortingEnabled() {
+        return PREFS.getBoolean(MsgEditorPreferences.SORT_KEYS);
+    }
+
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyChange.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyChange.java
index 961caae..e017dad 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyChange.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyChange.java
@@ -13,8 +13,8 @@
 import java.text.MessageFormat;
 import java.util.Collection;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.OperationCanceledException;
@@ -120,9 +120,9 @@
 			pm.beginTask("Rename resource bundle key", 1);
 
 			// Find the root - we will need this later
-			KeyTreeNode root = fKeyTreeNode.getParent();
+			KeyTreeNode root = (KeyTreeNode) fKeyTreeNode.getParent();
 			while (root.getName() != null) {
-				root = root.getParent();
+				root = (KeyTreeNode) root.getParent();
 			}
 			
 			if (fRenameChildKeys) {
@@ -146,7 +146,7 @@
 			String segments [] = fNewName.split("\\.");
 			KeyTreeNode renamedKey = root;
 			for (String segment : segments) {
-				renamedKey = renamedKey.getChild(segment);
+				renamedKey = (KeyTreeNode) renamedKey.getChild(segment);
 			}
 			
 			assert(renamedKey != null);
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyDescriptor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyDescriptor.java
index 9251999..dad86fa 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyDescriptor.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyDescriptor.java
@@ -10,8 +10,8 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.refactoring;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
 import org.eclipse.core.runtime.Assert;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.ltk.core.refactoring.Refactoring;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyProcessor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyProcessor.java
index 0b0e3e2..0151d5c 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyProcessor.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyProcessor.java
@@ -12,8 +12,8 @@
 
 import java.text.MessageFormat;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyWizard.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyWizard.java
index 6683545..cefc6fa 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyWizard.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/refactoring/RenameKeyWizard.java
@@ -10,7 +10,7 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.refactoring;
 
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
 import org.eclipse.jface.wizard.IWizardPage;
 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
 import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java
index b413a44..59e57ac 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/EclipsePropertiesEditorResource.java
@@ -7,19 +7,17 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Alexej Strelzow - TapJI integration -> DirtyHack
  ******************************************************************************/
 package org.eclipse.babel.editor.resource;
 
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.resource.AbstractPropertiesResource;
+import org.eclipse.babel.core.configuration.DirtyHack;
+import org.eclipse.babel.core.message.resource.internal.AbstractPropertiesResource;
 import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
 import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
 import org.eclipse.core.resources.IResource;
-import org.eclipse.jface.text.DocumentEvent;
-import org.eclipse.jface.text.IDocument;
-import org.eclipse.jface.text.IDocumentListener;
-import org.eclipse.swt.widgets.Display;
 import org.eclipse.ui.IEditorInput;
 import org.eclipse.ui.IFileEditorInput;
 import org.eclipse.ui.editors.text.TextEditor;
@@ -67,20 +65,20 @@
 //        };
 //        ResourcesPlugin.getWorkspace().addResourceChangeListener(rcl);        
         
-        
-        IDocument document = textEditor.getDocumentProvider().getDocument(
-                textEditor.getEditorInput());
-        System.out.println("DOCUMENT:" + document);
-        document.addDocumentListener(new IDocumentListener() {
-            public void documentAboutToBeChanged(DocumentEvent event) {
-                //do nothing
-                System.out.println("DOCUMENT ABOUT to CHANGE:");
-            }
-            public void documentChanged(DocumentEvent event) {
-                System.out.println("DOCUMENT CHANGED:");
-                fireResourceChange(EclipsePropertiesEditorResource.this);
-            }
-        });
+        // [alst] do we really need this? It causes an endless loop!
+//        IDocument document = textEditor.getDocumentProvider().getDocument(
+//                textEditor.getEditorInput());
+//        System.out.println("DOCUMENT:" + document);
+//        document.addDocumentListener(new IDocumentListener() {
+//            public void documentAboutToBeChanged(DocumentEvent event) {
+//                //do nothing
+//                System.out.println("DOCUMENT ABOUT to CHANGE:");
+//            }
+//            public void documentChanged(DocumentEvent event) {
+//                System.out.println("DOCUMENT CHANGED:");
+////                fireResourceChange(EclipsePropertiesEditorResource.this);
+//            }
+//        });
         
 //        IDocumentProvider docProvider = textEditor.getDocumentProvider();
 ////        PropertiesFileDocumentProvider
@@ -137,12 +135,15 @@
     	 * we are on the UI thread.  This may not be the best place to do
     	 * this???
     	 */
-    	Display.getDefault().asyncExec(new Runnable() {
-			public void run() {
-		        textEditor.getDocumentProvider().getDocument(
-		                textEditor.getEditorInput()).set(content);
-			}
-		});
+    	// [alst] muss 2x speichern wenn async exec
+//    	Display.getDefault().asyncExec(new Runnable() {
+//			public void run() {
+		if (DirtyHack.isEditorModificationEnabled()) {
+			textEditor.getDocumentProvider()
+					.getDocument(textEditor.getEditorInput()).set(content);
+		}
+//			}
+//		});
     }
 
     /**
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/FileMarkerStrategy.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/FileMarkerStrategy.java
index 317c8a7..b03521a 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/FileMarkerStrategy.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/FileMarkerStrategy.java
@@ -10,8 +10,9 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.resource.validator;
 
-import org.eclipse.babel.core.message.checks.DuplicateValueCheck;
-import org.eclipse.babel.core.message.checks.MissingValueCheck;
+import org.eclipse.babel.core.message.checks.internal.DuplicateValueCheck;
+import org.eclipse.babel.core.message.checks.internal.MissingValueCheck;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 import org.eclipse.babel.core.util.BabelUtils;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.babel.editor.preferences.MsgEditorPreferences;
@@ -31,8 +32,8 @@
      */
     public void markFailed(ValidationFailureEvent event) {
         if (event.getCheck() instanceof MissingValueCheck) {
-            addMarker((IResource) event.getBundleGroup().getMessagesBundle(
-                    event.getLocale()).getResource().getSource(),
+            MessagesBundle bundle = (MessagesBundle) event.getBundleGroup().getMessagesBundle(event.getLocale());
+            addMarker((IResource) bundle.getResource().getSource(),
 //            addMarker(event.getResource(),
                     event.getKey(),
                     "Key \"" + event.getKey() //$NON-NLS-1$
@@ -44,8 +45,8 @@
             String duplicates = BabelUtils.join(
                     ((DuplicateValueCheck) event.getCheck())
                             .getDuplicateKeys(), ", ");
-            addMarker((IResource) event.getBundleGroup().getMessagesBundle(
-                    event.getLocale()).getResource().getSource(),
+            MessagesBundle bundle = (MessagesBundle) event.getBundleGroup().getMessagesBundle(event.getLocale());
+            addMarker((IResource) bundle.getResource().getSource(),
 //            addMarker(event.getResource(),
                     event.getKey(),
                     "Key \"" + event.getKey() //$NON-NLS-1$
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/MessagesBundleGroupValidator.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/MessagesBundleGroupValidator.java
index 9590943..00dfe71 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/MessagesBundleGroupValidator.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/MessagesBundleGroupValidator.java
@@ -12,9 +12,9 @@
 
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.checks.DuplicateValueCheck;
-import org.eclipse.babel.core.message.checks.MissingValueCheck;
+import org.eclipse.babel.core.message.checks.internal.DuplicateValueCheck;
+import org.eclipse.babel.core.message.checks.internal.MissingValueCheck;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
 import org.eclipse.babel.editor.preferences.MsgEditorPreferences;
 
 
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/ValidationFailureEvent.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/ValidationFailureEvent.java
index b8b6afe..723b411 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/ValidationFailureEvent.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/resource/validator/ValidationFailureEvent.java
@@ -12,8 +12,8 @@
 
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
 import org.eclipse.babel.core.message.checks.IMessageCheck;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
 
 
 /**
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/IKeyTreeContributor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/IKeyTreeContributor.java
new file mode 100644
index 0000000..0a503b0
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/IKeyTreeContributor.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Alexej Strelzow.
+ * 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:
+ *     Alexej Strelzow - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.tree;
+
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.jface.viewers.TreeViewer;
+
+public interface IKeyTreeContributor {
+
+	void contribute(final TreeViewer treeViewer);
+
+	IKeyTreeNode getKeyTreeNode(String key);
+
+	IKeyTreeNode[] getRootKeyItems();
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/TreeType.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/TreeType.java
deleted file mode 100644
index f6d2d65..0000000
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/TreeType.java
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * 
- */
-package org.eclipse.babel.editor.tree;
-
-public enum TreeType {
-	Tree,
-	Flat
-}
\ No newline at end of file
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AbstractTreeAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AbstractTreeAction.java
index c62cc5f..bbfbda1 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AbstractTreeAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AbstractTreeAction.java
@@ -10,10 +10,10 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.jface.action.Action;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.ITreeContentProvider;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AddKeyAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AddKeyAction.java
index 9dd9fcd..b143210 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AddKeyAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/AddKeyAction.java
@@ -10,9 +10,9 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.jface.dialogs.IInputValidator;
@@ -22,7 +22,7 @@
 
 /**
  * @author Pascal Essiembre
- *
+ * 
  */
 public class AddKeyAction extends AbstractTreeAction {
 
@@ -30,38 +30,37 @@
      * 
      */
     public AddKeyAction(MessagesEditor editor, TreeViewer treeViewer) {
-        super(editor, treeViewer);
-        setText(MessagesEditorPlugin.getString("key.add")); //$NON-NLS-1$
-        setImageDescriptor(UIUtils.getImageDescriptor(UIUtils.IMAGE_ADD));
-        setToolTipText("TODO put something here"); //TODO put tooltip
+	super(editor, treeViewer);
+	setText(MessagesEditorPlugin.getString("key.add") + " ..."); //$NON-NLS-1$
+	setImageDescriptor(UIUtils.getImageDescriptor(UIUtils.IMAGE_ADD));
+	setToolTipText("TODO put something here"); // TODO put tooltip
     }
 
-
     /**
      * @see org.eclipse.jface.action.Action#run()
      */
+    @Override
     public void run() {
-        KeyTreeNode node = getNodeSelection();
-        String key = node.getMessageKey();
-        String msgHead = MessagesEditorPlugin.getString("dialog.add.head");
-        String msgBody = MessagesEditorPlugin.getString("dialog.add.body");
-        InputDialog dialog = new InputDialog(
-                getShell(), msgHead, msgBody, key, new IInputValidator() {
-                    public String isValid(String newText) {
-                        if (getBundleGroup().isMessageKey(newText)) {
-                            return  MessagesEditorPlugin.getString(
-                                    "dialog.error.exists");
-                        }
-                        return null;
-                    }
-                });
-        dialog.open();
-        if (dialog.getReturnCode() == Window.OK ) {
-            String inputKey = dialog.getValue();
-            MessagesBundleGroup messagesBundleGroup = getBundleGroup();
-            messagesBundleGroup.addMessages(inputKey);
-        }
+	KeyTreeNode node = getNodeSelection();
+	String key = node.getMessageKey();
+	String msgHead = MessagesEditorPlugin.getString("dialog.add.head");
+	String msgBody = MessagesEditorPlugin.getString("dialog.add.body");
+	InputDialog dialog = new InputDialog(getShell(), msgHead, msgBody, key,
+		new IInputValidator() {
+		    public String isValid(String newText) {
+			if (getBundleGroup().isMessageKey(newText)) {
+			    return MessagesEditorPlugin
+				    .getString("dialog.error.exists");
+			}
+			return null;
+		    }
+		});
+	dialog.open();
+	if (dialog.getReturnCode() == Window.OK) {
+	    String inputKey = dialog.getValue();
+	    MessagesBundleGroup messagesBundleGroup = getBundleGroup();
+	    messagesBundleGroup.addMessages(inputKey);
+	}
     }
-    
-    
+
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/CollapseAllAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/CollapseAllAction.java
index 8c32d48..b8e18cf 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/CollapseAllAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/CollapseAllAction.java
@@ -10,7 +10,7 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.jface.viewers.TreeViewer;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/DeleteKeyAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/DeleteKeyAction.java
index 83c8ad9..c38c791 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/DeleteKeyAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/DeleteKeyAction.java
@@ -10,9 +10,9 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.swt.SWT;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/ExpandAllAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/ExpandAllAction.java
index e3937f3..ed9018d 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/ExpandAllAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/ExpandAllAction.java
@@ -10,7 +10,7 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.jface.viewers.TreeViewer;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/FlatModelAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/FlatModelAction.java
index 4ec773b..942adb5 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/FlatModelAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/FlatModelAction.java
@@ -10,10 +10,10 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.core.message.tree.TreeType;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
-import org.eclipse.babel.editor.tree.KeyTreeContentProvider;
-import org.eclipse.babel.editor.tree.TreeType;
+import org.eclipse.babel.editor.tree.internal.KeyTreeContentProvider;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.viewers.TreeViewer;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java
index 2da68f2..a55b755 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/RenameKeyAction.java
@@ -10,8 +10,8 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.babel.editor.refactoring.RenameKeyProcessor;
 import org.eclipse.babel.editor.refactoring.RenameKeyWizard;
@@ -22,7 +22,7 @@
 
 /**
  * @author Pascal Essiembre
- *
+ * 
  */
 public class RenameKeyAction extends AbstractTreeAction {
 
@@ -30,28 +30,30 @@
      * 
      */
     public RenameKeyAction(MessagesEditor editor, TreeViewer treeViewer) {
-        super(editor, treeViewer);
-        setText(MessagesEditorPlugin.getString("key.rename")); //$NON-NLS-1$
-        setImageDescriptor(UIUtils.getImageDescriptor(UIUtils.IMAGE_RENAME));
-        setToolTipText("TODO put something here"); //TODO put tooltip
+	super(editor, treeViewer);
+	setText(MessagesEditorPlugin.getString("key.rename") + " ..."); //$NON-NLS-1$
+	setImageDescriptor(UIUtils.getImageDescriptor(UIUtils.IMAGE_RENAME));
+	setToolTipText("TODO put something here"); // TODO put tooltip
     }
 
-
     /**
      * @see org.eclipse.jface.action.Action#run()
      */
+    @Override
     public void run() {
-        KeyTreeNode node = getNodeSelection();
+	KeyTreeNode node = getNodeSelection();
 
-        // Rename single item
-		RenameKeyProcessor refactoring = new RenameKeyProcessor(node, getBundleGroup());
-		
-		RefactoringWizard wizard = new RenameKeyWizard(node, refactoring);
-		try {
-			RefactoringWizardOpenOperation operation= new RefactoringWizardOpenOperation(wizard);
-			operation.run(getShell(), "Introduce Indirection");
-		} catch (InterruptedException exception) {
-			// Do nothing
-		}
+	// Rename single item
+	RenameKeyProcessor refactoring = new RenameKeyProcessor(node,
+		getBundleGroup());
+
+	RefactoringWizard wizard = new RenameKeyWizard(node, refactoring);
+	try {
+	    RefactoringWizardOpenOperation operation = new RefactoringWizardOpenOperation(
+		    wizard);
+	    operation.run(getShell(), "Introduce Indirection");
+	} catch (InterruptedException exception) {
+	    // Do nothing
+	}
     }
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/TreeModelAction.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/TreeModelAction.java
index 94668f1..5bf94cc 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/TreeModelAction.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/actions/TreeModelAction.java
@@ -10,10 +10,10 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.tree.actions;
 
-import org.eclipse.babel.editor.MessagesEditor;
+import org.eclipse.babel.core.message.tree.TreeType;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
-import org.eclipse.babel.editor.tree.KeyTreeContentProvider;
-import org.eclipse.babel.editor.tree.TreeType;
+import org.eclipse.babel.editor.tree.internal.KeyTreeContentProvider;
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.viewers.TreeViewer;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContentProvider.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeContentProvider.java
similarity index 88%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContentProvider.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeContentProvider.java
index 3a4a704..4c03fa4 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContentProvider.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeContentProvider.java
@@ -8,14 +8,16 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.editor.tree;
+package org.eclipse.babel.editor.tree.internal;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
-import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
-import org.eclipse.babel.core.message.tree.visitor.IKeyTreeVisitor;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.IKeyTreeVisitor;
+import org.eclipse.babel.core.message.tree.TreeType;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
 import org.eclipse.jface.viewers.ITreeContentProvider;
 import org.eclipse.jface.viewers.TreeViewer;
 import org.eclipse.jface.viewers.Viewer;
@@ -98,9 +100,9 @@
         case Tree:
             return keyTreeModel.getRootNodes();
         case Flat:
-        	final Collection<KeyTreeNode> actualKeys = new ArrayList<KeyTreeNode>();
+        	final Collection<IKeyTreeNode> actualKeys = new ArrayList<IKeyTreeNode>();
         	IKeyTreeVisitor visitor = new IKeyTreeVisitor() {
-        		public void visitKeyTreeNode(KeyTreeNode node) {
+        		public void visitKeyTreeNode(IKeyTreeNode node) {
         			if (node.isUsedAsKey()) {
         				actualKeys.add(node);
         			}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContributor.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeContributor.java
similarity index 83%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContributor.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeContributor.java
index cffe1be..a9f7e21 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeContributor.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeContributor.java
@@ -8,23 +8,27 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.editor.tree;
+package org.eclipse.babel.editor.tree.internal;
 
 import java.util.Observable;
 import java.util.Observer;
 
-import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
-import org.eclipse.babel.core.message.tree.IKeyTreeModelListener;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.TreeType;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.internal.IKeyTreeModelListener;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
 import org.eclipse.babel.editor.IMessagesEditorChangeListener;
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorChangeAdapter;
-import org.eclipse.babel.editor.MessagesEditorMarkers;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorChangeAdapter;
+import org.eclipse.babel.editor.internal.MessagesEditorMarkers;
+import org.eclipse.babel.editor.tree.IKeyTreeContributor;
 import org.eclipse.babel.editor.tree.actions.AddKeyAction;
 import org.eclipse.babel.editor.tree.actions.DeleteKeyAction;
 import org.eclipse.babel.editor.tree.actions.RenameKeyAction;
 import org.eclipse.jface.action.IAction;
 import org.eclipse.jface.action.MenuManager;
+import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
 import org.eclipse.jface.viewers.IStructuredSelection;
 import org.eclipse.jface.viewers.ITreeContentProvider;
 import org.eclipse.jface.viewers.StructuredSelection;
@@ -46,7 +50,7 @@
  * @author Pascal Essiembre
  *
  */
-public class KeyTreeContributor {
+public class KeyTreeContributor implements IKeyTreeContributor {
 
 	private MessagesEditor editor;
     private AbstractKeyTreeModel treeModel;
@@ -62,8 +66,6 @@
         this.treeType = TreeType.Tree;
     }
 
-
-
     /**
      * 
      */
@@ -71,8 +73,10 @@
         
         KeyTreeContentProvider contentProvider = new KeyTreeContentProvider(treeType);
 		treeViewer.setContentProvider(contentProvider);
+		ColumnViewerToolTipSupport.enableFor (treeViewer);
         treeViewer.setLabelProvider(new KeyTreeLabelProvider(editor, treeModel, contentProvider));
-        treeViewer.setUseHashlookup(true);
+        if (treeViewer.getInput() == null)
+            treeViewer.setUseHashlookup(true);
         
         ViewerFilter onlyUnusedAndMissingKeysFilter = new OnlyUnsuedAndMissingKey();
         ViewerFilter[] filters = {onlyUnusedAndMissingKeysFilter};
@@ -124,7 +128,7 @@
     	 * @return true if this node should be in the filter. Does not navigate the tree
     	 * of KeyTreeNode. false unless the node is a missing or unused key.
     	 */
-    	public boolean isFilteredLeaf(KeyTreeNode node) {
+    	public boolean isFilteredLeaf(IKeyTreeNode node) {
     		MessagesEditorMarkers markers = KeyTreeContributor.this.editor.getMarkers();
     		String key = node.getMessageKey();
     		boolean missingOrUnused = markers.isMissingOrUnusedKey(key);
@@ -288,15 +292,20 @@
             public void selectedKeyChanged(String oldKey, String newKey) {
                 ITreeContentProvider provider =
                         (ITreeContentProvider) treeViewer.getContentProvider();
-                KeyTreeNode node = findKeyTreeNode(
-                        provider, provider.getElements(null), newKey);
-                
-//                String[] test = newKey.split("\\.");
-//                treeViewer.setSelection(new StructuredSelection(test), true);
-                
-                
-                treeViewer.setSelection(new StructuredSelection(node), true);
-                treeViewer.getTree().showSelection();
+                if (provider != null) { // alst workaround
+                    KeyTreeNode node = findKeyTreeNode(
+                            provider, provider.getElements(null), newKey);
+                    
+    //                String[] test = newKey.split("\\.");
+    //                treeViewer.setSelection(new StructuredSelection(test), true);
+                    
+                    
+					if (node != null) {
+						treeViewer.setSelection(new StructuredSelection(node),
+								true);
+						treeViewer.getTree().showSelection();
+					}
+                }
             }
         });
     }
@@ -353,5 +362,37 @@
         }
         return null;
     }
+
+    public IKeyTreeNode getKeyTreeNode(String key) {
+        return getKeyTreeNode(key, null);
+    }
+    
+    // TODO, think about a hashmap
+    private IKeyTreeNode getKeyTreeNode(String key, IKeyTreeNode node) {
+        if (node == null) { 
+            for (IKeyTreeNode ktn : treeModel.getRootNodes()) {
+                String id = ktn.getMessageKey();
+                if (key.equals(id)) {
+                    return ktn;
+                } else {
+                    getKeyTreeNode(key, ktn);
+                }
+            }
+        } else {
+            for (IKeyTreeNode ktn : node.getChildren()) {
+                String id = ktn.getMessageKey();
+                if (key.equals(id)) {
+                    return ktn;
+                } else {
+                    getKeyTreeNode(key, ktn);
+                }
+            }
+        }
+        return null;
+    }
+
+    public IKeyTreeNode[] getRootKeyItems() {
+        return treeModel.getRootNodes();
+    }
     
 }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeLabelProvider.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeLabelProvider.java
similarity index 73%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeLabelProvider.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeLabelProvider.java
index 295b6d7..ef4bfaa 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/KeyTreeLabelProvider.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/tree/internal/KeyTreeLabelProvider.java
@@ -8,23 +8,27 @@
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
  ******************************************************************************/
-package org.eclipse.babel.editor.tree;
+package org.eclipse.babel.editor.tree.internal;
 
 import java.util.Collection;
 
-import org.eclipse.babel.core.message.MessagesBundleGroup;
 import org.eclipse.babel.core.message.checks.IMessageCheck;
-import org.eclipse.babel.core.message.tree.AbstractKeyTreeModel;
-import org.eclipse.babel.core.message.tree.KeyTreeNode;
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.MessagesEditorMarkers;
+import org.eclipse.babel.core.message.internal.MessagesBundleGroup;
+import org.eclipse.babel.core.message.tree.IKeyTreeNode;
+import org.eclipse.babel.core.message.tree.internal.AbstractKeyTreeModel;
+import org.eclipse.babel.core.message.tree.internal.KeyTreeNode;
+import org.eclipse.babel.editor.internal.MessagesEditor;
+import org.eclipse.babel.editor.internal.MessagesEditorMarkers;
 import org.eclipse.babel.editor.util.OverlayImageIcon;
 import org.eclipse.babel.editor.util.UIUtils;
+import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.DecorationOverlayIcon;
 import org.eclipse.jface.viewers.IColorProvider;
+import org.eclipse.jface.viewers.IDecoration;
 import org.eclipse.jface.viewers.IFontProvider;
 import org.eclipse.jface.viewers.ILabelProvider;
-import org.eclipse.jface.viewers.LabelProvider;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.graphics.Image;
@@ -34,7 +38,7 @@
  * @author Pascal Essiembre
  */
 public class KeyTreeLabelProvider 
-        extends LabelProvider implements IFontProvider, IColorProvider {	
+        extends ColumnLabelProvider implements IFontProvider, IColorProvider {	
 
     private static final int KEY_DEFAULT = 1 << 1;
     private static final int KEY_COMMENTED = 1 << 2;
@@ -81,18 +85,28 @@
 			KeyTreeNode node = (KeyTreeNode)element;
 			Collection<IMessageCheck> c = editor.getMarkers().getFailedChecks(node.getMessageKey());
 			if (c == null || c.isEmpty()) {
-				return UIUtils.getImage(UIUtils.IMAGE_KEY);
+				// Return the default key image as no issue exists
+				return UIUtils.getKeyImage();
 			}
-			boolean isMissingOrUnused = editor.getMarkers().isMissingOrUnusedKey(node.getMessageKey());
-			if (isMissingOrUnused) {
-				if (editor.getMarkers().isUnusedKey(node.getMessageKey(), isMissingOrUnused)) {
-					return UIUtils.getImage(UIUtils.IMAGE_UNUSED_TRANSLATION);
-				} else {
-					return UIUtils.getImage(UIUtils.IMAGE_MISSING_TRANSLATION);
+			if (editor.getMarkers().isUnusedKey(node.getMessageKey(), false)) {
+				if (editor.getMarkers().isMissingKey(node.getMessageKey())){
+					return UIUtils.getMissingAndUnusedTranslationsImage();
+				} else if (editor.getMarkers().isDuplicateValue(node.getMessageKey())) {
+					return UIUtils.getDuplicateEntryAndUnusedTranslationsImage();
 				}
-			} else {
-				return UIUtils.getImage(UIUtils.IMAGE_WARNED_TRANSLATION);
+				return UIUtils.getUnusedTranslationsImage();
+			} else if (editor.getMarkers().isMissingKey(node.getMessageKey())){
+				return UIUtils.getMissingTranslationImage();
+			} else if (editor.getMarkers().isDuplicateValue(node.getMessageKey())) {
+				return UIUtils.getDuplicateEntryImage();
 			}
+			
+			// This shouldnt happen, but just in case a default key with a warning icon will be showed
+			Image someWarning = UIUtils.getKeyImage();
+			ImageDescriptor warning = ImageDescriptor.createFromImage(UIUtils.getImage(UIUtils.IMAGE_WARNING));
+			someWarning = new DecorationOverlayIcon(someWarning, warning, IDecoration.BOTTOM_RIGHT).createImage();
+			return someWarning;
+			//return UIUtils.getImage(UIUtils.IMAGE_WARNED_TRANSLATION);
 		} else {
 /*	        // Figure out background icon
 	        if (messagesBundleGroup.isMessageKey(key)) {
@@ -106,9 +120,10 @@
 	        } else {
 	            iconFlags += KEY_VIRTUAL;
 	        }*/
-			return UIUtils.getImage(UIUtils.IMAGE_KEY);
+			
+			return UIUtils.getKeyImage();
+			
 		}
-		
 	}
 
 
@@ -131,6 +146,28 @@
     		return "error";
         }
 	}
+	
+	public String getToolTipText(Object element) {
+		if (element instanceof KeyTreeNode) {
+			KeyTreeNode node = (KeyTreeNode)element;
+			Collection<IMessageCheck> c = editor.getMarkers().getFailedChecks(node.getMessageKey());
+			if (c == null || c.isEmpty()) {
+				return null;
+			}
+			boolean isMissingOrUnused = editor.getMarkers().isMissingOrUnusedKey(node.getMessageKey());
+			if (isMissingOrUnused) {
+				if (editor.getMarkers().isUnusedKey(node.getMessageKey(), isMissingOrUnused)) {
+					return "This Locale is unused";
+				} else {
+					return "This Locale has missing translations";
+				}
+			}
+			if (editor.getMarkers().isDuplicateValue(node.getMessageKey())) {
+				return "This Locale has a duplicate value";
+			}
+		}
+		return null;
+	}
 
     /**
      * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
@@ -214,12 +251,12 @@
         return image;
     }
 
-    private boolean isOneChildrenMarked(KeyTreeNode parentNode) {
+    private boolean isOneChildrenMarked(IKeyTreeNode parentNode) {
         MessagesEditorMarkers markers = editor.getMarkers();
-        KeyTreeNode[] childNodes = 
+        IKeyTreeNode[] childNodes = 
                 editor.getKeyTreeModel().getChildren(parentNode);
         for (int i = 0; i < childNodes.length; i++) {
-            KeyTreeNode node = childNodes[i];
+            IKeyTreeNode node = childNodes[i];
             if (markers.isMarked(node.getMessageKey())) {
                 return true;
             }
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/util/UIUtils.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/util/UIUtils.java
index 07c375b..ae6e38a 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/util/UIUtils.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/util/UIUtils.java
@@ -37,6 +37,8 @@
 import org.eclipse.jface.dialogs.ErrorDialog;
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.ImageRegistry;
+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.Cursor;
@@ -100,13 +102,21 @@
     public static final String IMAGE_EMPTY =
     		"empty.gif";  //$NON-NLS-1$
     public static final String IMAGE_MISSING_TRANSLATION =
-			"missing_translation.png";  //$NON-NLS-1$
+			"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_WARNING =
+			"warning.gif";  //$NON-NLS-1$
+    public static final String IMAGE_ERROR =
+			"error_co.gif";  //$NON-NLS-1$
+    
     
     /** Image registry. */
     private static final ImageRegistry imageRegistry =
@@ -426,6 +436,64 @@
     }
 
     /**
+     * @return Image for the icon that indicates a key with no issues
+     */
+    public static Image getKeyImage() {
+    	Image image = UIUtils.getImage(UIUtils.IMAGE_KEY);
+    	return image;
+    }
+    
+    /**
+     * @return Image for the icon which indicates a key that has missing translations
+     */
+    public static Image getMissingTranslationImage() {
+    	Image image = UIUtils.getImage(UIUtils.IMAGE_KEY);
+    	ImageDescriptor missing = ImageDescriptor.createFromImage(UIUtils.getImage(UIUtils.IMAGE_ERROR));
+		image = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage();
+    	return image;
+    }
+    
+    /**
+     * @return Image for the icon which indicates a key that is unused
+     */
+    public static Image getUnusedTranslationsImage() {
+    	Image image = UIUtils.getImage(UIUtils.IMAGE_UNUSED_TRANSLATION);
+    	ImageDescriptor warning = ImageDescriptor.createFromImage(UIUtils.getImage(UIUtils.IMAGE_WARNING));
+		image = new DecorationOverlayIcon(image, warning, IDecoration.BOTTOM_RIGHT).createImage();
+    	return image;
+    }
+    
+    /**
+     * @return Image for the icon which indicates a key that has missing translations and is unused
+     */
+    public static Image getMissingAndUnusedTranslationsImage() {
+    	Image image = UIUtils.getImage(UIUtils.IMAGE_UNUSED_TRANSLATION);
+    	ImageDescriptor missing = ImageDescriptor.createFromImage(UIUtils.getImage(UIUtils.IMAGE_ERROR));
+		image = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage();
+    	return image;
+    }
+    
+    /**
+     * @return Image for the icon which indicates a key that has duplicate entries
+     */
+    public static Image getDuplicateEntryImage() {
+    	Image image = UIUtils.getImage(UIUtils.IMAGE_KEY);
+    	ImageDescriptor missing = ImageDescriptor.createFromImage(UIUtils.getImage(UIUtils.IMAGE_WARNING));
+		image = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage();
+    	return image;
+    }
+    
+    /**
+     * @return Image for the icon which indicates a key that has duplicate entries and is unused
+     */
+    public static Image getDuplicateEntryAndUnusedTranslationsImage() {
+    	Image image = UIUtils.getImage(UIUtils.IMAGE_UNUSED_TRANSLATION);
+    	ImageDescriptor missing = ImageDescriptor.createFromImage(UIUtils.getImage(UIUtils.IMAGE_DUPLICATE));
+		image = new DecorationOverlayIcon(image, missing, IDecoration.BOTTOM_RIGHT).createImage();
+    	return image;
+    }
+    
+    /**
      * 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>
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/views/MessagesBundleGroupOutline.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/views/MessagesBundleGroupOutline.java
index 1571623..e6f77d5 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/views/MessagesBundleGroupOutline.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/views/MessagesBundleGroupOutline.java
@@ -12,12 +12,12 @@
 
 
 
-import org.eclipse.babel.editor.MessagesEditor;
-import org.eclipse.babel.editor.tree.KeyTreeContributor;
+import org.eclipse.babel.editor.internal.MessagesEditor;
 import org.eclipse.babel.editor.tree.actions.CollapseAllAction;
 import org.eclipse.babel.editor.tree.actions.ExpandAllAction;
 import org.eclipse.babel.editor.tree.actions.FlatModelAction;
 import org.eclipse.babel.editor.tree.actions.TreeModelAction;
+import org.eclipse.babel.editor.tree.internal.KeyTreeContributor;
 import org.eclipse.jface.action.IToolBarManager;
 import org.eclipse.jface.action.Separator;
 import org.eclipse.swt.widgets.Composite;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/widgets/NullableText.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/widgets/NullableText.java
index 65e84e7..46ff23b 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/widgets/NullableText.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/widgets/NullableText.java
@@ -10,6 +10,8 @@
  ******************************************************************************/
 package org.eclipse.babel.editor.widgets;
 
+import java.util.Stack;
+
 import org.eclipse.babel.editor.util.UIUtils;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.events.FocusListener;
@@ -60,6 +62,8 @@
     public NullableText(Composite parent, int style) {
         super(parent, SWT.NONE);
         text = new Text(this, style);
+        text.setData("UNDO", new Stack<String>());
+        text.setData("REDO", new Stack<String>());
         defaultColor = text.getBackground();
         nullColor = UIUtils.getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW);
         
@@ -88,6 +92,8 @@
             this.text.setText(text);
             renderNormal();
         }
+        Stack<String> undoCache = (Stack<String>) this.text.getData("UNDO");
+        undoCache.push(this.text.getText());
     }
     public String getText() {
         if (isnull) {
@@ -177,4 +183,23 @@
         text.setEditable(editable);
     }
     
+//    private class SaveListener implements IMessagesEditorListener {
+//
+//		public void onSave() {
+//			Stack<String> undoCache = (Stack<String>) text.getData("UNDO");
+//			undoCache.clear();
+//		}
+//
+//		public void onModify() {
+//			// TODO Auto-generated method stub
+//			
+//		}
+//
+//		public void onResourceChanged(IMessagesBundle bundle) {
+//			// TODO Auto-generated method stub
+//			
+//		}
+//    	
+//    }
+    
 }
\ No newline at end of file
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/IResourceBundleWizard.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/IResourceBundleWizard.java
new file mode 100644
index 0000000..5a797dc
--- /dev/null
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/IResourceBundleWizard.java
@@ -0,0 +1,19 @@
+/*******************************************************************************
+ * Copyright (c) 2012 Martin Reiterer.
+ * 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:
+ *     Martin Reiterer - initial API and implementation
+ ******************************************************************************/
+package org.eclipse.babel.editor.wizards;
+
+public interface IResourceBundleWizard {
+
+	void setBundleId(String rbName);
+
+	void setDefaultPath(String pathName);
+
+}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/ResourceBundleNewWizardPage.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/internal/ResourceBundleNewWizardPage.java
similarity index 75%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/ResourceBundleNewWizardPage.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/internal/ResourceBundleNewWizardPage.java
index f6d638b..3e2e8be 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/ResourceBundleNewWizardPage.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/internal/ResourceBundleNewWizardPage.java
@@ -7,9 +7,10 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Clemente Lodi-Fè - fixing bugs and setting dialog defaults
  ******************************************************************************/
 
-package org.eclipse.babel.editor.wizards;
+package org.eclipse.babel.editor.wizards.internal;
 
 import java.util.Locale;
 
@@ -17,7 +18,9 @@
 import org.eclipse.babel.editor.widgets.LocaleSelector;
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.Path;
 import org.eclipse.jface.dialogs.IDialogPage;
 import org.eclipse.jface.viewers.ISelection;
@@ -52,26 +55,42 @@
             + MessagesEditorPlugin.getString("editor.default") //$NON-NLS-1$
             + "]"; //$NON-NLS-1$
     
+    /**
+     * contains the path of the folder in which the resource file will be created
+     */
     private Text containerText;
+    /**
+     * Contains the name of the resource file
+     */
     private Text fileText;
     private ISelection selection;
     
     private Button addButton;
     private Button removeButton;
-    
+    /**
+     * Contains all added locales
+     */
     private List bundleLocalesList;
     
     private LocaleSelector localeSelector;
 
+    private String defaultPath = "";
+    private String defaultRBName = "ApplicationResources";
+    
     /**
      * Constructor for SampleNewWizardPage.
      * @param selection workbench selection
      */
-    public ResourceBundleNewWizardPage(ISelection selection) {
+    public ResourceBundleNewWizardPage(ISelection selection, String defaultPath, String defaultRBName) {
         super("wizardPage"); //$NON-NLS-1$
         setTitle(MessagesEditorPlugin.getString("editor.wiz.title")); //$NON-NLS-1$
         setDescription(MessagesEditorPlugin.getString("editor.wiz.desc")); //$NON-NLS-1$
         this.selection = selection;
+        
+        if (! defaultPath.isEmpty())
+        	this.defaultPath = defaultPath;
+        if (! defaultRBName.isEmpty())
+        	this.defaultRBName = defaultRBName;
     }
 
     /**
@@ -150,6 +169,8 @@
                 setAddButtonState();
             }
         });
+        // add a single Locale so that the bundleLocalesList isn't empty on startup
+        bundleLocalesList.add(DEFAULT_LOCALE);
     }
     
     /**
@@ -174,6 +195,7 @@
             public void widgetSelected(SelectionEvent event) {
                 bundleLocalesList.add(getSelectedLocaleAsString());
                 setAddButtonState();
+                dialogChanged(); // for the locale-check
             }
         });
 
@@ -189,6 +211,7 @@
                         bundleLocalesList.getSelectionIndices());
                 removeButton.setEnabled(false);
                 setAddButtonState();
+                dialogChanged(); // for the locale-check
             }
         });
     }
@@ -262,26 +285,45 @@
         label.setText("[locale].properties"); //$NON-NLS-1$
     }
     
-    
     /**
      * Tests if the current workbench selection is a suitable
      * container to use.
      */
     private void initialize() {
-        if (selection!=null && selection.isEmpty()==false && selection instanceof IStructuredSelection) {
+        if (! defaultPath.isEmpty()) {
+        	containerText.setText(defaultPath);
+        	
+        } else if (selection!=null && selection.isEmpty()==false && 
+        		selection instanceof IStructuredSelection) {
             IStructuredSelection ssel = (IStructuredSelection)selection;
-            if (ssel.size()>1) return;
-            Object obj = ssel.getFirstElement();
-            if (obj instanceof IResource) {
-                IContainer container;
-                if (obj instanceof IContainer)
-                    container = (IContainer)obj;
-                else
-                    container = ((IResource)obj).getParent();
-                containerText.setText(container.getFullPath().toString());
+            if (ssel.size()>1) {
+            	return;
             }
+            Object obj = ssel.getFirstElement();
+            if (obj instanceof IAdaptable) {
+	    		IResource resource = (IResource) ((IAdaptable) obj).
+	    				getAdapter(IResource.class);
+	    		// check if selection is a file
+	    		if (resource.getType() == IResource.FILE) {
+	    			resource = resource.getParent();
+	    		}
+	    		// fill filepath container
+	    		containerText.setText(resource.getFullPath().
+	    				toPortableString());
+	    	} else if (obj instanceof IResource) { 
+	    		// this will most likely never happen (legacy code)
+                IContainer container;
+                if (obj instanceof IContainer) {
+                    container = (IContainer)obj;
+                } else {
+                	container = ((IResource)obj).getParent();
+                }
+                containerText.setText(container.getFullPath().
+                		toPortableString());
+            } 
         }
-        fileText.setText("ApplicationResources"); //$NON-NLS-1$
+        
+        fileText.setText(defaultRBName);
     }
     
     /**
@@ -306,7 +348,7 @@
     }
     
     /**
-     * Ensures that both text fields are set.
+     * Ensures that both text fields and the Locale field are set.
      */
     /*default*/ void dialogChanged() {
         String container = getContainerName();
@@ -328,6 +370,35 @@
                     "editor.wiz.error.extension")); //$NON-NLS-1$
             return;
         }
+        // check if at least one Locale has been added to th list
+        if (bundleLocalesList.getItemCount() <= 0) {
+        	updateStatus(MessagesEditorPlugin.getString(
+                    "editor.wiz.error.locale")); //$NON-NLS-1$
+            return;
+        }
+        // check if the container field contains a valid path
+        // meaning: Project exists, at least one segment, valid path
+        Path pathContainer = new Path(container);
+        if (!pathContainer.isValidPath(container)) {
+        	updateStatus(MessagesEditorPlugin.getString(
+                    "editor.wiz.error.invalidpath")); //$NON-NLS-1$
+            return;
+        }
+        
+        if (pathContainer.segmentCount() < 1) {
+        	updateStatus(MessagesEditorPlugin.getString(
+                    "editor.wiz.error.invalidpath")); //$NON-NLS-1$
+        	return;
+        }
+        
+        if (!projectExists(pathContainer.segment(0))) {
+        	String errormessage = MessagesEditorPlugin.getString(
+                    "editor.wiz.error.projectnotexist");
+        	errormessage = String.format(errormessage, pathContainer.segment(0));
+        	updateStatus(errormessage); //$NON-NLS-1$
+        	return;
+        }
+        
         updateStatus(null);
     }
 
@@ -378,4 +449,27 @@
         }
         return DEFAULT_LOCALE;
     }
+    
+    /**
+     * Checks if there is a Project with the given name in the Package Explorer
+     * @param projectName
+     * @return
+     */
+    /*default*/ boolean projectExists(String projectName) {
+    	IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+        Path containerNamePath = new Path("/"+projectName);
+        IResource resource = root.findMember(containerNamePath);
+        if (resource == null) {
+        	return false;
+        }
+        return resource.exists();
+    }
+    
+    public void setDefaultRBName(String name) {
+    	defaultRBName = name;
+    }
+    
+    public void setDefaultPath(String path) {
+    	defaultPath = path;
+    }
 }
\ No newline at end of file
diff --git a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/ResourceBundleWizard.java b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/internal/ResourceBundleWizard.java
similarity index 60%
rename from org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/ResourceBundleWizard.java
rename to org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/internal/ResourceBundleWizard.java
index f458d8b..c04016a 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/ResourceBundleWizard.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/babel/editor/wizards/internal/ResourceBundleWizard.java
@@ -7,8 +7,9 @@
  *
  * Contributors:
  *    Pascal Essiembre - initial API and implementation
+ *    Matthias Lettmayer - added setBundleId() + setDefaultPath() (fixed issue 60)
  ******************************************************************************/
-package org.eclipse.babel.editor.wizards;
+package org.eclipse.babel.editor.wizards.internal;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -17,8 +18,10 @@
 
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.babel.editor.preferences.MsgEditorPreferences;
+import org.eclipse.babel.editor.wizards.IResourceBundleWizard;
 import org.eclipse.core.resources.IContainer;
 import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.IWorkspaceRoot;
 import org.eclipse.core.resources.ResourcesPlugin;
@@ -49,9 +52,12 @@
  * "properties".
  * @author Pascal Essiembre (pascal@essiembre.com)
  */
-public class ResourceBundleWizard extends Wizard implements INewWizard {
+public class ResourceBundleWizard extends Wizard implements INewWizard, IResourceBundleWizard {
     private ResourceBundleNewWizardPage page;
     private ISelection selection;
+    
+    private String defaultRbName = "";
+    private String defaultPath = "";
 
     /**
      * Constructor for ResourceBundleWizard.
@@ -66,10 +72,10 @@
      */
 
     public void addPages() {
-        page = new ResourceBundleNewWizardPage(selection);
+        page = new ResourceBundleNewWizardPage(selection, defaultPath, defaultRbName);
         addPage(page);
     }
-
+    
     /**
      * This method is called when 'Finish' button is pressed in
      * the wizard. We will create an operation and run it
@@ -79,6 +85,16 @@
         final String containerName = page.getContainerName();
         final String baseName = page.getFileName();
         final String[] locales = page.getLocaleStrings();
+        if (!folderExists(containerName)) {
+        	//show choosedialog
+        	String message = MessagesEditorPlugin.getString(
+                    "editor.wiz.createfolder");
+        	message = String.format(message, containerName);
+        	if(!MessageDialog.openConfirm(getShell(), "Create Folder", message)) { //$NON-NLS-1$
+        		return false;
+        	}
+        	
+        }
         IRunnableWithProgress op = new IRunnableWithProgress() {
             public void run(IProgressMonitor monitor) throws InvocationTargetException {
                 try {
@@ -97,6 +113,10 @@
                         }
                         file = createFile(containerName, fileName, monitor);
                     }
+                    if (file == null) { // file creation failed
+                    	MessageDialog.openError(getShell(), "Error", "Error creating file"); //$NON-NLS-1$
+                    	throwCoreException("File \""+containerName+baseName+"\" could not be created"); //$NON-NLS-1$
+                    }
                     final IFile lastFile = file;
                     getShell().getDisplay().asyncExec(new Runnable() {
                         public void run() {
@@ -123,16 +143,29 @@
         } catch (InvocationTargetException e) {
             Throwable realException = e.getTargetException();
             MessageDialog.openError(getShell(), 
-                    "Error", realException.getMessage()); //$NON-NLS-1$
+                    "Error", realException.getLocalizedMessage()); //$NON-NLS-1$
             return false;
         }
         return true;
     }
+    /*
+     * Checks if the input folder existsS
+     */
+    /*default*/ boolean folderExists(String path) {
+    	IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+        IResource resource = root.findMember(new Path(path));
+        if (resource == null) {
+        	return false;
+        } else {
+        	return resource.exists();
+        }
+    }
     
     /*
      * The worker method. It will find the container, create the
      * file if missing or just replace its contents, and open
-     * the editor on the newly created file.
+     * the editor on the newly created file. Will also create
+     * the parent folders of the file if they do not exist.
      */
     /*default*/ IFile createFile(
             String containerName,
@@ -143,12 +176,36 @@
         monitor.beginTask(MessagesEditorPlugin.getString(
                 "editor.wiz.creating") + fileName, 2); //$NON-NLS-1$
         IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
-        IResource resource = root.findMember(new Path(containerName));
-        if (!resource.exists() || !(resource instanceof IContainer)) {
-            throwCoreException("Container \"" + containerName  //$NON-NLS-1$
-                    + "\" does not exist."); //$NON-NLS-1$
+        Path containerNamePath = new Path(containerName);
+        IResource resource = root.findMember(containerNamePath);
+        if (resource == null) {
+        	if (!createFolder(containerNamePath, root, monitor)) {
+        		MessageDialog.openError(getShell(), "Error", 
+        				String.format(MessagesEditorPlugin.getString(
+        						"editor.wiz.error.couldnotcreatefolder"), 
+        						containerName)); //$NON-NLS-1$
+        		return null;
+        	}
+        } else if (!resource.exists() || !(resource instanceof IContainer)) {
+            //throwCoreException("Container \"" + containerName  //$NON-NLS-1$
+            //        + "\" does not exist."); //$NON-NLS-1$
+        	if (!createFolder(containerNamePath, root, monitor)) {
+        		MessageDialog.openError(getShell(), "Error", 
+        				String.format(MessagesEditorPlugin.getString(
+        						"editor.wiz.error.couldnotcreatefolder"), 
+        						containerName)); //$NON-NLS-1$
+        		return null;
+        	}
         }
-        IContainer container = (IContainer) resource;
+        
+        IContainer container = (IContainer) root.findMember(containerNamePath);
+        if (container == null) {
+        	MessageDialog.openError(getShell(), "Error", 
+    				String.format(MessagesEditorPlugin.getString(
+    						"editor.wiz.error.couldnotcreatefolder"), 
+    						containerName)); //$NON-NLS-1$
+    		return null;
+        }
         final IFile file = container.getFile(new Path(fileName));
         try {
             InputStream stream = openContentStream();
@@ -164,17 +221,52 @@
     }
     
     /*
+     * Recursively creates all missing folders
+     */
+    /*default*/ boolean createFolder(Path folderPath, IWorkspaceRoot root, IProgressMonitor monitor) {
+    	IResource baseResource = root.findMember(folderPath);
+    	if (!(baseResource == null)) {
+    		if (baseResource.exists()) {
+    			return true;
+    		}
+    	} else { // if folder does not exist
+    		if (folderPath.segmentCount() <= 1) {
+    			return true;
+    		}
+    		Path oneSegmentLess = (Path)folderPath.removeLastSegments(1); // get parent
+    		if (createFolder(oneSegmentLess, root, monitor)) { // create parent folder
+    			IResource resource = root.findMember(oneSegmentLess);
+    			if (resource  == null) {
+    				return false; // resource is null
+    			} else if (!resource.exists() || !(resource instanceof IContainer)) {
+    				return false; // resource does not exist
+    			}
+    			final IFolder folder = root.getFolder(folderPath);
+    			try {
+					folder.create(true, true, monitor);
+				} catch (CoreException e) {
+					return false;
+				}
+    			return true;
+    		} else {
+    			return false; // could not create parent folder of the input path
+    		}
+    	}
+    	return true;
+    }
+    
+    /*
      * We will initialize file contents with a sample text.
      */
     private InputStream openContentStream() {
         String contents = ""; //$NON-NLS-1$
-        if (MsgEditorPreferences.getInstance().isShowSupportEnabled()) {
+        if (MsgEditorPreferences.getInstance().getSerializerConfig().isShowSupportEnabled()) {
 //            contents = PropertiesGenerator.GENERATED_BY;
         }
         return new ByteArrayInputStream(contents.getBytes());
     }
 
-    private void throwCoreException(String message) throws CoreException {
+    private synchronized void throwCoreException(String message) throws CoreException {
         IStatus status = new Status(IStatus.ERROR, 
                 "org.eclipse.babel.editor",  //$NON-NLS-1$
                 IStatus.OK, message, null);
@@ -190,4 +282,12 @@
             IWorkbench workbench, IStructuredSelection structSelection) {
         this.selection = structSelection;
     }
+
+	public void setBundleId(String rbName) {
+		defaultRbName = rbName;
+	}
+
+	public void setDefaultPath(String pathName) {
+		defaultPath = pathName;
+	}
 }
\ No newline at end of file
diff --git a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/dialogs/EditResourceBundleEntriesDialog.java b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/dialogs/EditResourceBundleEntriesDialog.java
index 8cab4cf..1ad0557 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/dialogs/EditResourceBundleEntriesDialog.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/dialogs/EditResourceBundleEntriesDialog.java
@@ -13,10 +13,10 @@
 import java.util.ArrayList;
 import java.util.Locale;
 
-import org.eclipse.babel.core.message.Message;
-import org.eclipse.babel.core.message.MessagesBundle;
+import org.eclipse.babel.core.message.internal.Message;
+import org.eclipse.babel.core.message.internal.MessagesBundle;
 import org.eclipse.babel.core.message.resource.IMessagesResource;
-import org.eclipse.babel.core.message.resource.PropertiesIFileResource;
+import org.eclipse.babel.core.message.resource.internal.PropertiesIFileResource;
 import org.eclipse.babel.core.message.resource.ser.PropertiesDeserializer;
 import org.eclipse.babel.core.message.resource.ser.PropertiesSerializer;
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
@@ -236,8 +236,8 @@
 
 		                IMessagesResource messagesResource = new PropertiesIFileResource(
 		                        field.locale,
-		                        new PropertiesSerializer(prefs),
-		                        new PropertiesDeserializer(prefs),
+		                        new PropertiesSerializer(prefs.getSerializerConfig()),
+		                        new PropertiesDeserializer(prefs.getDeserializerConfig()),
 		                        (IFile) resource, MessagesEditorPlugin.getDefault());
 		                MessagesBundle bundle = new MessagesBundle(messagesResource);
 
diff --git a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/editor/LocalizationEditor.java b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/editor/LocalizationEditor.java
index e0f5ef6..f2b9223 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/editor/LocalizationEditor.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/editor/LocalizationEditor.java
@@ -1,12 +1,12 @@
 /*******************************************************************************
- * Copyright (c) 2008 Stefan Mücke and others.
+ * Copyright (c) 2008 Stefan M�cke 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:
- *     Stefan Mücke - initial API and implementation
+ *     Stefan M�cke - initial API and implementation
  *******************************************************************************/
 package org.eclipse.pde.nls.internal.ui.editor;
 
@@ -113,10 +113,12 @@
 			this.columnConfig = columnConfig;
 		}
 
+		@Override
 		public String getText(Object element) {
 			ResourceBundleKey key = (ResourceBundleKey) element;
-			if (columnConfig == KEY)
+			if (columnConfig == KEY) {
 				return key.getName();
+			}
 			Locale locale = (Locale) columnConfig;
 			String value;
 			try {
@@ -125,8 +127,9 @@
 				value = null;
 				MessagesEditorPlugin.log(e);
 			}
-			if (value == null)
+			if (value == null) {
 				value = "";
+			}
 			return value;
 		}
 	}
@@ -139,6 +142,7 @@
 		/*
 		 * @see org.eclipse.jface.action.Action#run()
 		 */
+		@Override
 		public void run() {
 			ResourceBundleKey key = getSelectedEntry();
 			if (key == null) {
@@ -146,7 +150,8 @@
 			}
 			Shell shell = Display.getCurrent().getActiveShell();
 			Locale[] locales = getLocales();
-			EditResourceBundleEntriesDialog dialog = new EditResourceBundleEntriesDialog(shell, locales);
+			EditResourceBundleEntriesDialog dialog = new EditResourceBundleEntriesDialog(
+			        shell, locales);
 			dialog.setResourceBundleKey(key);
 			if (dialog.open() == Window.OK) {
 				updateLabels();
@@ -156,24 +161,28 @@
 
 	private class ConfigureColumnsAction extends Action {
 		public ConfigureColumnsAction() {
-			super(null, IAction.AS_PUSH_BUTTON); //$NON-NLS-1$
-			setImageDescriptor(MessagesEditorPlugin.getImageDescriptor("elcl16/conf_columns.gif"));
+			super(null, IAction.AS_PUSH_BUTTON);
+			setImageDescriptor(MessagesEditorPlugin
+			        .getImageDescriptor("elcl16/conf_columns.gif"));
 			setToolTipText("Configure Columns");
 		}
 
 		/*
 		 * @see org.eclipse.jface.action.Action#run()
 		 */
+		@Override
 		public void run() {
 			Shell shell = Display.getCurrent().getActiveShell();
 			String[] values = new String[columnConfigs.length];
 			for (int i = 0; i < columnConfigs.length; i++) {
 				String config = columnConfigs[i].toString();
-				if (config.equals("")) //$NON-NLS-1$
+				if (config.equals("")) {
 					config = "default"; //$NON-NLS-1$
+				}
 				values[i] = config;
 			}
-			ConfigureColumnsDialog dialog = new ConfigureColumnsDialog(shell, values);
+			ConfigureColumnsDialog dialog = new ConfigureColumnsDialog(shell,
+			        values);
 			if (dialog.open() == Window.OK) {
 				String[] result = dialog.getResult();
 				Object[] newConfigs = new Object[result.length];
@@ -193,14 +202,16 @@
 
 	private class EditFilterOptionsAction extends Action {
 		public EditFilterOptionsAction() {
-			super(null, IAction.AS_PUSH_BUTTON); //$NON-NLS-1$
-			setImageDescriptor(MessagesEditorPlugin.getImageDescriptor("elcl16/filter_obj.gif"));
+			super(null, IAction.AS_PUSH_BUTTON);
+			setImageDescriptor(MessagesEditorPlugin
+			        .getImageDescriptor("elcl16/filter_obj.gif"));
 			setToolTipText("Edit Filter Options");
 		}
 
 		/*
 		 * @see org.eclipse.jface.action.Action#run()
 		 */
+		@Override
 		public void run() {
 			Shell shell = Display.getCurrent().getActiveShell();
 			FilterOptionsDialog dialog = new FilterOptionsDialog(shell);
@@ -215,14 +226,16 @@
 
 	private class RefreshAction extends Action {
 		public RefreshAction() {
-			super(null, IAction.AS_PUSH_BUTTON); //$NON-NLS-1$
-			setImageDescriptor(MessagesEditorPlugin.getImageDescriptor("elcl16/refresh.gif"));
+			super(null, IAction.AS_PUSH_BUTTON);
+			setImageDescriptor(MessagesEditorPlugin
+			        .getImageDescriptor("elcl16/refresh.gif"));
 			setToolTipText("Refresh");
 		}
 
 		/*
 		 * @see org.eclipse.jface.action.Action#run()
 		 */
+		@Override
 		public void run() {
 			MessagesEditorPlugin.disposeModel();
 			entryList = new ResourceBundleKeyList(new ResourceBundleKey[0]);
@@ -232,11 +245,14 @@
 		}
 	}
 
-	private class BundleStringComparator implements Comparator<ResourceBundleKey> {
+	private class BundleStringComparator implements
+	        Comparator<ResourceBundleKey> {
 		private final Locale locale;
+
 		public BundleStringComparator(Locale locale) {
 			this.locale = locale;
 		}
+
 		public int compare(ResourceBundleKey o1, ResourceBundleKey o2) {
 			String value1 = null;
 			String value2 = null;
@@ -250,53 +266,59 @@
 			} catch (CoreException e) {
 				MessagesEditorPlugin.log(e);
 			}
-			if (value1 == null)
+			if (value1 == null) {
 				value1 = ""; //$NON-NLS-1$
-			if (value2 == null)
+			}
+			if (value2 == null) {
 				value2 = ""; //$NON-NLS-1$
+			}
 			return value1.compareToIgnoreCase(value2);
 		}
 	}
 
 	private class ExportAction extends Action {
 		public ExportAction() {
-			super(null, IAction.AS_PUSH_BUTTON); //$NON-NLS-1$
-			setImageDescriptor(MessagesEditorPlugin.getImageDescriptor("elcl16/export.gif"));
+			super(null, IAction.AS_PUSH_BUTTON);
+			setImageDescriptor(MessagesEditorPlugin
+			        .getImageDescriptor("elcl16/export.gif"));
 			setToolTipText("Export Current View to CSV or HTML File");
 		}
 
 		/*
 		 * @see org.eclipse.jface.action.Action#run()
 		 */
+		@Override
 		public void run() {
 			Shell shell = Display.getCurrent().getActiveShell();
 			FileDialog dialog = new FileDialog(shell);
 			dialog.setText("Export File");
-			dialog.setFilterExtensions(new String[] {"*.*", "*.htm; *.html", "*.txt; *.csv"});
-			dialog.setFilterNames(new String[] {"All Files (*.*)", "HTML File (*.htm; *.html)",
-					"Tabulator Separated File (*.txt; *.csv)"});
+			dialog.setFilterExtensions(new String[] { "*.*", "*.htm; *.html",
+			        "*.txt; *.csv" });
+			dialog.setFilterNames(new String[] { "All Files (*.*)",
+			        "HTML File (*.htm; *.html)",
+			        "Tabulator Separated File (*.txt; *.csv)" });
 			final String filename = dialog.open();
 			if (filename != null) {
 				BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
 					public void run() {
 						File file = new File(filename);
 						try {
-							BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
-								new FileOutputStream(file),
-								"UTF8")); //$NON-NLS-1$
+							BufferedWriter writer = new BufferedWriter(
+							        new OutputStreamWriter(
+							                new FileOutputStream(file), "UTF8")); //$NON-NLS-1$
 							boolean isHtml = filename.endsWith(".htm") || filename.endsWith(".html"); //$NON-NLS-1$ //$NON-NLS-2$
 							if (isHtml) {
 								writer.write("" //$NON-NLS-1$
-										+ "<html>\r\n" //$NON-NLS-1$
-										+ "<head>\r\n" //$NON-NLS-1$
-										+ "<meta http-equiv=Content-Type content=\"text/html; charset=UTF-8\">\r\n" //$NON-NLS-1$
-										+ "<style>\r\n" //$NON-NLS-1$
-										+ "table {width:100%;}\r\n" //$NON-NLS-1$
-										+ "td.sep {height:10px;background:#C0C0C0;}\r\n" //$NON-NLS-1$
-										+ "</style>\r\n" //$NON-NLS-1$
-										+ "</head>\r\n" //$NON-NLS-1$
-										+ "<body>\r\n" //$NON-NLS-1$
-										+ "<table width=\"100%\" border=\"1\">\r\n"); //$NON-NLS-1$
+								        + "<html>\r\n" //$NON-NLS-1$
+								        + "<head>\r\n" //$NON-NLS-1$
+								        + "<meta http-equiv=Content-Type content=\"text/html; charset=UTF-8\">\r\n" //$NON-NLS-1$
+								        + "<style>\r\n" //$NON-NLS-1$
+								        + "table {width:100%;}\r\n" //$NON-NLS-1$
+								        + "td.sep {height:10px;background:#C0C0C0;}\r\n" //$NON-NLS-1$
+								        + "</style>\r\n" //$NON-NLS-1$
+								        + "</head>\r\n" //$NON-NLS-1$
+								        + "<body>\r\n" //$NON-NLS-1$
+								        + "<table width=\"100%\" border=\"1\">\r\n"); //$NON-NLS-1$
 							}
 
 							int size = entryList.getSize();
@@ -313,8 +335,9 @@
 										writer.write("<tr><td>"); //$NON-NLS-1$
 									}
 									Object config = configs[j];
-									if (!isHtml && j > 0)
+									if (!isHtml && j > 0) {
 										writer.write("\t"); //$NON-NLS-1$
+									}
 									if (config == KEY) {
 										writer.write(key.getName());
 									} else {
@@ -332,7 +355,8 @@
 										} else {
 											valueCount++;
 										}
-										writer.write(EditResourceBundleEntriesDialog.escape(value));
+										writer.write(EditResourceBundleEntriesDialog
+										        .escape(value));
 									}
 									if (isHtml) {
 										writer.write("</td></tr>\r\n"); //$NON-NLS-1$
@@ -350,23 +374,21 @@
 							}
 							writer.close();
 							Shell shell = Display.getCurrent().getActiveShell();
-							MessageDialog.openInformation(
-									shell,
-									"Finished",
-									"File written successfully.\n\nNumber of entries written: "
-											+ entryList.getSize()
-											+ "\nNumber of translations: "
-											+ valueCount
-											+ " ("
-											+ missingCount
-											+ " missing)");
+							MessageDialog.openInformation(shell, "Finished",
+							        "File written successfully.\n\nNumber of entries written: "
+							                + entryList.getSize()
+							                + "\nNumber of translations: "
+							                + valueCount + " (" + missingCount
+							                + " missing)");
 						} catch (IOException e) {
 							Shell shell = Display.getCurrent().getActiveShell();
-							ErrorDialog.openError(shell, "Error", "Error saving file.", new Status(
-								IStatus.ERROR,
-								MessagesEditorPlugin.PLUGIN_ID,
-								e.getMessage(),
-								e));
+							ErrorDialog.openError(
+							        shell,
+							        "Error",
+							        "Error saving file.",
+							        new Status(IStatus.ERROR,
+							                MessagesEditorPlugin.PLUGIN_ID, e
+							                        .getMessage(), e));
 						}
 					}
 				});
@@ -376,7 +398,8 @@
 
 	public static final String ID = "org.eclipse.pde.nls.ui.LocalizationEditor"; //$NON-NLS-1$
 
-	protected static final Object KEY = "key"; // used to indicate the key column
+	protected static final Object KEY = "key"; // used to indicate the key
+											   // column
 
 	private static final String PREF_SECTION_NAME = "org.eclipse.pde.nls.ui.LocalizationEditor"; //$NON-NLS-1$
 	private static final String PREF_SORT_ORDER = "sortOrder"; //$NON-NLS-1$
@@ -400,7 +423,7 @@
 	protected Composite queryComposite;
 	protected Text queryText;
 
-	// Results 
+	// Results
 	private Section resultsSection;
 	private Composite tableComposite;
 	protected TableViewer tableViewer;
@@ -413,7 +436,8 @@
 	protected FilterOptions filterOptions;
 
 	/**
-	 * Column configuration. Values may be either <code>KEY</code> or a {@link Locale}.
+	 * Column configuration. Values may be either <code>KEY</code> or a
+	 * {@link Locale}.
 	 */
 	protected Object[] columnConfigs;
 	/**
@@ -428,6 +452,7 @@
 		public boolean contains(ISchedulingRule rule) {
 			return rule == this;
 		}
+
 		public boolean isConflicting(ISchedulingRule rule) {
 			return rule == this;
 		}
@@ -439,7 +464,8 @@
 	}
 
 	public ResourceBundleKey getSelectedEntry() {
-		IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
+		IStructuredSelection selection = (IStructuredSelection) tableViewer
+		        .getSelection();
 		if (selection.size() == 1) {
 			return (ResourceBundleKey) selection.getFirstElement();
 		}
@@ -459,7 +485,8 @@
 		form.setSeparatorVisible(true);
 		form.setText("Localization");
 
-		form.setImage(formImage = MessagesEditorPlugin.getImageDescriptor("obj16/nls_editor.gif").createImage()); //$NON-NLS-1$
+		form.setImage(formImage = MessagesEditorPlugin.getImageDescriptor(
+		        "obj16/nls_editor.gif").createImage()); //$NON-NLS-1$
 		toolkit.adapt(form);
 		toolkit.paintBordersFor(form);
 		final Composite body = form.getBody();
@@ -492,8 +519,10 @@
 		toolkit.createLabel(queryComposite, "Search:");
 
 		// Query text
-		queryText = toolkit.createText(queryComposite, "", SWT.WRAP | SWT.SINGLE); //$NON-NLS-1$
+		queryText = toolkit.createText(queryComposite,
+		        "", SWT.WRAP | SWT.SINGLE); //$NON-NLS-1$
 		queryText.addKeyListener(new KeyAdapter() {
+			@Override
 			public void keyPressed(KeyEvent e) {
 				if (e.keyCode == SWT.ARROW_DOWN) {
 					table.setFocus();
@@ -523,13 +552,16 @@
 		toolkit.adapt(control);
 
 		// Results section
-		resultsSection = toolkit.createSection(body, ExpandableComposite.TITLE_BAR
-				| ExpandableComposite.LEFT_TEXT_CLIENT_ALIGNMENT);
-		resultsSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+		resultsSection = toolkit.createSection(body,
+		        ExpandableComposite.TITLE_BAR
+		                | ExpandableComposite.LEFT_TEXT_CLIENT_ALIGNMENT);
+		resultsSection.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+		        true, 2, 1));
 		resultsSection.setText("Localization Strings");
 		toolkit.adapt(resultsSection);
 
-		final Composite resultsComposite = toolkit.createComposite(resultsSection, SWT.NONE);
+		final Composite resultsComposite = toolkit.createComposite(
+		        resultsSection, SWT.NONE);
 		toolkit.adapt(resultsComposite);
 		final GridLayout gridLayout2 = new GridLayout();
 		gridLayout2.marginTop = 1;
@@ -539,8 +571,10 @@
 		resultsComposite.setLayout(gridLayout2);
 
 		filteredLabel = new Label(resultsSection, SWT.NONE);
-		filteredLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
-		filteredLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
+		filteredLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER,
+		        false, false));
+		filteredLabel.setForeground(Display.getCurrent().getSystemColor(
+		        SWT.COLOR_RED));
 		filteredLabel.setText(""); //$NON-NLS-1$
 
 		toolkit.paintBordersFor(resultsComposite);
@@ -548,9 +582,11 @@
 		resultsSection.setTextClient(filteredLabel);
 
 		tableComposite = toolkit.createComposite(resultsComposite, SWT.NONE);
-		tableComposite.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TREE_BORDER);
+		tableComposite.setData(FormToolkit.KEY_DRAW_BORDER,
+		        FormToolkit.TREE_BORDER);
 		toolkit.adapt(tableComposite);
-		tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
+		tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
+		        true));
 
 		// Table
 		createTableViewer();
@@ -563,7 +599,7 @@
 		filterOptions.pluginPatterns = new String[0];
 		filterOptions.keysWithMissingEntriesOnly = false;
 		sortOrder = KEY;
-		columnConfigs = new Object[] {KEY, new Locale(""), new Locale("de")}; //$NON-NLS-1$ //$NON-NLS-2$
+		columnConfigs = new Object[] { KEY, new Locale(""), new Locale("de") }; //$NON-NLS-1$ //$NON-NLS-2$
 
 		// Load configuration
 		try {
@@ -578,7 +614,8 @@
 	}
 
 	protected void updateFilterLabel() {
-		if (filterOptions.filterPlugins || filterOptions.keysWithMissingEntriesOnly) {
+		if (filterOptions.filterPlugins
+		        || filterOptions.keysWithMissingEntriesOnly) {
 			filteredLabel.setText("(filtered)");
 		} else {
 			filteredLabel.setText(""); //$NON-NLS-1$
@@ -588,10 +625,12 @@
 
 	private void loadSettings() {
 		// TODO Move this to the preferences?
-		IDialogSettings dialogSettings = MessagesEditorPlugin.getDefault().getDialogSettings();
+		IDialogSettings dialogSettings = MessagesEditorPlugin.getDefault()
+		        .getDialogSettings();
 		IDialogSettings section = dialogSettings.getSection(PREF_SECTION_NAME);
-		if (section == null)
+		if (section == null) {
 			return;
+		}
 
 		// Sort order
 		String sortOrderString = section.get(PREF_SORT_ORDER);
@@ -610,7 +649,8 @@
 		// Columns
 		String columns = section.get(PREF_COLUMNS);
 		if (columns != null) {
-			String[] cols = columns.substring(1, columns.length() - 1).split(","); //$NON-NLS-1$
+			String[] cols = columns.substring(1, columns.length() - 1).split(
+			        ","); //$NON-NLS-1$
 			columnConfigs = new Object[cols.length];
 			for (int i = 0; i < cols.length; i++) {
 				String value = cols[i].trim();
@@ -633,7 +673,8 @@
 		this.filterOptions.filterPlugins = "true".equals(filterOptions); //$NON-NLS-1$
 		String patterns = section.get(PREF_FILTER_OPTIONS_PLUGIN_PATTERNS);
 		if (patterns != null) {
-			String[] split = patterns.substring(1, patterns.length() - 1).split(","); //$NON-NLS-1$
+			String[] split = patterns.substring(1, patterns.length() - 1)
+			        .split(","); //$NON-NLS-1$
 			for (int i = 0; i < split.length; i++) {
 				split[i] = split[i].trim();
 			}
@@ -641,11 +682,12 @@
 		}
 		this.filterOptions.keysWithMissingEntriesOnly = "true".equals(section.get(PREF_FILTER_OPTIONS_MISSING_ONLY)); //$NON-NLS-1$
 
-		// TODO Save column widths 
+		// TODO Save column widths
 	}
 
 	private void saveSettings() {
-		IDialogSettings dialogSettings = MessagesEditorPlugin.getDefault().getDialogSettings();
+		IDialogSettings dialogSettings = MessagesEditorPlugin.getDefault()
+		        .getDialogSettings();
 		IDialogSettings section = dialogSettings.getSection(PREF_SECTION_NAME);
 		if (section == null) {
 			section = dialogSettings.addNewSection(PREF_SECTION_NAME);
@@ -657,13 +699,17 @@
 		section.put(PREF_COLUMNS, Arrays.toString(columnConfigs));
 
 		// Filter options
-		section.put(PREF_FILTER_OPTIONS_FILTER_PLUGINS, filterOptions.filterPlugins);
-		section.put(PREF_FILTER_OPTIONS_PLUGIN_PATTERNS, Arrays.toString(filterOptions.pluginPatterns));
-		section.put(PREF_FILTER_OPTIONS_MISSING_ONLY, filterOptions.keysWithMissingEntriesOnly);
+		section.put(PREF_FILTER_OPTIONS_FILTER_PLUGINS,
+		        filterOptions.filterPlugins);
+		section.put(PREF_FILTER_OPTIONS_PLUGIN_PATTERNS,
+		        Arrays.toString(filterOptions.pluginPatterns));
+		section.put(PREF_FILTER_OPTIONS_MISSING_ONLY,
+		        filterOptions.keysWithMissingEntriesOnly);
 	}
 
 	private void createTableViewer() {
-		table = new Table(tableComposite, SWT.VIRTUAL | SWT.FULL_SELECTION | SWT.MULTI);
+		table = new Table(tableComposite, SWT.VIRTUAL | SWT.FULL_SELECTION
+		        | SWT.MULTI);
 		tableViewer = new TableViewer(table);
 		table.setHeaderVisible(true);
 		toolkit.adapt(table);
@@ -674,9 +720,12 @@
 			public void updateElement(int index) {
 				tableViewer.replace(entryList.getKey(index), index);
 			}
+
 			public void dispose() {
 			}
-			public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+
+			public void inputChanged(Viewer viewer, Object oldInput,
+			        Object newInput) {
 			}
 		});
 		tableViewer.addDoubleClickListener(new IDoubleClickListener() {
@@ -696,7 +745,8 @@
 		});
 		Menu contextMenu = menuManager.createContextMenu(table);
 		table.setMenu(contextMenu);
-		getSite().registerContextMenu(menuManager, getSite().getSelectionProvider());
+		getSite().registerContextMenu(menuManager,
+		        getSite().getSelectionProvider());
 	}
 
 	protected void fillContextMenu(IMenuManager menu) {
@@ -706,8 +756,10 @@
 			menu.add(new Separator());
 		}
 		MenuManager showInSubMenu = new MenuManager("&Show In");
-		IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
-		IContributionItem item = ContributionItemFactory.VIEWS_SHOW_IN.create(window);
+		IWorkbenchWindow window = PlatformUI.getWorkbench()
+		        .getActiveWorkbenchWindow();
+		IContributionItem item = ContributionItemFactory.VIEWS_SHOW_IN
+		        .create(window);
 		showInSubMenu.add(item);
 		menu.add(showInSubMenu);
 	}
@@ -726,7 +778,8 @@
 	}
 
 	@Override
-	public void init(IEditorSite site, IEditorInput input) throws PartInitException {
+	public void init(IEditorSite site, IEditorInput input)
+	        throws PartInitException {
 		setSite(site);
 		setInput(input);
 		this.input = (LocalizationEditorInput) input;
@@ -784,14 +837,15 @@
 					strPattern = "*".concat(strPattern); //$NON-NLS-1$
 				}
 
-				ResourceBundleModel model = MessagesEditorPlugin.getModel(new NullProgressMonitor());
+				ResourceBundleModel model = MessagesEditorPlugin
+				        .getModel(new NullProgressMonitor());
 				Locale[] locales = getLocales();
 
 				// Collect keys
 				ResourceBundleKey[] keys;
 				if (!filterOptions.filterPlugins
-						|| filterOptions.pluginPatterns == null
-						|| filterOptions.pluginPatterns.length == 0) {
+				        || filterOptions.pluginPatterns == null
+				        || filterOptions.pluginPatterns.length == 0) {
 
 					// Ensure the bundles are loaded
 					for (Locale locale : locales) {
@@ -812,7 +866,8 @@
 					String[] patterns = filterOptions.pluginPatterns;
 					StringMatcher[] matchers = new StringMatcher[patterns.length];
 					for (int i = 0; i < matchers.length; i++) {
-						matchers[i] = new StringMatcher(patterns[i], true, false);
+						matchers[i] = new StringMatcher(patterns[i], true,
+						        false);
 					}
 
 					int size = 0;
@@ -833,14 +888,17 @@
 						size += family.getKeyCount();
 					}
 
-					ArrayList<ResourceBundleKey> filteredKeys = new ArrayList<ResourceBundleKey>(size);
+					ArrayList<ResourceBundleKey> filteredKeys = new ArrayList<ResourceBundleKey>(
+					        size);
 					for (ResourceBundleFamily family : families) {
 						// Ensure the bundles are loaded
 						for (Locale locale : locales) {
 							try {
-								ResourceBundle bundle = family.getBundle(locale);
-								if (bundle != null)
+								ResourceBundle bundle = family
+								        .getBundle(locale);
+								if (bundle != null) {
 									bundle.load();
+								}
 							} catch (CoreException e) {
 								MessagesEditorPlugin.log(e);
 							}
@@ -851,25 +909,30 @@
 							filteredKeys.add(key);
 						}
 					}
-					keys = filteredKeys.toArray(new ResourceBundleKey[filteredKeys.size()]);
+					keys = filteredKeys
+					        .toArray(new ResourceBundleKey[filteredKeys.size()]);
 				}
 
 				// Filter keys
 				ArrayList<ResourceBundleKey> filtered = new ArrayList<ResourceBundleKey>();
 
-				StringMatcher keyMatcher = new StringMatcher(keyPattern, true, false);
-				StringMatcher strMatcher = new StringMatcher(strPattern, true, false);
+				StringMatcher keyMatcher = new StringMatcher(keyPattern, true,
+				        false);
+				StringMatcher strMatcher = new StringMatcher(strPattern, true,
+				        false);
 				for (ResourceBundleKey key : keys) {
-					if (monitor.isCanceled())
+					if (monitor.isCanceled()) {
 						return Status.OK_STATUS;
+					}
 
 					// Missing entries
 					if (filterOptions.keysWithMissingEntriesOnly) {
 						boolean hasMissingEntry = false;
 						// Check all columns for missing values
 						for (Object config : columnConfigs) {
-							if (config == KEY)
+							if (config == KEY) {
 								continue;
+							}
 							Locale locale = (Locale) config;
 							String value = null;
 							try {
@@ -882,8 +945,9 @@
 								break;
 							}
 						}
-						if (!hasMissingEntry)
+						if (!hasMissingEntry) {
 							continue;
+						}
 					}
 
 					// Match key
@@ -894,8 +958,9 @@
 
 					// Match entries
 					for (Object config : columnConfigs) {
-						if (config == KEY)
+						if (config == KEY) {
 							continue;
+						}
 						Locale locale = (Locale) config;
 						String value = null;
 						try {
@@ -910,11 +975,14 @@
 					}
 				}
 
-				ResourceBundleKey[] array = filtered.toArray(new ResourceBundleKey[filtered.size()]);
+				ResourceBundleKey[] array = filtered
+				        .toArray(new ResourceBundleKey[filtered.size()]);
 				if (sortOrder == KEY) {
 					Arrays.sort(array, new Comparator<ResourceBundleKey>() {
-						public int compare(ResourceBundleKey o1, ResourceBundleKey o2) {
-							return o1.getName().compareToIgnoreCase(o2.getName());
+						public int compare(ResourceBundleKey o1,
+						        ResourceBundleKey o2) {
+							return o1.getName().compareToIgnoreCase(
+							        o2.getName());
 						}
 					});
 				} else {
@@ -923,8 +991,9 @@
 				}
 				entryList = new ResourceBundleKeyList(array);
 
-				if (monitor.isCanceled())
+				if (monitor.isCanceled()) {
 					return Status.OK_STATUS;
+				}
 
 				final ResourceBundleKeyList entryList2 = entryList;
 				Display.getDefault().syncExec(new Runnable() {
@@ -968,7 +1037,8 @@
 	}
 
 	/**
-	 * @param columnConfigs an array containing <code>KEY</code> and {@link Locale} values 
+	 * @param columnConfigs
+	 *            an array containing <code>KEY</code> and {@link Locale} values
 	 */
 	public void setColumns(Object[] columnConfigs) {
 		this.columnConfigs = columnConfigs;
@@ -992,10 +1062,12 @@
 
 		// Create columns
 		for (Object config : columnConfigs) {
-			if (config == null)
+			if (config == null) {
 				continue;
+			}
 
-			final TableViewerColumn viewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
+			final TableViewerColumn viewerColumn = new TableViewerColumn(
+			        tableViewer, SWT.NONE);
 			TableColumn column = viewerColumn.getColumn();
 			if (config == KEY) {
 				column.setText("Key");
@@ -1005,14 +1077,16 @@
 					column.setText("Default Bundle");
 				} else {
 					String displayName = locale.getDisplayName();
-					if (displayName.equals("")) //$NON-NLS-1$
+					if (displayName.equals("")) {
 						displayName = locale.toString();
+					}
 					column.setText(displayName);
 					localesToUnload.remove(locale);
 				}
 			}
 
-			viewerColumn.setLabelProvider(new LocalizationLabelProvider(config));
+			viewerColumn
+			        .setLabelProvider(new LocalizationLabelProvider(config));
 			tableColumnLayout.setColumnData(column, new ColumnWeightData(33));
 			columns.add(column);
 			column.addSelectionListener(new SelectionAdapter() {
@@ -1040,8 +1114,9 @@
 			sortOrder = KEY; // fall back to default sort order
 		}
 		int index = configs.indexOf(sortOrder);
-		if (index != -1)
+		if (index != -1) {
 			table.setSortColumn(columns.get(index));
+		}
 
 		refresh();
 	}
@@ -1051,18 +1126,22 @@
 	 */
 	@SuppressWarnings("unchecked")
 	@Override
-	public Object getAdapter(Class adapter) {
+	public Object getAdapter(@SuppressWarnings("rawtypes") Class adapter) {
 		if (IShowInSource.class == adapter) {
 			return new IShowInSource() {
 				public ShowInContext getShowInContext() {
 					ResourceBundleKey entry = getSelectedEntry();
-					if (entry == null)
+					if (entry == null) {
 						return null;
-					ResourceBundle bundle = entry.getParent().getBundle(new Locale(""));
-					if (bundle == null)
+					}
+					ResourceBundle bundle = entry.getParent().getBundle(
+					        new Locale(""));
+					if (bundle == null) {
 						return null;
+					}
 					Object resource = bundle.getUnderlyingResource();
-					return new ShowInContext(resource, new StructuredSelection(resource));
+					return new ShowInContext(resource, new StructuredSelection(
+					        resource));
 				}
 			};
 		}
diff --git a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundle.java b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundle.java
index 63f8719..c6b8a43 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundle.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundle.java
@@ -1,12 +1,12 @@
 /*******************************************************************************
- * Copyright (c) 2008 Stefan Mücke and others.
+ * Copyright (c) 2008 Stefan M�cke 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:
- *     Stefan Mücke - initial API and implementation
+ *     Stefan M�cke - initial API and implementation
  *******************************************************************************/
 package org.eclipse.pde.nls.internal.ui.model;
 
@@ -15,9 +15,9 @@
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Locale;
+import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.Set;
-import java.util.Map.Entry;
 
 import org.eclipse.babel.editor.plugin.MessagesEditorPlugin;
 import org.eclipse.core.resources.IFile;
diff --git a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundleModel.java b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundleModel.java
index 500ce6a..e2f8107 100644
--- a/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundleModel.java
+++ b/org.eclipse.babel.editor/src/org/eclipse/pde/nls/internal/ui/model/ResourceBundleModel.java
@@ -1,12 +1,12 @@
 /*******************************************************************************
- * Copyright (c) 2008 Stefan Mücke and others.
+ * Copyright (c) 2008 Stefan M�cke 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:
- *     Stefan Mücke - initial API and implementation
+ *     Stefan M�cke - initial API and implementation
  *******************************************************************************/
 package org.eclipse.pde.nls.internal.ui.model;
 
@@ -32,489 +32,541 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragment;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
-import org.eclipse.pde.core.plugin.IFragmentModel;
-import org.eclipse.pde.core.plugin.IPluginModelBase;
-import org.eclipse.pde.core.plugin.PluginRegistry;
+import org.eclipse.osgi.service.resolver.BundleDescription;
 
 /**
- * A <code>ResourceBundleModel</code> is the host for all {@link ResourceBundleFamily} elements. 
+ * A <code>ResourceBundleModel</code> is the host for all
+ * {@link ResourceBundleFamily} elements.
  */
 public class ResourceBundleModel extends ResourceBundleElement {
 
-	private static final String PROPERTIES_SUFFIX = ".properties"; //$NON-NLS-1$
+    private static final String PROPERTIES_SUFFIX = ".properties"; //$NON-NLS-1$
 
-	private static final String JAVA_NATURE = "org.eclipse.jdt.core.javanature"; //$NON-NLS-1$
+    private static final String JAVA_NATURE = "org.eclipse.jdt.core.javanature"; //$NON-NLS-1$
 
-	private ArrayList<ResourceBundleFamily> bundleFamilies = new ArrayList<ResourceBundleFamily>();
+    private ArrayList<ResourceBundleFamily> bundleFamilies = new ArrayList<ResourceBundleFamily>();
 
-	/**
-	 * The locales for which all bundles have been loaded.
-	 */
-	// TODO Perhaps we should add reference counting to prevent unexpected unloading of bundles 
-	private HashSet<Locale> loadedLocales = new HashSet<Locale>();
+    /**
+     * The locales for which all bundles have been loaded.
+     */
+    // TODO Perhaps we should add reference counting to prevent unexpected
+    // unloading of bundles
+    private HashSet<Locale> loadedLocales = new HashSet<Locale>();
 
-	public ResourceBundleModel(IProgressMonitor monitor) {
-		super(null);
+    public ResourceBundleModel(IProgressMonitor monitor) {
+	super(null);
+	try {
+	    populateFromWorkspace(monitor);
+	} catch (CoreException e) {
+	    MessagesEditorPlugin.log(e);
+	}
+    }
+
+    /**
+     * Returns all resource bundle families contained in this model.
+     * 
+     * @return all resource bundle families contained in this model
+     */
+    public ResourceBundleFamily[] getFamilies() {
+	return bundleFamilies.toArray(new ResourceBundleFamily[bundleFamilies
+		.size()]);
+    }
+
+    public ResourceBundleFamily[] getFamiliesForPluginId(String pluginId) {
+	ArrayList<ResourceBundleFamily> found = new ArrayList<ResourceBundleFamily>();
+	for (ResourceBundleFamily family : bundleFamilies) {
+	    if (family.getPluginId().equals(pluginId)) {
+		found.add(family);
+	    }
+	}
+	return found.toArray(new ResourceBundleFamily[found.size()]);
+    }
+
+    public ResourceBundleFamily[] getFamiliesForProjectName(String projectName) {
+	ArrayList<ResourceBundleFamily> found = new ArrayList<ResourceBundleFamily>();
+	for (ResourceBundleFamily family : bundleFamilies) {
+	    if (family.getProjectName().equals(projectName)) {
+		found.add(family);
+	    }
+	}
+	return found.toArray(new ResourceBundleFamily[found.size()]);
+    }
+
+    public ResourceBundleFamily[] getFamiliesForProject(IProject project) {
+	return getFamiliesForProjectName(project.getName());
+    }
+
+    /**
+     * Returns an array of all currently known bundle keys. This always includes
+     * the keys from the default bundles and may include some additional keys
+     * from bundles that have been loaded sometime and that contain keys not
+     * found in a bundle's default bundle. When a bundle is unloaded, these
+     * additional keys will not be removed from the model.
+     * 
+     * @return the array of bundles keys
+     * @throws CoreException
+     */
+    public ResourceBundleKey[] getAllKeys() throws CoreException {
+	Locale root = new Locale("", "", "");
+
+	// Ensure default bundle is loaded and count keys
+	int size = 0;
+	for (ResourceBundleFamily family : bundleFamilies) {
+	    ResourceBundle bundle = family.getBundle(root);
+	    if (bundle != null)
+		bundle.load();
+	    size += family.getKeyCount();
+	}
+
+	ArrayList<ResourceBundleKey> allKeys = new ArrayList<ResourceBundleKey>(
+		size);
+	for (ResourceBundleFamily family : bundleFamilies) {
+	    ResourceBundleKey[] keys = family.getKeys();
+	    for (ResourceBundleKey key : keys) {
+		allKeys.add(key);
+	    }
+	}
+
+	return allKeys.toArray(new ResourceBundleKey[allKeys.size()]);
+    }
+
+    /**
+     * Loads all the bundles for the given locale into memory.
+     * 
+     * @param locale
+     *            the locale of the bundles to load
+     * @throws CoreException
+     */
+    public void loadBundles(Locale locale) throws CoreException {
+	ResourceBundleFamily[] families = getFamilies();
+	for (ResourceBundleFamily family : families) {
+	    ResourceBundle bundle = family.getBundle(locale);
+	    if (bundle != null)
+		bundle.load();
+	}
+	loadedLocales.add(locale);
+    }
+
+    /**
+     * Unloads all the bundles for the given locale from this model. The default
+     * bundle cannot be unloaded. Such a request will be ignored.
+     * 
+     * @param locale
+     *            the locale of the bundles to unload
+     */
+    public void unloadBundles(Locale locale) {
+	if ("".equals(locale.getLanguage()))
+	    return; // never unload the default bundles
+
+	ResourceBundleFamily[] families = getFamilies();
+	for (ResourceBundleFamily family : families) {
+	    ResourceBundle bundle = family.getBundle(locale);
+	    if (bundle != null)
+		bundle.unload();
+	}
+	loadedLocales.remove(locale);
+    }
+
+    /**
+     * @param monitor
+     * @throws CoreException
+     */
+    private void populateFromWorkspace(IProgressMonitor monitor)
+	    throws CoreException {
+	IWorkspace workspace = ResourcesPlugin.getWorkspace();
+	IWorkspaceRoot root = workspace.getRoot();
+	IProject[] projects = root.getProjects();
+	for (IProject project : projects) {
+	    try {
+		if (!project.isOpen())
+		    continue;
+
+		IJavaProject javaProject = (IJavaProject) project
+			.getNature(JAVA_NATURE);
+		String pluginId = null;
+
 		try {
-			populateFromWorkspace(monitor);
-		} catch (CoreException e) {
-			MessagesEditorPlugin.log(e);
-		}
-	}
+		    Class IFragmentModel = Class
+			    .forName("org.eclipse.pde.core.plugin.IFragmentModel");
+		    Class IPluginModelBase = Class
+			    .forName("org.eclipse.pde.core.plugin.IPluginModelBase");
+		    Class PluginRegistry = Class
+			    .forName("org.eclipse.pde.core.plugin.PluginRegistry");
+		    Class IPluginBase = Class
+			    .forName("org.eclipse.pde.core.plugin.IPluginBase");
+		    Class PluginFragmentModel = Class
+			    .forName("org.eclipse.core.runtime.model.PluginFragmentModel");
 
-	/**
-	 * Returns all resource bundle families contained in this model.
-	 * 
-	 * @return all resource bundle families contained in this model
-	 */
-	public ResourceBundleFamily[] getFamilies() {
-		return bundleFamilies.toArray(new ResourceBundleFamily[bundleFamilies.size()]);
-	}
-
-	public ResourceBundleFamily[] getFamiliesForPluginId(String pluginId) {
-		ArrayList<ResourceBundleFamily> found = new ArrayList<ResourceBundleFamily>();
-		for (ResourceBundleFamily family : bundleFamilies) {
-			if (family.getPluginId().equals(pluginId)) {
-				found.add(family);
+		    // Plugin and fragment projects
+		    Class pluginModel = (Class) PluginRegistry.getMethod(
+			    "findModel", IProject.class).invoke(null, project);
+		    if (pluginModel != null) {
+			// Get plugin id
+			BundleDescription bd = (BundleDescription) IPluginModelBase
+				.getMethod("getBundleDescription").invoke(
+					pluginModel);
+			pluginId = bd.getName();
+			// OSGi bundle name
+			if (pluginId == null) {
+			    Object pluginBase = IPluginModelBase.getMethod(
+				    "getPluginBase").invoke(pluginModel);
+			    pluginId = (String) IPluginBase.getMethod("getId")
+				    .invoke(pluginBase); // non-OSGi
+			    // plug-in id
 			}
-		}
-		return found.toArray(new ResourceBundleFamily[found.size()]);
-	}
 
-	public ResourceBundleFamily[] getFamiliesForProjectName(String projectName) {
-		ArrayList<ResourceBundleFamily> found = new ArrayList<ResourceBundleFamily>();
-		for (ResourceBundleFamily family : bundleFamilies) {
-			if (family.getProjectName().equals(projectName)) {
-				found.add(family);
+			boolean isFragment = IFragmentModel
+				.isInstance(pluginModel);
+			if (isFragment) {
+			    Object pfm = IFragmentModel
+				    .getMethod("getFragment");
+			    pluginId = (String) PluginFragmentModel.getMethod(
+				    "getPluginId").invoke(pfm);
 			}
-		}
-		return found.toArray(new ResourceBundleFamily[found.size()]);
-	}
 
-	public ResourceBundleFamily[] getFamiliesForProject(IProject project) {
-		return getFamiliesForProjectName(project.getName());
-	}
+			// Look for additional 'nl' resources
+			IFolder nl = project.getFolder("nl"); //$NON-NLS-1$
+			if (isFragment && nl.exists()) {
+			    IResource[] members = nl.members();
+			    for (IResource member : members) {
+				if (member instanceof IFolder) {
+				    IFolder langFolder = (IFolder) member;
+				    String language = langFolder.getName();
 
-	/**
-	 * Returns an array of all currently known bundle keys. This always includes
-	 * the keys from the default bundles and may include some additional keys
-	 * from bundles that have been loaded sometime and that contain keys not found in
-	 * a bundle's default bundle. When a bundle is unloaded, these additional keys
-	 * will not be removed from the model.
-	 * 
-	 * @return the array of bundles keys
-	 * @throws CoreException 
-	 */
-	public ResourceBundleKey[] getAllKeys() throws CoreException {
-		Locale root = new Locale("", "", "");
-		
-		// Ensure default bundle is loaded and count keys  
-		int size = 0;
-		for (ResourceBundleFamily family : bundleFamilies) {
-			ResourceBundle bundle = family.getBundle(root);
-			if (bundle != null)
-				bundle.load();
-			size += family.getKeyCount();
-		}
+				    // Collect property files
+				    IFile[] propertyFiles = collectPropertyFiles(langFolder);
+				    for (IFile file : propertyFiles) {
+					// Compute path name
+					IPath path = file
+						.getProjectRelativePath();
+					String country = ""; //$NON-NLS-1$
+					String packageName = null;
+					int segmentCount = path.segmentCount();
+					if (segmentCount > 1) {
+					    StringBuilder builder = new StringBuilder();
 
-		ArrayList<ResourceBundleKey> allKeys = new ArrayList<ResourceBundleKey>(size);
-		for (ResourceBundleFamily family : bundleFamilies) {
-			ResourceBundleKey[] keys = family.getKeys();
-			for (ResourceBundleKey key : keys) {
-				allKeys.add(key);
+					    // Segment 0: 'nl'
+					    // Segment 1: language code
+					    // Segment 2: (country code)
+					    int begin = 2;
+					    if (segmentCount > 2
+						    && isCountry(path
+							    .segment(2))) {
+						begin = 3;
+						country = path.segment(2);
+					    }
+
+					    for (int i = begin; i < segmentCount - 1; i++) {
+						if (i > begin)
+						    builder.append('.');
+						builder.append(path.segment(i));
+					    }
+					    packageName = builder.toString();
+					}
+
+					String baseName = getBaseName(file
+						.getName());
+
+					ResourceBundleFamily family = getOrCreateFamily(
+						project.getName(), pluginId,
+						packageName, baseName);
+					addBundle(family,
+						getLocale(language, country),
+						file);
+				    }
+				}
+			    }
 			}
-		}
 
-		return allKeys.toArray(new ResourceBundleKey[allKeys.size()]);
-	}
+			// Collect property files
+			if (isFragment || javaProject == null) {
+			    IFile[] propertyFiles = collectPropertyFiles(project);
+			    for (IFile file : propertyFiles) {
+				IPath path = file.getProjectRelativePath();
+				int segmentCount = path.segmentCount();
 
-	/**
-	 * Loads all the bundles for the given locale into memory.
-	 * 
-	 * @param locale the locale of the bundles to load
-	 * @throws CoreException 
-	 */
-	public void loadBundles(Locale locale) throws CoreException {
-		ResourceBundleFamily[] families = getFamilies();
-		for (ResourceBundleFamily family : families) {
-			ResourceBundle bundle = family.getBundle(locale);
-			if (bundle != null)
-				bundle.load();
-		}
-		loadedLocales.add(locale);
-	}
+				if (segmentCount > 0
+					&& path.segment(0).equals("nl")) //$NON-NLS-1$
+				    continue; // 'nl' resource have been
+					      // processed
+				// above
 
-	/**
-	 * Unloads all the bundles for the given locale from this model. The default
-	 * bundle cannot be unloaded. Such a request will be ignored.
-	 * 
-	 * @param locale the locale of the bundles to unload
-	 */
-	public void unloadBundles(Locale locale) {
-		if ("".equals(locale.getLanguage()))
-			return; // never unload the default bundles
-
-		ResourceBundleFamily[] families = getFamilies();
-		for (ResourceBundleFamily family : families) {
-			ResourceBundle bundle = family.getBundle(locale);
-			if (bundle != null)
-				bundle.unload();
-		}
-		loadedLocales.remove(locale);
-	}
-
-	private void populateFromWorkspace(IProgressMonitor monitor) throws CoreException {
-		IWorkspace workspace = ResourcesPlugin.getWorkspace();
-		IWorkspaceRoot root = workspace.getRoot();
-		IProject[] projects = root.getProjects();
-		for (IProject project : projects) {
-			try {
-				if (!project.isOpen())
-					continue;
-
-				IJavaProject javaProject = (IJavaProject) project.getNature(JAVA_NATURE);
-
-				// Plugin and fragment projects
-				IPluginModelBase pluginModel = PluginRegistry.findModel(project);
-				String pluginId = null;
-				if (pluginModel != null) {
-					// Get plugin id
-					pluginId = pluginModel.getBundleDescription().getName(); // OSGi bundle name
-					if (pluginId == null) {
-						pluginId = pluginModel.getPluginBase().getId(); // non-OSGi plug-in id
-					}
-					boolean isFragment = pluginModel instanceof IFragmentModel;
-					if (isFragment) {
-						IFragmentModel fragmentModel = (IFragmentModel) pluginModel;
-						pluginId = fragmentModel.getFragment().getPluginId();
-					}
-
-					// Look for additional 'nl' resources
-					IFolder nl = project.getFolder("nl"); //$NON-NLS-1$
-					if (isFragment && nl.exists()) {
-						IResource[] members = nl.members();
-						for (IResource member : members) {
-							if (member instanceof IFolder) {
-								IFolder langFolder = (IFolder) member;
-								String language = langFolder.getName();
-
-								// Collect property files
-								IFile[] propertyFiles = collectPropertyFiles(langFolder);
-								for (IFile file : propertyFiles) {
-									// Compute path name
-									IPath path = file.getProjectRelativePath();
-									String country = ""; //$NON-NLS-1$
-									String packageName = null;
-									int segmentCount = path.segmentCount();
-									if (segmentCount > 1) {
-										StringBuilder builder = new StringBuilder();
-
-										// Segment 0: 'nl'
-										// Segment 1: language code
-										// Segment 2: (country code)
-										int begin = 2;
-										if (segmentCount > 2 && isCountry(path.segment(2))) {
-											begin = 3;
-											country = path.segment(2);
-										}
-
-										for (int i = begin; i < segmentCount - 1; i++) {
-											if (i > begin)
-												builder.append('.');
-											builder.append(path.segment(i));
-										}
-										packageName = builder.toString();
-									}
-
-									String baseName = getBaseName(file.getName());
-
-									ResourceBundleFamily family = getOrCreateFamily(
-											project.getName(),
-											pluginId,
-											packageName,
-											baseName);
-									addBundle(family, getLocale(language, country), file);
-								}
-							}
-						}
-					}
-
-					// Collect property files
-					if (isFragment || javaProject == null) {
-						IFile[] propertyFiles = collectPropertyFiles(project);
-						for (IFile file : propertyFiles) {
-							IPath path = file.getProjectRelativePath();
-							int segmentCount = path.segmentCount();
-
-							if (segmentCount > 0 && path.segment(0).equals("nl")) //$NON-NLS-1$
-								continue; // 'nl' resource have been processed above
-
-							// Guess package name
-							String packageName = null;
-							if (segmentCount > 1) {
-								StringBuilder builder = new StringBuilder();
-								for (int i = 0; i < segmentCount - 1; i++) {
-									if (i > 0)
-										builder.append('.');
-									builder.append(path.segment(i));
-								}
-								packageName = builder.toString();
-							}
-
-							String baseName = getBaseName(file.getName());
-							String language = getLanguage(file.getName());
-							String country = getCountry(file.getName());
-
-							ResourceBundleFamily family = getOrCreateFamily(
-									project.getName(),
-									pluginId,
-									packageName,
-									baseName);
-							addBundle(family, getLocale(language, country), file);
-						}
-					}
-
+				// Guess package name
+				String packageName = null;
+				if (segmentCount > 1) {
+				    StringBuilder builder = new StringBuilder();
+				    for (int i = 0; i < segmentCount - 1; i++) {
+					if (i > 0)
+					    builder.append('.');
+					builder.append(path.segment(i));
+				    }
+				    packageName = builder.toString();
 				}
 
-				// Look for resource bundles in Java packages (output folders, e.g. 'bin', will be ignored)
-				if (javaProject != null) {
-					IClasspathEntry[] classpathEntries = javaProject.getResolvedClasspath(true);
-					for (IClasspathEntry entry : classpathEntries) {
-						if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
-							IPath path = entry.getPath();
-							IFolder folder = workspace.getRoot().getFolder(path);
-							IFile[] propertyFiles = collectPropertyFiles(folder);
+				String baseName = getBaseName(file.getName());
+				String language = getLanguage(file.getName());
+				String country = getCountry(file.getName());
 
-							for (IFile file : propertyFiles) {
-								String name = file.getName();
-								String baseName = getBaseName(name);
-								String language = getLanguage(name);
-								String country = getCountry(name);
-								IPackageFragment pf = javaProject.findPackageFragment(file.getParent()
-										.getFullPath());
-								String packageName = pf.getElementName();
+				ResourceBundleFamily family = getOrCreateFamily(
+					project.getName(), pluginId,
+					packageName, baseName);
+				addBundle(family, getLocale(language, country),
+					file);
+			    }
+			}
 
-								ResourceBundleFamily family = getOrCreateFamily(
-										project.getName(),
-										pluginId,
-										packageName,
-										baseName);
+		    }
+		} catch (Throwable e) {
+		    // MessagesEditorPlugin.log(e);
+		}
 
-								addBundle(family, getLocale(language, country), file);
-							}
-						} else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
-							IPackageFragmentRoot[] findPackageFragmentRoots = javaProject.findPackageFragmentRoots(entry);
-							for (IPackageFragmentRoot packageFragmentRoot : findPackageFragmentRoots) {
-								IJavaElement[] children = packageFragmentRoot.getChildren();
-								for (IJavaElement child : children) {
-									IPackageFragment pf = (IPackageFragment) child;
-									Object[] nonJavaResources = pf.getNonJavaResources();
+		// Look for resource bundles in Java packages (output folders,
+		// e.g. 'bin', will be ignored)
+		if (javaProject != null) {
+		    IClasspathEntry[] classpathEntries = javaProject
+			    .getResolvedClasspath(true);
+		    for (IClasspathEntry entry : classpathEntries) {
+			if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
+			    IPath path = entry.getPath();
+			    IFolder folder = workspace.getRoot()
+				    .getFolder(path);
+			    IFile[] propertyFiles = collectPropertyFiles(folder);
 
-									for (Object resource : nonJavaResources) {
-										if (resource instanceof IJarEntryResource) {
-											IJarEntryResource jarEntryResource = (IJarEntryResource) resource;
-											String name = jarEntryResource.getName();
-											if (name.endsWith(PROPERTIES_SUFFIX)) {
-												String baseName = getBaseName(name);
-												String language = getLanguage(name);
-												String country = getCountry(name);
-												String packageName = pf.getElementName();
+			    for (IFile file : propertyFiles) {
+				String name = file.getName();
+				String baseName = getBaseName(name);
+				String language = getLanguage(name);
+				String country = getCountry(name);
+				IPackageFragment pf = javaProject
+					.findPackageFragment(file.getParent()
+						.getFullPath());
+				String packageName = pf.getElementName();
 
-												ResourceBundleFamily family = getOrCreateFamily(
-														project.getName(),
-														pluginId,
-														packageName,
-														baseName);
+				ResourceBundleFamily family = getOrCreateFamily(
+					project.getName(), pluginId,
+					packageName, baseName);
 
-												addBundle(
-														family,
-														getLocale(language, country),
-														jarEntryResource);
-											}
-										}
-									}
-								}
-							}
-						}
-					}
+				addBundle(family, getLocale(language, country),
+					file);
+			    }
+			} else if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
+			    IPackageFragmentRoot[] findPackageFragmentRoots = javaProject
+				    .findPackageFragmentRoots(entry);
+			    for (IPackageFragmentRoot packageFragmentRoot : findPackageFragmentRoots) {
+				IJavaElement[] children = packageFragmentRoot
+					.getChildren();
+				for (IJavaElement child : children) {
+				    IPackageFragment pf = (IPackageFragment) child;
+				    Object[] nonJavaResources = pf
+					    .getNonJavaResources();
 
-					// Collect non-Java resources 
-					Object[] nonJavaResources = javaProject.getNonJavaResources();
-					ArrayList<IFile> files = new ArrayList<IFile>();
-					for (Object resource : nonJavaResources) {
-						if (resource instanceof IContainer) {
-							IContainer container = (IContainer) resource;
-							collectPropertyFiles(container, files);
-						} else if (resource instanceof IFile) {
-							IFile file = (IFile) resource;
-							String name = file.getName();
-							if (isIgnoredFilename(name))
-								continue;
-							if (name.endsWith(PROPERTIES_SUFFIX)) {
-								files.add(file);
-							}
-						}
-					}
-					for (IFile file : files) {
-
-						// Convert path to package name format
-						IPath path = file.getProjectRelativePath();
-						String packageName = null;
-						int segmentCount = path.segmentCount();
-						if (segmentCount > 1) {
-							StringBuilder builder = new StringBuilder();
-							for (int i = 0; i < segmentCount - 1; i++) {
-								if (i > 0)
-									builder.append('.');
-								builder.append(path.segment(i));
-							}
-							packageName = builder.toString();
-						}
-
-						String baseName = getBaseName(file.getName());
-						String language = getLanguage(file.getName());
-						String country = getCountry(file.getName());
+				    for (Object resource : nonJavaResources) {
+					if (resource instanceof IJarEntryResource) {
+					    IJarEntryResource jarEntryResource = (IJarEntryResource) resource;
+					    String name = jarEntryResource
+						    .getName();
+					    if (name.endsWith(PROPERTIES_SUFFIX)) {
+						String baseName = getBaseName(name);
+						String language = getLanguage(name);
+						String country = getCountry(name);
+						String packageName = pf
+							.getElementName();
 
 						ResourceBundleFamily family = getOrCreateFamily(
-								project.getName(),
-								pluginId,
-								packageName,
-								baseName);
-						addBundle(family, getLocale(language, country), file);
+							project.getName(),
+							pluginId, packageName,
+							baseName);
+
+						addBundle(
+							family,
+							getLocale(language,
+								country),
+							jarEntryResource);
+					    }
 					}
-
+				    }
 				}
-			} catch (Exception e) {
-				MessagesEditorPlugin.log(e);
+			    }
 			}
-		}
-	}
+		    }
 
-	private IFile[] collectPropertyFiles(IContainer container) throws CoreException {
-		ArrayList<IFile> files = new ArrayList<IFile>();
-		collectPropertyFiles(container, files);
-		return files.toArray(new IFile[files.size()]);
-	}
-
-	private void collectPropertyFiles(IContainer container, ArrayList<IFile> files) throws CoreException {
-		IResource[] members = container.members();
-		for (IResource resource : members) {
-			if (!resource.exists())
-				continue;
+		    // Collect non-Java resources
+		    Object[] nonJavaResources = javaProject
+			    .getNonJavaResources();
+		    ArrayList<IFile> files = new ArrayList<IFile>();
+		    for (Object resource : nonJavaResources) {
 			if (resource instanceof IContainer) {
-				IContainer childContainer = (IContainer) resource;
-				collectPropertyFiles(childContainer, files);
+			    IContainer container = (IContainer) resource;
+			    collectPropertyFiles(container, files);
 			} else if (resource instanceof IFile) {
-				IFile file = (IFile) resource;
-				String name = file.getName();
-				if (file.getProjectRelativePath().segmentCount() == 0 && isIgnoredFilename(name))
-					continue;
-				if (name.endsWith(PROPERTIES_SUFFIX)) {
-					files.add(file);
-				}
+			    IFile file = (IFile) resource;
+			    String name = file.getName();
+			    if (isIgnoredFilename(name))
+				continue;
+			    if (name.endsWith(PROPERTIES_SUFFIX)) {
+				files.add(file);
+			    }
 			}
-		}
-	}
+		    }
+		    for (IFile file : files) {
 
-	private boolean isCountry(String name) {
-		if (name == null || name.length() != 2)
-			return false;
-		char c1 = name.charAt(0);
-		char c2 = name.charAt(1);
-		return 'A' <= c1 && c1 <= 'Z' && 'A' <= c2 && c2 <= 'Z';
-	}
-
-	private Locale getLocale(String language, String country) {
-		if (language == null)
-			language = ""; //$NON-NLS-1$
-		if (country == null)
-			country = ""; //$NON-NLS-1$
-		return new Locale(language, country);
-	}
-
-	private void addBundle(ResourceBundleFamily family, Locale locale, Object resource) throws CoreException {
-		ResourceBundle bundle = new ResourceBundle(family, resource, locale);
-		if ("".equals(locale.getLanguage()))
-			bundle.load();
-		family.addBundle(bundle);
-	}
-
-	private String getBaseName(String filename) {
-		if (!filename.endsWith(PROPERTIES_SUFFIX))
-			throw new IllegalArgumentException();
-		String name = filename.substring(0, filename.length() - 11);
-		int len = name.length();
-		if (len > 3 && name.charAt(len - 3) == '_') {
-			if (len > 6 && name.charAt(len - 6) == '_') {
-				return name.substring(0, len - 6);
-			} else {
-				return name.substring(0, len - 3);
+			// Convert path to package name format
+			IPath path = file.getProjectRelativePath();
+			String packageName = null;
+			int segmentCount = path.segmentCount();
+			if (segmentCount > 1) {
+			    StringBuilder builder = new StringBuilder();
+			    for (int i = 0; i < segmentCount - 1; i++) {
+				if (i > 0)
+				    builder.append('.');
+				builder.append(path.segment(i));
+			    }
+			    packageName = builder.toString();
 			}
-		}
-		return name;
-	}
 
-	private String getLanguage(String filename) {
-		if (!filename.endsWith(PROPERTIES_SUFFIX))
-			throw new IllegalArgumentException();
-		String name = filename.substring(0, filename.length() - 11);
-		int len = name.length();
-		if (len > 3 && name.charAt(len - 3) == '_') {
-			if (len > 6 && name.charAt(len - 6) == '_') {
-				return name.substring(len - 5, len - 3);
-			} else {
-				return name.substring(len - 2);
-			}
+			String baseName = getBaseName(file.getName());
+			String language = getLanguage(file.getName());
+			String country = getCountry(file.getName());
+
+			ResourceBundleFamily family = getOrCreateFamily(
+				project.getName(), pluginId, packageName,
+				baseName);
+			addBundle(family, getLocale(language, country), file);
+		    }
+
 		}
+	    } catch (Exception e) {
+		MessagesEditorPlugin.log(e);
+	    }
+	}
+    }
+
+    private IFile[] collectPropertyFiles(IContainer container)
+	    throws CoreException {
+	ArrayList<IFile> files = new ArrayList<IFile>();
+	collectPropertyFiles(container, files);
+	return files.toArray(new IFile[files.size()]);
+    }
+
+    private void collectPropertyFiles(IContainer container,
+	    ArrayList<IFile> files) throws CoreException {
+	IResource[] members = container.members();
+	for (IResource resource : members) {
+	    if (!resource.exists())
+		continue;
+	    if (resource instanceof IContainer) {
+		IContainer childContainer = (IContainer) resource;
+		collectPropertyFiles(childContainer, files);
+	    } else if (resource instanceof IFile) {
+		IFile file = (IFile) resource;
+		String name = file.getName();
+		if (file.getProjectRelativePath().segmentCount() == 0
+			&& isIgnoredFilename(name))
+		    continue;
+		if (name.endsWith(PROPERTIES_SUFFIX)) {
+		    files.add(file);
+		}
+	    }
+	}
+    }
+
+    private boolean isCountry(String name) {
+	if (name == null || name.length() != 2)
+	    return false;
+	char c1 = name.charAt(0);
+	char c2 = name.charAt(1);
+	return 'A' <= c1 && c1 <= 'Z' && 'A' <= c2 && c2 <= 'Z';
+    }
+
+    private Locale getLocale(String language, String country) {
+	if (language == null)
+	    language = ""; //$NON-NLS-1$
+	if (country == null)
+	    country = ""; //$NON-NLS-1$
+	return new Locale(language, country);
+    }
+
+    private void addBundle(ResourceBundleFamily family, Locale locale,
+	    Object resource) throws CoreException {
+	ResourceBundle bundle = new ResourceBundle(family, resource, locale);
+	if ("".equals(locale.getLanguage()))
+	    bundle.load();
+	family.addBundle(bundle);
+    }
+
+    private String getBaseName(String filename) {
+	if (!filename.endsWith(PROPERTIES_SUFFIX))
+	    throw new IllegalArgumentException();
+	String name = filename.substring(0, filename.length() - 11);
+	int len = name.length();
+	if (len > 3 && name.charAt(len - 3) == '_') {
+	    if (len > 6 && name.charAt(len - 6) == '_') {
+		return name.substring(0, len - 6);
+	    } else {
+		return name.substring(0, len - 3);
+	    }
+	}
+	return name;
+    }
+
+    private String getLanguage(String filename) {
+	if (!filename.endsWith(PROPERTIES_SUFFIX))
+	    throw new IllegalArgumentException();
+	String name = filename.substring(0, filename.length() - 11);
+	int len = name.length();
+	if (len > 3 && name.charAt(len - 3) == '_') {
+	    if (len > 6 && name.charAt(len - 6) == '_') {
+		return name.substring(len - 5, len - 3);
+	    } else {
+		return name.substring(len - 2);
+	    }
+	}
+	return ""; //$NON-NLS-1$
+    }
+
+    private String getCountry(String filename) {
+	if (!filename.endsWith(PROPERTIES_SUFFIX))
+	    throw new IllegalArgumentException();
+	String name = filename.substring(0, filename.length() - 11);
+	int len = name.length();
+	if (len > 3 && name.charAt(len - 3) == '_') {
+	    if (len > 6 && name.charAt(len - 6) == '_') {
+		return name.substring(len - 2);
+	    } else {
 		return ""; //$NON-NLS-1$
+	    }
 	}
+	return ""; //$NON-NLS-1$
+    }
 
-	private String getCountry(String filename) {
-		if (!filename.endsWith(PROPERTIES_SUFFIX))
-			throw new IllegalArgumentException();
-		String name = filename.substring(0, filename.length() - 11);
-		int len = name.length();
-		if (len > 3 && name.charAt(len - 3) == '_') {
-			if (len > 6 && name.charAt(len - 6) == '_') {
-				return name.substring(len - 2);
-			} else {
-				return ""; //$NON-NLS-1$
-			}
-		}
-		return ""; //$NON-NLS-1$
-	}
+    private ResourceBundleFamily getOrCreateFamily(String projectName,
+	    String pluginId, String packageName, String baseName) {
 
-	private ResourceBundleFamily getOrCreateFamily(String projectName, String pluginId, String packageName,
-			String baseName) {
+	// Ignore project name
+	if (pluginId != null)
+	    projectName = null;
 
-		// Ignore project name
-		if (pluginId != null)
-			projectName = null;
-
-		for (ResourceBundleFamily family : bundleFamilies) {
-			if (areEqual(family.getProjectName(), projectName)
-					&& areEqual(family.getPluginId(), pluginId)
-					&& areEqual(family.getPackageName(), packageName)
-					&& areEqual(family.getBaseName(), baseName)) {
-				return family;
-			}
-		}
-		ResourceBundleFamily family = new ResourceBundleFamily(
-			this,
-			projectName,
-			pluginId,
-			packageName,
-			baseName);
-		bundleFamilies.add(family);
+	for (ResourceBundleFamily family : bundleFamilies) {
+	    if (areEqual(family.getProjectName(), projectName)
+		    && areEqual(family.getPluginId(), pluginId)
+		    && areEqual(family.getPackageName(), packageName)
+		    && areEqual(family.getBaseName(), baseName)) {
 		return family;
+	    }
 	}
+	ResourceBundleFamily family = new ResourceBundleFamily(this,
+		projectName, pluginId, packageName, baseName);
+	bundleFamilies.add(family);
+	return family;
+    }
 
-	private boolean isIgnoredFilename(String filename) {
-		return filename.equals("build.properties") || filename.equals("logging.properties"); //$NON-NLS-1$ //$NON-NLS-2$
-	}
+    private boolean isIgnoredFilename(String filename) {
+	return filename.equals("build.properties") || filename.equals("logging.properties"); //$NON-NLS-1$ //$NON-NLS-2$
+    }
 
-	private boolean areEqual(String str1, String str2) {
-		return str1 == null && str2 == null || str1 != null && str1.equals(str2);
-	}
+    private boolean areEqual(String str1, String str2) {
+	return str1 == null && str2 == null || str1 != null
+		&& str1.equals(str2);
+    }
 
 }