Index: tmp/org.txm.translate.rcp/preferences TXM 0.8.0.ods
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: tmp/org.txm.translate.rcp/preferences TXM 0.8.0.ods
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/i18n/PluginMessagesManager.java
===================================================================
--- tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/i18n/PluginMessagesManager.java	(revision 1406)
+++ tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/i18n/PluginMessagesManager.java	(revision 1407)
@@ -131,7 +131,7 @@
 	/**
 	 * 
 	 * @param projectDirectory
-	 * @param javaMessageFile
+	 * @param javaPreferenceFile
 	 * @throws UnsupportedEncodingException
 	 * @throws FileNotFoundException
 	 * @throws IOException
Index: tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/PluginPreferencesManager.java
===================================================================
--- tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/PluginPreferencesManager.java	(revision 0)
+++ tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/PluginPreferencesManager.java	(revision 1407)
@@ -0,0 +1,754 @@
+package org.txm.rcp.translate.preferences;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang.StringUtils;
+import org.txm.rcp.translate.devtools.NormalizeKeys;
+import org.txm.utils.BiHashMap;
+import org.txm.utils.io.IOUtils;
+
+/**
+ *  
+ * Check any missing key in both of messages.properties and Preference.java files
+ *
+ * @author mdecorde
+ * @author sjacquot
+ *
+ */
+public class PluginPreferencesManager {
+	/**
+	 * Files encoding.
+	 */
+	public static String ENCODING = "UTF-8";
+
+	public final static String FILE_SEPARATOR = System.getProperty("file.separator");
+
+	/**
+	 * Debug state.
+	 */
+	protected boolean debug;
+
+	/**
+	 * Project root directory.
+	 */
+	protected File projectDirectory;
+
+	/**
+	 * Java message file, eg.: TXMCorePreferences.java, ConcordanceUIPreferences.java, etc.
+	 */
+	protected File javaPreferenceFile;
+
+	/**
+	 * Source files of the project.
+	 */
+	protected ArrayList<File> srcFiles;
+
+	/**
+	 * Extensions to use when creating the source files list.
+	 */
+	protected static final String[] srcFilesExtensions = new String[] {"java", "groovy"};
+
+	/**
+	 * Index of the keys used and their associated files.
+	 */
+	protected TreeMap<String, TreeSet<File>> usedKeysFilesIndex = new TreeMap<String, TreeSet<File>>();
+
+	/**
+	 * the XXXPreferences.java preferences keys
+	 */
+	TreeSet<String> preferenceKeys = new TreeSet<String>();
+	
+	protected TreeMap<String, Object> names = new TreeMap<String, Object>();
+	
+	protected TreeMap<String, Object> defaultValues = new TreeMap<String, Object>();
+
+	/**
+	 * plugin.xml file -> contains eventually keys
+	 */
+	protected File pluginXMLFile;
+
+	public File getPluginXMLFile() {
+		return pluginXMLFile;
+	}
+
+	/**
+	 * Stores the key modifications for further saves in the source files
+	 */
+	HashMap<String, String> keyModifications = new HashMap<String, String>();
+
+	/**
+	 * the properties files langs
+	 */
+	BiHashMap<File, String> file2lang = new BiHashMap<File, String>();
+
+	/**
+	 * 
+	 * @param projectDirectory
+	 * @param javaPreferenceFile
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public PluginPreferencesManager(File projectDirectory) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		this(projectDirectory, false);
+	}
+
+	/**
+	 * 
+	 * @param projectDirectory
+	 * @param debug
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public PluginPreferencesManager(File projectDirectory, boolean debug) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		this(projectDirectory, findPreferenceFile(projectDirectory), debug);
+	}
+
+
+
+	/**
+	 * 
+	 * @param projectDirectory
+	 * @param javaPreferenceFile
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public PluginPreferencesManager(File projectDirectory, File javaPreferenceFile) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		this(projectDirectory, javaPreferenceFile, false);
+	}
+
+
+
+	/**
+	 * 
+	 * @param projectDirectory
+	 * @param javaPreferenceFile
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public PluginPreferencesManager(File projectDirectory, File javaPreferenceFile, boolean debug) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+
+		this.javaPreferenceFile = javaPreferenceFile;
+		this.projectDirectory = projectDirectory;
+		this.pluginXMLFile = new File(projectDirectory, "plugin.xml");
+		this.srcFiles = new ArrayList<File>();
+		this.debug = debug;
+
+		if (debug) {
+			System.out.println("********************************************************************************************************************");
+			System.out.println("PluginPreferencesManager.PluginPreferences(): project root directory = " + this.projectDirectory);
+			System.out.println("PluginPreferencesManager.PluginPreferences(): java message file = " + this.javaPreferenceFile);
+		}
+
+		// create the project source files list
+		this.createSourceFilesList();
+
+		//this.createKeysGlobalREGEX();
+		this.createUsedKeysFilesIndex();
+
+
+		if (this.javaPreferenceFile != null) {
+			String className = getPreferenceClassName();
+			
+			BufferedReader reader2 = new BufferedReader(new InputStreamReader(new FileInputStream(javaPreferenceFile), ENCODING));
+			String line2 = reader2.readLine();
+			while (line2 != null) {
+				line2 = line2.trim();
+
+				if (line2.startsWith("public static final String")) {
+					int idx = line2.indexOf("//");
+					if (idx > 0 && line2.contains("\"")) { // remove comment from line
+						//System.out.println("COMMENT DETECTED AFTER KEY: line="+line2+" IN "+javaPreferenceFile);
+						line2 = line2.substring(0, idx).trim();
+					}
+					if (line2.endsWith(";") && line2.contains("=") && line2.contains("\"")) {
+						String key = line2.substring(27, line2.indexOf("=") -1);
+						String name = line2.substring(line2.indexOf("\"")+1, line2.indexOf("\";"));
+
+						if(debug)	{
+							System.out.println("PluginPreferencesManager.PluginPreferencesManager(): messages key: " + line2 + " added.");
+						}
+						//System.out.println("+K='"+key+"'");
+						preferenceKeys.add(key);
+						names.put(key, name);
+					}
+				} else if (line2.startsWith("preferences.put")) {
+					int idx = line2.indexOf("//");
+					if (idx > 0 && line2.contains("\"")) { // remove comment from line
+						//System.out.println("COMMENT DETECTED AFTER KEY: line="+line2+" IN "+javaPreferenceFile);
+						line2 = line2.substring(0, idx).trim();
+					}
+//					System.out.println(line2);
+//					System.out.println(""+line2.indexOf("preferences.put")+" "+line2.indexOf("(")+" "+line2.indexOf(", ")+ " "+line2.indexOf(");"));
+					if (line2.indexOf("preferences.put") < line2.indexOf("(") && 
+							line2.indexOf("(") < line2.indexOf(", ") && 
+							line2.indexOf(", ") < line2.indexOf(");")) {
+						
+						String key = line2.substring(line2.indexOf("(")+1, line2.indexOf(", "));
+						String value = line2.substring(line2.indexOf(", ")+2, line2.indexOf(");"));
+						//System.out.println("K2='"+key+"' V='"+value+"'");
+						if(debug)	{
+							System.out.println("PluginPreferencesManager.PluginPreferencesManager(): messages key: " + line2 + " added.");
+						}
+						defaultValues.put(key, value);
+					}
+				}
+
+				line2 = reader2.readLine();
+			}
+			reader2.close();
+
+
+			if(debug)	{
+				System.out.println("PluginPreferencesManager.PluginPreferencesManager(): number of keys: " + this.preferenceKeys.size() + ".");
+			}
+
+			if(debug)	{
+				this.dumpUsedKeysFilesIndex();
+			}
+		}
+		else {
+			if (debug) {
+				System.err.println("PluginPreferencesManager.PluginPreferencesManager(): skipped, java message file not found for project " + this.projectDirectory + ".");
+			}
+		}
+	}
+
+	//		/**
+	//		 * Creates a global REGEX containing all keys to later search in files.
+	//		 */
+	//		public void createKeysGlobalREGEX()	{
+	//			
+	//			if(messageKeys.size() == 0) {
+	//				return;
+	//			}
+	//			
+	//			StringBuffer buffer = new StringBuffer();
+	//			buffer.append(this.getPreferenceClassName() + "\\\\.(");
+	//			
+	//			int i = 0;
+	//			for (String key : messageKeys) {
+	//				if(i > 0)	{
+	//					buffer.append("|" + key);	
+	//				}
+	//				else {
+	//					buffer.append(key);
+	//				}
+	//				i++;
+	//			}
+	//			
+	//			// remove first pipe
+	//			//buffer.deleteCharAt(0);
+	//			
+	//			this.keysGlobalREGEX = Pattern.compile("(" + buffer + "))");
+	//			
+	//			if(debug)	{
+	//				System.out.println("PluginPreferencesManager.createKeysGlobalREGEX(): REGEX created: " + this.keysGlobalREGEX + ".");
+	//			}
+	//			
+	//		}
+
+	public static File findPreferenceFile(File projectDirectory2) {
+		File messagesPackageDir = new File(projectDirectory2, "src/"+projectDirectory2.getName().replaceAll("\\.", "/")+"/preferences");
+
+		if (!messagesPackageDir.exists()) {
+			messagesPackageDir = new File(projectDirectory2, "src/java/"+projectDirectory2.getName().replaceAll("\\.", "/")+"/preferences");
+		}
+
+		if (!messagesPackageDir.exists()) {
+			messagesPackageDir = new File(projectDirectory2, "src/main/java/"+projectDirectory2.getName().replaceAll("\\.", "/")+"/preferences");
+		}
+
+		if (!messagesPackageDir.exists()) {
+			return null;
+		}
+
+		for (File messagesJavaFile : messagesPackageDir.listFiles(IOUtils.FILTER_HIDDEN)) {
+			if (messagesJavaFile.isDirectory()) continue;
+			if (!messagesJavaFile.getName().endsWith("Preferences.java")) continue;
+			return messagesJavaFile;
+		}
+		return null;
+	}
+
+	/**
+	 * Creates/updates the index of the keys used and their associated files.
+	 * @throws IOException 
+	 */
+	public void createUsedKeysFilesIndex() throws IOException	{
+		this.usedKeysFilesIndex = new TreeMap<String, TreeSet<File>>();
+
+		// New version using REGEX
+		for (File file : this.srcFiles) {
+			if (!file.exists()) continue;
+			String lines = IOUtils.getText(file, PluginPreferencesManager.ENCODING);
+
+			Matcher m = WorkspacePreferencesManager.KEY_REGEX.matcher(lines);
+			//Matcher m = this.keysGlobalREGEX.matcher(lines);
+			while (m.find()) {
+				// Get the matching string
+				String key = m.group();
+
+				if (!this.usedKeysFilesIndex.containsKey(key)) {
+					this.usedKeysFilesIndex.put(key, new TreeSet<File>());
+				}
+				this.usedKeysFilesIndex.get(key).add(file);
+
+				if(debug) {
+					System.out.println("PluginPreferencesManager.createUsedKeysFilesIndex(): messages key: " + key + " added for file " + file +  ".");
+				}
+			}
+		}
+	}
+
+
+	/**
+	 * Dumps in console the index of the keys used and their associated files.
+	 */
+	public void dumpUsedKeysFilesIndex()	{
+
+		System.out.println("PluginPreferencesManager.dumpUsedKeysIndex(): dumping used keys files index...");
+
+		if(this.usedKeysFilesIndex == null)	{
+			System.out.println("PluginPreferencesManager.dumpUsedKeysIndex(): project have no used keys.");
+			return;
+		}
+
+		for (Map.Entry<String, TreeSet<File>> entry : this.usedKeysFilesIndex.entrySet()) {
+			System.out.println("key: " + entry.getKey());
+			if(entry.getValue().isEmpty())	{
+				System.out.println("   file(s): -not used in any file of the project " + this.getProjectDirectory() + "-");
+			}
+			else	{
+				for(File file : entry.getValue())	{
+					System.out.println("   file(s): " + file);
+				}
+			}
+		}
+
+		System.out.println("PluginPreferencesManager.dumpUsedKeysIndex(): number of used keys: " + this.usedKeysFilesIndex.size() + ".");
+	}
+
+	/***
+	 * @param key
+	 * @return all source files using the specified message key (except the main Java message file).
+	 */
+	public TreeSet<File> getFilesUsingKey(String key) {
+		if (usedKeysFilesIndex.containsKey(key)) {
+			return this.usedKeysFilesIndex.get(key);
+		} else {
+			return new TreeSet<File>();
+		}
+	}
+
+	/***
+	 * @param key local key name
+	 * @return all source files using the specified local message key (except the main Java message file).
+	 */
+	public TreeSet<File> getFilesUsingLocalKey(String key) {
+		return getFilesUsingKey(getKeyFullName(key));
+	}
+
+
+	/**
+	 * Returns the keys of all messages that are not used in the project itself.
+	 * @return a sorted list containing all unused keys
+	 */
+	public ArrayList<String> getUnusedKeys()	{
+		return getUnusedKeys(usedKeysFilesIndex, debug);
+	}
+
+	/**
+	 * @param usedKeysFilesIndex
+	 * 
+	 * @return a sorted list containing all unused keys of all messages that are not used in the used key files index.
+	 */
+	public static ArrayList<String> getUnusedKeys(TreeMap<String, TreeSet<File>> usedKeysFilesIndex, boolean debug)	{
+		ArrayList<String> unusedKeys = new ArrayList<String>();
+		for (Map.Entry<String, TreeSet<File>> entry : usedKeysFilesIndex.entrySet()) {
+			if(entry.getValue().isEmpty())	{
+
+				if(debug)	{
+					System.out.println("PluginPreferencesManager.getUnusedKeys(): unused key found: " + entry.getKey() + ".");
+				}
+
+				unusedKeys.add(entry.getKey());
+			}
+		}
+
+		Collections.sort(unusedKeys);
+		return unusedKeys;
+	}
+
+	public void put(String key, String defaultValue) {
+		preferenceKeys.add(key);
+		defaultValues.put(key, defaultValue);
+	}
+
+	public Object getDefaultValue(String key) {
+		return defaultValues.get(key);
+	}
+
+	public TreeSet<String> getPreferenceKeys() {
+		return preferenceKeys;
+	}
+
+	public File getPreferenceFile() {
+		return javaPreferenceFile;
+	}
+
+	public String getPreferenceClassName() {
+		if (javaPreferenceFile == null) return "";
+		return javaPreferenceFile.getName().substring(0, javaPreferenceFile.getName().length() - 5);
+	}
+
+	public String getPreferenceFullClassName() {
+		if (javaPreferenceFile == null) return "";
+		return javaPreferenceFile.getAbsolutePath().substring(javaPreferenceFile.getAbsolutePath().lastIndexOf("org" + FILE_SEPARATOR + "txm" + FILE_SEPARATOR),
+				javaPreferenceFile.getAbsolutePath().length() - 5).replace(FILE_SEPARATOR, ".");
+	}
+
+	/**
+	 * @return the XXXPreferences.java class name without the 'Preferences' part
+	 */
+	public String getPreferenceName() {
+		if (javaPreferenceFile == null) return "";
+		return javaPreferenceFile.getName().substring(0, javaPreferenceFile.getName().length()-5-8);
+	}
+
+	public String getPreferenceFullName() {
+		if (javaPreferenceFile == null) return "";
+		return javaPreferenceFile.getAbsolutePath().substring(javaPreferenceFile.getAbsolutePath().lastIndexOf("org" + FILE_SEPARATOR + "txm" + FILE_SEPARATOR) + 8, 
+				javaPreferenceFile.getAbsolutePath().length() - 5 - 8).replace(FILE_SEPARATOR, ".");
+	}
+
+	/**
+	 * Returns the full name of the specified key including the Java message class name.
+	 * @param key
+	 * @return
+	 */
+	public String getKeyFullName(String key)	{
+		return this.getPreferenceClassName() + "." + key;
+	}
+
+	public static Collator col = Collator.getInstance(Locale.FRANCE);
+	public static Comparator comp = new Comparator<String>() {
+		@Override
+		public int compare(String arg0, String arg1) {
+			return col.compare(arg0, arg1);
+		}
+	};
+	static {
+		col.setStrength(Collator.TERTIARY);
+	}
+	public void saveChanges(boolean replaceFiles) throws IOException {
+
+		if (javaPreferenceFile == null) return;
+
+		// write message File
+		File newJavaPreferenceFile = new File(javaPreferenceFile.getParentFile(), javaPreferenceFile.getName()+".new");
+
+//		ArrayList<String> lines = IOUtils.getLines(javaPreferenceFile, "UFT-8");
+//		TreeSet<String> oldKeys = new TreeSet<String>(IOUtils.findWithGroup(javaPreferenceFile, "public static String ([^\"=;]+);"));
+//		TreeSet<String> newKeys = new TreeSet<String>(preferenceKeys);
+//		TreeSet<String> writtenKeys = new TreeSet<String>();
+//		
+//		newKeys.removeAll(oldKeys);
+//		newKeys.removeAll(keyModifications.values()); // now contains only the very newly created keys
+//
+//		if (replaceFiles) {
+//			newJavaPreferenceFile = javaPreferenceFile;
+//		}
+//
+//		PrintWriter out = IOUtils.getWriter(newJavaPreferenceFile, ENCODING);
+//
+//		// update lines
+//		for (String line : lines) {
+//			String l = line.trim();// remove tabs
+//			String comments = "";
+//			int idx = l.indexOf("//"); // remove comments
+//			if (idx > 0) {
+//				comments = l.substring(idx).trim();
+//				l = l.substring(0, idx).trim();
+//			}
+//
+//			if (l.startsWith("private static final String BUNDLE_NAME")) {
+//				out.println(line);
+//
+//				// write the totally new keys
+//				if (newKeys.size() > 0) {
+//					out.println("\t");
+//				}
+//				for (String key : newKeys) {
+//					if (writtenKeys.contains(key)) continue; // key already written
+//					out.println("\tpublic static String "+key+";");
+//					writtenKeys.add(key);
+//				}
+//			} else if (l.startsWith("public static String") && l.endsWith(";") && !l.contains("=") && !l.contains("\"")) {
+//
+//				String key = l.substring(21, l.length() -1);
+//				if (preferenceKeys.contains(key)) {
+//					if (writtenKeys.contains(key)) continue; // key already written
+//					out.println(line); // keep the line
+//					writtenKeys.add(key);
+//				} else if (keyModifications.containsKey(key)){
+//					// the key has been renamed
+//					if (writtenKeys.contains(keyModifications.get(key))) continue; // key already written
+//					out.println("\tpublic static String "+keyModifications.get(key)+"; "+comments);
+//					writtenKeys.add(keyModifications.get(key));
+//				} else {
+//					// the key has been removed
+//				}
+//			} else {
+//				out.println(line);
+//			}
+//		}
+//
+//		out.close();
+	}
+
+	public void summary() {
+		String name = getPreferenceClassName();
+		if (name == null || name.length() == 0) return;
+		System.out.println(name+" "+preferenceKeys.size()+" preferences");
+//		System.out.println(preferenceKeys);
+//		System.out.println(names);
+//		System.out.println(defaultValues);
+		for (String key : preferenceKeys) {
+			System.out.println(key+"\t"+names.get(key)+"\t"+defaultValues.get(key));
+		}
+	}
+
+	/**
+	 * Parses the specified path and stores a list of the source files. 
+	 */
+	private void createSourceFilesList(File path)	{
+		File[] list = path.listFiles(IOUtils.FILTER_HIDDEN);
+
+		if (list == null) {
+			return;
+		}
+
+		for (File file : list) {
+			if (file.isDirectory()) {
+				this.createSourceFilesList(file);
+			}
+			else if (!file.equals(this.javaPreferenceFile)
+					&& Arrays.asList(this.srcFilesExtensions).contains(FilenameUtils.getExtension(file.getName())) 
+					) {
+
+				if (debug) {
+					System.out.println("PluginPreferencesManager.createSourceFilesList(): adding source files " + file + ".");
+				}
+				else	{
+					//System.out.print(".");
+				}
+
+				this.srcFiles.add(file);
+			}
+		}
+	}
+
+	/**
+	 * Parses the project and stores a list of the source files.
+	 */
+	public void createSourceFilesList()	{
+
+		if (debug) {
+			System.out.println("PluginPreferencesManager.loadSourceFilesList(): creating source files list for extensions [" + StringUtils.join(this.srcFilesExtensions, ", ") + "]...");
+		}
+
+		this.createSourceFilesList(this.projectDirectory);
+
+
+		if(debug) {
+			System.out.println("PluginPreferencesManager.loadSourceFilesList(): done. Source files count = " + this.srcFiles.size() + ".");
+		}
+	}
+
+	/**
+	 * Rename a key and update in the properties file the keys
+	 * 
+	 * stores the modification to rename the keys later in the Workspace source files
+	 * 
+	 * @param oldName
+	 * @param newName
+	 */
+	public void renameKey(String oldName, String newName) {
+
+		if (!preferenceKeys.contains(oldName)) {
+			System.err.println("PluginPreferencesManager.renameKey(): key=" + oldName + " not found, aborting renaming to " + newName + ".");
+			return;
+		}
+
+		// continue only if key name has changed
+		if(oldName.equals(newName))	{
+			if(debug)	{
+				System.out.println("PluginPreferencesManager.renameKey(): no changes, skipped key: " + oldName + " = " + newName);
+			}
+			return;
+		}
+
+		preferenceKeys.remove(oldName);
+		preferenceKeys.add(newName);
+
+		defaultValues.put(newName, defaultValues.get(oldName));
+		defaultValues.remove(oldName);
+
+		//System.out.println("M+ "+oldName+" -> "+newName);
+		keyModifications.put(oldName, newName);
+	}
+
+	/**
+	 * Remove a messages from XXPreferences.java and messages.properties files
+	 * 
+	 * @param key the local name of the key to remove
+	 */
+	public void removeKey(String key) {
+		if (!preferenceKeys.contains(key)) {
+			System.err.println("PluginPreferencesManager.removeKey(): key=" + key + " not found, aborting removing.");
+			return;
+		}
+
+		preferenceKeys.remove(key);
+		defaultValues.remove(key);
+
+		keyModifications.remove(key); // if any modifications was done
+	}
+
+	public void newKey(String defaultPreference) {
+		String key = NormalizeKeys.normalize(defaultPreference);
+		String newKey = ""+key;
+		int c = 1;
+		while (preferenceKeys.contains(newKey)) {
+			newKey = key+"_"+(c++);
+		}
+
+		preferenceKeys.add(newKey);
+	}
+
+	/**
+	 * 
+	 * @return the renamed keys
+	 */
+	public HashMap<String, String> getKeyModifications() {
+		return keyModifications;
+	}
+
+	public BiHashMap<File, String> getFile2lang() {
+		return file2lang;
+	}
+
+	public TreeMap<String, Object> getDefaults() {
+		return defaultValues;
+	}
+
+	/**
+	 * Gets the project root directory.
+	 * @return the projectDirectory
+	 */
+
+	public File getProjectDirectory() {
+		return projectDirectory;
+	}
+
+
+	/**
+	 * Dumps the specified BiHashMap<String, String> to standard output.
+	 */
+	public void dump(BiHashMap<String, String> messages)	{
+		for (String key : messages.getKeys()) {
+			System.out.println("PluginPreferencesManager.dump(): " + key + "=" + messages.get(key));
+		}
+	}
+
+
+	/**
+	 * Dumps the keys replacements table.
+	 */
+	public void dumpKeysReplacements()	{
+		System.out.println("PluginPreferencesManager.dumpKeysReplacements(): keys replacements table");
+		for (String key : this.keyModifications.keySet()) {
+			System.out.println("PluginPreferencesManager.dumpKeysReplacements(): " + key + "=>" + this.keyModifications.get(key));
+		}
+	}
+
+	/**
+	 * @return the usedKeysIndex
+	 */
+	public TreeMap<String, TreeSet<File>> getUsedKeysFilesIndex() {
+		return usedKeysFilesIndex;
+	}
+
+	/**
+	 * 
+	 * @param args
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+
+		long startTime = System.currentTimeMillis();
+
+		//File projectFile = new File(new File(System.getProperty("user.dir")).getParentFile().getAbsolutePath() + "/org.txm.rcp");
+		File projectFile = new File(new File(System.getProperty("user.dir")).getParentFile().getAbsolutePath() + "/org.txm.core");
+
+		PluginPreferencesManager pmManager = new PluginPreferencesManager(projectFile, true);
+
+		// test to find files using the specified key
+		/*
+		String key = "TXMCorePreferences.binaryDirectory";
+		TreeSet<File> files = pmManager.getFilesUsingKey(key);
+		System.out.println("getFilesUsingKey: files using key: " + key);
+		for(File file : files)	{
+			System.out.println("   file: " + file);
+		}
+		key = "TXMCorePreferences.common_frequency";
+		files = pmManager.getFilesUsingKey(key);
+		System.out.println("getFilesUsingKey: files using key: " + key);
+		for(File file : files)	{
+			System.out.println("   file: " + file);
+		}
+
+		// test to find unused keys
+		ArrayList<String> unusedKeys = pmManager.getUnusedKeys();
+		for (int i = 0; i < unusedKeys.size(); i++) {
+			System.out.println("findUnusedKeys: key " + unusedKeys.get(i) + " is unused in project " + pmManager.getProjectDirectory() + " (main language value = " + pmManager.getPreferencesForLang("").get(unusedKeys.get(i)) + ")");	
+		}
+		 */
+		//dict.summary();
+
+		pmManager.saveChanges(false);
+
+		System.out.println("dir="+pmManager.getProjectDirectory());
+		System.out.println("Elapsed time:"+ ((double)(System.currentTimeMillis()-startTime)/1000));
+
+		System.out.println("PluginPreferencesManager.main(): done.");
+	}
+}
\ No newline at end of file

Property changes on: tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/PluginPreferencesManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Index: tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/WorkspacePreferencesManager.java
===================================================================
--- tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/WorkspacePreferencesManager.java	(revision 0)
+++ tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/WorkspacePreferencesManager.java	(revision 1407)
@@ -0,0 +1,318 @@
+package org.txm.rcp.translate.preferences;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import org.txm.stat.utils.ConsoleProgressBar;
+import org.txm.utils.io.IOUtils;
+
+/**
+ * Manages the messages of the TXM projects of an RCP workspace
+ * 
+ * @author mdecorde
+ *
+ */
+public class WorkspacePreferencesManager {
+
+	/**
+	 * Debug state.
+	 */
+	protected boolean debug = false;
+
+	/**
+	 * the plugins discovered and their messages
+	 */
+	LinkedHashMap<File, PluginPreferencesManager> pluginsPreferencesPerProject = new LinkedHashMap<File, PluginPreferencesManager>();
+
+	/**
+	 * the Eclipse RCP workspace location containing the projects
+	 */
+	File workspaceLocation;
+
+	/**
+	 * Index of the keys used in all plugins sources files.
+	 */
+	protected TreeMap<String, TreeSet<File>> usedKeysFilesIndex;
+
+	/**
+	 * Generic Regex to find keys in source files 
+	 */
+	public static final Pattern KEY_REGEX = Pattern.compile("(?:[A-Z][a-zA-Z0-9]+)?Preferences\\.[a-zA-Z0-9_]+");
+
+	/**
+	 * Generic Regex to find Strings in source files. Warning the "\"" strings are not found. 
+	 */
+	public static final Pattern STRING_REGEX = Pattern.compile("\"[^\"]+\"");
+
+	/**
+	 * 
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public WorkspacePreferencesManager() throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		this(false);
+	}
+
+	/**
+	 * Creates the manager using the "user.dir" parent directory -> works when run from Eclipse
+	 * 
+	 * @throws IOException 
+	 * @throws FileNotFoundException 
+	 * @throws UnsupportedEncodingException 
+	 */
+	public WorkspacePreferencesManager(boolean debug) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		this(new File(System.getProperty("user.dir")).getParentFile(), debug);
+	}
+
+	/**
+	 * Build a WorkspacePreferencesManager for a certain workspace directory
+	 * 
+	 * @param workspaceLocation
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public WorkspacePreferencesManager(File workspaceLocation, boolean debug) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+
+		if (!new File(workspaceLocation, ".metadata").exists()) {
+			throw new IllegalArgumentException("Workspace directory is not a RCP workspace: "+workspaceLocation);
+		}
+
+		this.workspaceLocation = workspaceLocation;
+		this.debug = debug;
+
+		if (debug) {
+			System.out.println("WorkspacePreferencesManager.WorkspacePreferencesManager(): workspace location = " + this.workspaceLocation);
+		}
+
+		if (!workspaceLocation.exists()) return;
+		if (!workspaceLocation.isDirectory()) {
+			System.out.println("Error: workspace not found in: "+workspaceLocation);
+			return;
+		}
+
+		System.out.println("Initializing project preferences...");
+		ArrayList<File> files = new ArrayList<File>();
+		for (File project : workspaceLocation.listFiles(IOUtils.FILTER_HIDDEN)) {
+			if (!project.isDirectory()) continue;
+			if (project.isHidden()) continue;
+			if (!project.getName().startsWith("org.txm")) continue;
+			if (project.getName().endsWith(".feature")) continue;
+			files.add(project);
+		}
+		ConsoleProgressBar cpb = new ConsoleProgressBar(files.size());
+		for (File project : files) {
+			cpb.tick();
+
+			//			File messagesPackageDir = new File(project, "src/"+project.getName().replaceAll("\\.", "/")+"/messages");
+			//			if (!messagesPackageDir.exists()) {
+			//				messagesPackageDir = new File(project, "src/java/"+project.getName().replaceAll("\\.", "/")+"/messages");
+			//			}
+			//			//System.out.println(messagesPackageDir.getAbsolutePath());
+			//
+			//			File messagesJavaFile = PluginPreferences.findPreferenceFile(project);
+
+			//			if (messagesJavaFile != null && messagesJavaFile.exists()) {
+
+			PluginPreferencesManager preferences = new PluginPreferencesManager(project, debug);
+
+			pluginsPreferencesPerProject.put(project, preferences);
+
+			if (debug) {
+				System.out.println(project + "=" + preferences.getPreferenceKeys().size() + " preferences and "+preferences.getDefaults().size()+" default values.");
+			}
+			//			}
+		}
+		cpb.done();
+
+		this.createUsedKeysFilesIndex();
+
+		// Log summary
+		if (debug) {
+
+			this.dumpUsedKeysFilesIndex();
+
+			System.out.println("WorkspacePreferencesManager.WorkspacePreferencesManager(): ------------------ process summary --------------------------------------------------------------");
+			System.out.println("WorkspacePreferencesManager.WorkspacePreferencesManager(): numbers of projects: " + this.pluginsPreferencesPerProject.size() + ".");
+			System.out.println("WorkspacePreferencesManager.WorkspacePreferencesManager(): numbers of used keys: " + this.usedKeysFilesIndex.size() + ".");
+			System.out.println("WorkspacePreferencesManager.WorkspacePreferencesManager(): done.");
+		}
+	}
+
+	public TreeMap<String, TreeSet<File>> getUsedKeysFilesIndex() {
+		return usedKeysFilesIndex;
+	}
+
+	/**
+	 *  Dumps the index of the keys used and their associated files.
+	 */
+	protected void dumpUsedKeysFilesIndex() {
+		System.out.println("WorkspacePreferencesManager.dumpUsedKeysIndex(): dumping used keys files index...");
+
+		for (Map.Entry<String, TreeSet<File>> entry : this.usedKeysFilesIndex.entrySet()) {
+			System.out.println(entry.getKey());
+			if(entry.getValue().isEmpty())	{
+				System.out.println("\t-not used in any file of the workspace-");
+			}
+			else	{
+				for(File file : entry.getValue())	{
+					System.out.println("\t" + file);
+				}
+			}
+		}
+
+		System.out.println("WorkspacePreferencesManager.dumpUsedKeysFilesIndex(): number of used keys: " + this.usedKeysFilesIndex.size());
+	}
+
+	/**
+	 * Save modifications of keys of all known PluginPreferences in all known source files
+	 * @throws IOException 
+	 */
+	public void saveKeyModificationsInSources() throws IOException {
+//		HashMap<String, String> modifications = new HashMap<String, String>();
+//
+//		// stores all modifications
+//		ArrayList<PluginPreferencesManager> plugins = new ArrayList<PluginPreferencesManager>(pluginsPreferencesPerProject.values());
+//
+//		// sort plugins by name length. Needed to not erase a replacement: for messages BPreferences.xx and ABPreferences.xx, ABPreferences.xx should be replaced first
+//		Collections.sort(plugins, new Comparator<PluginPreferencesManager>() {
+//			@Override
+//			public int compare(PluginPreferencesManager arg0, PluginPreferencesManager arg1) {
+//				return arg1.getPreferenceName().length() - arg0.getPreferenceName().length();
+//			}
+//
+//		});
+//
+//		// build the global keys used in sources
+//		for (PluginPreferencesManager pm : plugins) {
+//			HashMap<String, String> modifs = pm.getKeyModifications();
+//			String name = pm.getPreferenceClassName();
+//
+//			for (String old : modifs.keySet()) {
+//				modifications.put(pm.getKeyFullName(old), pm.getKeyFullName(modifs.get(old))); // prefix the key with class name: Key -> XXXPreferences.Key used in sources
+//			}
+//		}
+//
+//		// update source files
+//
+//		// sort keys by name length. Needed to not erase a replacement: for messages BPreferences.xx and ABPreferences.xx, ABPreferences.xx should be replaced first
+//		ArrayList<String> keys = new ArrayList<String>(modifications.keySet());
+//		Collections.sort(keys, new Comparator<String>() {
+//			@Override
+//			public int compare(String arg0, String arg1) {
+//				return arg1.length() - arg0.length();
+//			}
+//		});
+//
+//		System.out.println("Keys to update: "+keys);
+//		ArrayList<String> updated = new ArrayList<String>();
+//		//		for (PluginPreferencesManager pm : pluginsPreferencesPerProject.values()) {
+//		TreeMap<String, TreeSet<File>> index = getUsedKeysFilesIndex();
+//
+//		for (String oldKey : keys) {
+//			if (index.containsKey(oldKey)) {
+//				TreeSet<File> files = index.get(oldKey);
+//				if (files.size() > 0) {
+//					Pattern p = Pattern.compile(oldKey+"([^_0-9a-zA-Z$])");
+//					System.out.println("Replace KEY="+p+" BY KEY="+modifications.get(oldKey));
+//					System.out.println("Files: "+files);
+//					for (File srcFile : files) {
+//						//FIXME AAAAA remplace "AAAAA" et "AAAAA1"
+//						IOUtils.replaceAll(srcFile, p, modifications.get(oldKey)+"$1");
+//					}
+//					updated.add(oldKey);
+//				}
+//			}
+//		}
+		//		}
+	}
+
+	/**
+	 * @return the Project directory associated with their PluginPreferences
+	 */
+	public LinkedHashMap<File, PluginPreferencesManager> getPluginPreferences() {
+		return pluginsPreferencesPerProject;
+	}
+
+	public File getWorkspaceLocation() {
+		return workspaceLocation;
+	}
+
+	/**
+	 *  dedicated to get a manager that use the specified key in the project source files for example to move an unused message to another plugin (move dedicated string from core/rcp to dedicated plugin)
+	 * @param key local key (without the 'XXXPreferences.' part)
+	 * @return the PluginPreferences that uses the key in source files
+	 */
+	public ArrayList<PluginPreferencesManager> getPluginPreferencesManagersUsingKey(String key)	{
+		ArrayList<PluginPreferencesManager> pms = new ArrayList<>();
+
+		for (PluginPreferencesManager pm : this.getPluginPreferences().values()) {
+			if (pm.getUsedKeysFilesIndex().containsKey(key)) {
+				pms.add(pm);
+			}
+		}
+
+		return pms;
+	}
+
+
+	/**
+	 * Creates the index of the keys used and their associated files.
+	 */
+	public void createUsedKeysFilesIndex()	{
+		this.usedKeysFilesIndex = new TreeMap<String, TreeSet<File>>();
+
+		for (File p : this.pluginsPreferencesPerProject.keySet()) {
+			PluginPreferencesManager pmManager = this.pluginsPreferencesPerProject.get(p);
+
+			TreeMap<String, TreeSet<File>> index = pmManager.getUsedKeysFilesIndex();
+
+			if(index == null) {
+				System.err.println("WorkspacePreferencesManager.createUsedKeysFilesIndex(): project " + pmManager.getProjectDirectory() + " have no used keys.");
+				continue;
+			}
+
+			for (Map.Entry<String, TreeSet<File>> entry :index.entrySet()) {
+
+				if (debug) {
+					System.out.println("WorkspacePreferencesManager.createUsedKeysFilesIndex(): key added: " + entry.getKey() + ".");
+				}
+
+				if(this.usedKeysFilesIndex.containsKey(entry.getKey()))	{
+					this.usedKeysFilesIndex.get(entry.getKey()).addAll(entry.getValue());
+				}
+				else	{
+					this.usedKeysFilesIndex.put(entry.getKey(), entry.getValue());
+				}
+			}
+		}
+	}
+
+
+	/**
+	 * 
+	 * @param args
+	 * @throws UnsupportedEncodingException
+	 * @throws FileNotFoundException
+	 * @throws IOException
+	 */
+	public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException, IOException {
+		WorkspacePreferencesManager wmm = new WorkspacePreferencesManager();
+		for (PluginPreferencesManager preferences : wmm.getPluginPreferences().values()) {
+			preferences.summary();
+		}
+		//wmm.saveKeyModificationsInSources();
+	}
+}

Property changes on: tmp/org.txm.translate.rcp/src/org/txm/rcp/translate/preferences/WorkspacePreferencesManager.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

