Index: /trunk/gli/clean.bat
===================================================================
--- /trunk/gli/clean.bat	(revision 8312)
+++ /trunk/gli/clean.bat	(revision 8313)
@@ -33,10 +33,7 @@
 if exist "gui\*.class" del "gui\*.class"
 if exist "help\*.class" del "help\*.class"
-if exist "mem\*.class" del "mem\*.class"
 if exist "metadata\*.class" del "metadata\*.class"
-if exist "msm\*.class" del "msm\*.class"
 if exist "shell\*.class" del "shell\*.class"
 if exist "util\*.class" del "util\*.class"
-if exist "valuetree\*.class" del "valuetree\*.class"
 cd ..\..\..\..
 
Index: /trunk/gli/clean.sh
===================================================================
--- /trunk/gli/clean.sh	(revision 8312)
+++ /trunk/gli/clean.sh	(revision 8313)
@@ -26,10 +26,7 @@
 rm -rf gui
 rm -rf help
-rm -rf mem
 rm -rf metadata
-rm -rf msm
 rm -rf shell
 rm -rf util
-rm -rf valuetree
 cd ../../../..
 
Index: /trunk/gli/makegli.bat
===================================================================
--- /trunk/gli/makegli.bat	(revision 8312)
+++ /trunk/gli/makegli.bat	(revision 8313)
@@ -173,11 +173,7 @@
 "%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/gui/tree/*.java
 "%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/help/*.java
-"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/mem/*.java
 "%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/metadata/*.java
-"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/msm/*.java
-"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/msm/parsers/*.java
 "%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/shell/*.java
 "%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/util/*.java
-"%JAVACPATH%\javac.exe" -d classes/ -sourcepath src/ -classpath classes/;lib/apache.jar;lib/qfslib.jar;lib/mail.jar;lib/activation.jar src/org/greenstone/gatherer/valuetree/*.java
 
 if "%GLILANG%" == "en" echo Done!
Index: /trunk/gli/makegli.sh
===================================================================
--- /trunk/gli/makegli.sh	(revision 8312)
+++ /trunk/gli/makegli.sh	(revision 8313)
@@ -164,11 +164,7 @@
 $javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/gui/tree/*.java
 $javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/help/*.java
-$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/mem/*.java
 $javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/metadata/*.java
-$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/msm/*.java
-$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/msm/parsers/*.java
 $javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/shell/*.java
 $javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/util/*.java
-$javacpath -deprecation -d classes/ -sourcepath src/ -classpath classes/:lib/apache.jar:lib/qfslib.jar:lib/mail.jar:lib/activation.jar src/org/greenstone/gatherer/valuetree/*.java
 
 if [ "$glilang" == "es" ]; then
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/Argument.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/Argument.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/Argument.java	(revision 8313)
@@ -39,5 +39,6 @@
 import org.greenstone.gatherer.collection.Collection;
 import org.greenstone.gatherer.collection.CollectionManager;
-import org.greenstone.gatherer.msm.ElementWrapper;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataTools;
 import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.Utility;
@@ -246,44 +247,14 @@
      * @see org.greenstone.gatherer.collection.CollectionManager#getCollection
      */
-    public String getValue() {
-	String value = null;
-	// Only assigned arguments have values. 
-	if(element != null) {
-	    value = XMLTools.getValue(element);
-	    // We may have to retrieve the language dependant string for a metadata element
-	    if(type == METADATUM) {
-		ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(value);
-		if(element_wrapper != null) {
-		    value = element_wrapper.getName();
-		}
-	    }
-	}
-	return value;
-    }
-
-    /** Retrieve the vector of values.
-     * @return an ArrayList of values
-     * @see org.greenstone.gatherer.Gatherer#c_man
-     * @see org.greenstone.gatherer.collection.CollectionManager#getCollection
-     */
-    public ArrayList getValues() {
-	ArrayList values = new ArrayList();
-	// Only assigned arguments have values. 
-	if(element != null) {
-	    String value = XMLTools.getValue(element);
-	    StringTokenizer tokenizer = new StringTokenizer(value, ",");
-	    while(tokenizer.hasMoreTokens()) {
-		String token = tokenizer.nextToken();
-		if(type == METADATA) {
-		    ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(token);
-		    if(element_wrapper != null) {
-			token = element_wrapper.toString();
-		    }
-		}
-		values.add(token);
-	    }
-	}
-	return values;
-    }
+    public String getValue()
+    {
+	// Only assigned arguments have values.
+	if (element == null) {
+	    return null;
+	}
+
+	return XMLTools.getValue(element);
+    }
+
 
     /** Method to determine if this argument has been assigned.
@@ -509,47 +480,53 @@
      * @see org.greenstone.gatherer.util.StaticStrings#SPEECH_CHARACTER
      */
-    public String toString() {
+    public String toString()
+    {
 	StringBuffer text = new StringBuffer("-");
-	if(element != null) {
-	    if(name == null) {
-		name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
-	    }
-	    text.append(name);
-	    String value = XMLTools.getValue(element);
-	    if(value.length() > 0) {
-		text.append(StaticStrings.SPACE_CHARACTER);
-		// If the value contains a space, add speech marks
-		if(value.indexOf(StaticStrings.SPACE_CHARACTER) != -1) {
-		    value = StaticStrings.SPEECH_CHARACTER + value + StaticStrings.SPEECH_CHARACTER;
-		}
-		// Tokenize the string
-		StringTokenizer tokenizer = new StringTokenizer(value, ",");
-		while(tokenizer.hasMoreTokens()) {
-		    String token = tokenizer.nextToken();
-		    if(type == METADATA || type == METADATUM) {
-			ElementWrapper element_wrapper = null;
-			// if you click on exit before saving and format statements have changed, this could be null
-			if (Gatherer.c_man.getCollection() != null) {
-			    element_wrapper = Gatherer.c_man.getCollection().msm.getElement(token);
-			}
-			if(element_wrapper != null) {
-			    text.append(element_wrapper.toString());
-			    element_wrapper = null;
-			}
-			else {
-			    text.append(token);
-			}
-		    }
-		    else {
-			text.append(token);
-		    }
-		    token = null;
-		    text.append(StaticStrings.COMMA_CHARACTER);
-		}
-		tokenizer = null;
-		text.deleteCharAt(text.length() - 1);
-	    }
-	    value = null;
-	}
+
+	if (element == null) {
+	    return text.toString();
+	}
+
+	if (name == null) {
+	    name = element.getAttribute(StaticStrings.NAME_ATTRIBUTE);
+	}
+	text.append(name);
+
+	String value = XMLTools.getValue(element);
+	if (value.length() == 0) {
+	    return text.toString();
+	}
+
+	text.append(StaticStrings.SPACE_CHARACTER);
+
+// 	// Handle metadata elements specially
+// 	if (type == METADATA || type == METADATUM) {
+// 	    // Tokenize the string
+// 	    StringTokenizer tokenizer = new StringTokenizer(value, ",");
+// 	    while (tokenizer.hasMoreTokens()) {
+// 		String token = tokenizer.nextToken();
+
+// 		MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName(token);
+// 		if (metadata_element != null) {
+// 		    text.append(metadata_element.getFullName());
+// 		}
+// 		else {
+// 		    text.append(token);
+// 		}
+
+// 		if (tokenizer.hasMoreTokens()) {
+// 		    text.append(StaticStrings.COMMA_CHARACTER);
+// 		}
+// 	    }
+// 	    return text.toString();
+// 	}
+
+	// If the value contains a space, add speech marks
+	//   (Except for metadata elements, which won't have spaces when written out to collect.cfg)
+	if (value.indexOf(StaticStrings.SPACE_CHARACTER) != -1 && !(type == METADATUM || type == METADATA)) {
+	    value = StaticStrings.SPEECH_CHARACTER + value + StaticStrings.SPEECH_CHARACTER;
+	}
+
+	text.append(value);
 	return text.toString();
     }   
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/ArgumentConfiguration.java	(revision 8313)
@@ -39,5 +39,6 @@
 import org.greenstone.gatherer.gui.ModalDialog;
 import org.greenstone.gatherer.gui.SimpleMenuBar;
-import org.greenstone.gatherer.msm.ElementWrapper;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
 import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.Utility;
@@ -321,4 +322,5 @@
 	    String existing_value = argument.getValue();
 	    String default_value = argument.getDefaultValue();
+
 	    switch(argument.getType()) {
 	    case Argument.ENUM:
@@ -333,5 +335,4 @@
 		Collections.sort(options_model);
 		value = new GComboBox(options_model.toArray(), false);
-		//((JComboBox)value).setEditable(false);
 		((JComboBox)value).addActionListener(new ToolTipUpdater());
 		if(existing_value != null && existing_value.length() > 0) {
@@ -345,20 +346,13 @@
 		}
 		break;
+
 	    case Argument.FLAG:
 		// Only need the check box.
 		break;
+
 	    case Argument.HIERARCHY:
-		value = new GComboBox(Gatherer.c_man.getCollection().msm.getAssignedElements(true), false);
-		/** @TODO - figure out a smarter way of allowing Greenstone extracted metadata to be selected. */
-		//((JComboBox)value).setEditable(false);
-		((JComboBox)value).addItemListener(new HierarchyListener());
-		// Now ensure we have the existing value or default value selected if either exist.
-		if(existing_value != null && existing_value.length() > 0) {
-		    selectValue((JComboBox)value, existing_value);
-		}
-		else if(default_value != null) {
-		    selectValue((JComboBox)value, default_value);
-		}
+		// I don't think these are used any more...
 		break;
+
 	    case Argument.INTEGER:
 		// Build a spinner
@@ -393,39 +387,44 @@
 		value = spinner;
 		break;
+
 	    case Argument.REGEXP:
 	    case Argument.STRING:
-		// Use a standard text field
-		if(existing_value != null && existing_value.length() > 0) {
+		// If there is already a value set for this argument, use it
+		if (existing_value != null && !existing_value.equals("")) {
 		    value = new JTextField(existing_value);
-		}
-		else {
-		    if(default_value != null) {
-			value = new JTextField(default_value);
-		    }
-		    // Special test just for the hfile field.
-		    else if(argument.getName().equals("hfile")) {
-			// Work through previous controls looking for the metadata one.
-			for(int i = 0; i < central_pane.getComponentCount(); i++) {
-			    Object object = central_pane.getComponent(i);
-			    if(object instanceof ArgumentControl) {
-				ArgumentControl control = (ArgumentControl) object;
-				if(control.toString().equals("metadata")) {
-				    Object temp = control.getValue();
-				    if(temp != null) {
-					value = new JTextField(temp.toString() + ".txt");
-				    }
-				}
-
-			    }
-			}
-		    }
-		    else {
-			value = new JTextField();
-		    }
-		}
+		    break;
+		}
+
+		// Use the default value, if there is one
+		if (default_value != null && !default_value.equals("")) {
+		    value = new JTextField(default_value);
+		    break;
+		}
+
+// 		// Special test just for the hfile field.
+// 		if (argument.getName().equals("hfile")) {
+// 		    // Work through previous controls looking for the metadata one.
+// 		    for (int i = 0; i < central_pane.getComponentCount(); i++) {
+// 			Object object = central_pane.getComponent(i);
+// 			if (object instanceof ArgumentControl) {
+// 			    ArgumentControl control = (ArgumentControl) object;
+// 			    if (control.toString().equals("metadata")) {
+// 				Object temp = control.getValue();
+// 				if (temp != null) {
+// 				    value = new JTextField(temp.toString() + ".txt");
+//                                  break;
+// 				}
+// 			    }
+// 			}
+// 		    }
+// 		}
+
+		// Blank field
+		value = new JTextField();
 		break;
+
 	    case Argument.LANGUAGE:
 		value = new GComboBox(CollectionDesignManager.language_manager.getLanguageCodes().toArray(), false);
-		//((JComboBox)value).setEditable(false);
+
 		// Now ensure we have the existing value or default value selected if either exist.
 		Language selected = null;
@@ -440,7 +439,8 @@
 		}
 		break;
+
 	    case Argument.METADATUM:
 	    case Argument.METADATA:
-		value = new GComboBox(Gatherer.c_man.getCollection().msm.getAssignedElements(), false);
+		value = new GComboBox(MetadataSetManager.getEveryMetadataSetElement(), false);
 
 		// Editable for advanced modes (allows things like dc.Title,ex.Title)
@@ -450,16 +450,18 @@
 
 		// Now ensure we have the existing value or default value selected if either exist.
-		if(existing_value != null && existing_value.length() > 0) {
-		    boolean found = selectValue((JComboBox)value, existing_value);
-		    // Its possible that this is a custom value and so doesn't exist in the combobox. If so add it and then select it
-		    if(!found) {
-			((JComboBox)value).addItem(existing_value);
-			((JComboBox)value).setSelectedItem(existing_value);
-		    }
-		}
-		else if(default_value != null) {
-		    selectValue((JComboBox)value, default_value);
+		if (existing_value != null && existing_value.length() > 0) {
+		    boolean found = selectValue((JComboBox) value, existing_value);
+		    // It's possible that this is a custom value and so doesn't exist in the combobox
+		    if (!found) {
+			// If so, add it then select it
+			((JComboBox) value).addItem(existing_value);
+			((JComboBox) value).setSelectedItem(existing_value);
+		    }
+		}
+		else if (default_value != null) {
+		    selectValue((JComboBox) value, default_value);
 		}
 		break;
+
 // ---- Special interface for adding and ordering multiple metadata items ----
 // Turned off at Ian's request!
@@ -467,5 +469,5 @@
 //  		// Comma separated metadata values.
 //  		ArrayList values = argument.getValues();
-//  		value = new GComboBox(Gatherer.c_man.getCollection().msm.getAssignedElements(), false);
+//  		value = new GComboBox(MetadataSetManager.getEveryMetadataSetElement(), false);
 //  		//((JComboBox)value).setEditable(false);
 //  		DefaultListModel model = new DefaultListModel();
@@ -680,8 +682,7 @@
 		case Argument.METADATUM:
 		case Argument.METADATA:
-		    Object new_value_raw = ((JComboBox)value).getSelectedItem();
-		    if(new_value_raw instanceof ElementWrapper) {
-			// Element wrappers are guaranteed to be non-zero length
-			argument.setValue(((ElementWrapper)new_value_raw).getName());
+		    Object new_value_raw = ((JComboBox) value).getSelectedItem();
+		    if (new_value_raw instanceof MetadataElement) {
+			argument.setValue(((MetadataElement) new_value_raw).getFullName());
 		    }
 		    else {
@@ -719,7 +720,7 @@
 //  		    return true;
 		case Argument.HIERARCHY:
-		    argument.setValue(((JComboBox)value).getSelectedItem().toString());
-		    // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
-		    argument.setAssigned(true);
+// 		    argument.setValue(((JComboBox)value).getSelectedItem().toString());
+// 		    // Kinda lucked out here. Its impossible not to choose an entry from these comboboxes as they are restricted.
+// 		    argument.setAssigned(true);
 		    return true;
 		case Argument.REGEXP:
@@ -777,5 +778,5 @@
 		    */
 		}
-		else if(object instanceof ElementWrapper) {
+		else if (object instanceof MetadataElement) {
 		    if(object.toString().equals(target)) {
 			combobox.setSelectedIndex(i);
@@ -796,33 +797,33 @@
 	    ((JTextField)value).setText(value_str);
 	}
-	/** Listener which adds entries to a list from a combobox when fired. */
-	private class AddListener
-	    implements ActionListener {
-	    /** The model behind the target list. */
-	    private DefaultListModel model = null;
-      	    /** The source for data to be added to the list. */
-	    private JComboBox source = null;
-	    /** The list to add data to. */
-	    private JList target = null;
-	    /** Constructor.
-	     * @param source A <strong>JComboBox</strong> which serves as the source for data.
-	     * @param target A <strong>JList</strong> which serves as the target for data.
-	     */
-	    public AddListener(JComboBox source, JList target) {
-		this.model = (DefaultListModel) target.getModel();
-		this.source = source;
-		this.target = target;
-	    }
-	    /** When the add button is clicked, we attempt to add the selected metadata from the source into the target.
-	     * @param event An <strong>ActionEvent</strong> containing information about the event.
-	     */
-	    public void actionPerformed(ActionEvent event) {
-		ElementWrapper element = (ElementWrapper) source.getSelectedItem();
-		String name = element.toString();
-		if (!model.contains(name)) {
-		    model.addElement(name);
-		}
-	    }
-	}
+// 	/** Listener which adds entries to a list from a combobox when fired. */
+// 	private class AddListener
+// 	    implements ActionListener {
+// 	    /** The model behind the target list. */
+// 	    private DefaultListModel model = null;
+//       	    /** The source for data to be added to the list. */
+// 	    private JComboBox source = null;
+// 	    /** The list to add data to. */
+// 	    private JList target = null;
+// 	    /** Constructor.
+// 	     * @param source A <strong>JComboBox</strong> which serves as the source for data.
+// 	     * @param target A <strong>JList</strong> which serves as the target for data.
+// 	     */
+// 	    public AddListener(JComboBox source, JList target) {
+// 		this.model = (DefaultListModel) target.getModel();
+// 		this.source = source;
+// 		this.target = target;
+// 	    }
+// 	    /** When the add button is clicked, we attempt to add the selected metadata from the source into the target.
+// 	     * @param event An <strong>ActionEvent</strong> containing information about the event.
+// 	     */
+// 	    public void actionPerformed(ActionEvent event) {
+// 		ElementWrapper element = (ElementWrapper) source.getSelectedItem();
+// 		String name = element.toString();
+// 		if (!model.contains(name)) {
+// 		    model.addElement(name);
+// 		}
+// 	    }
+// 	}
 	/** Listens for actions apon the enable checkbox, and if detected enables or diables control appropriately. */
 	private class EnabledListener
@@ -896,27 +897,27 @@
 	}
 	/** If a metadata element is selected that requires an hfile, then this listener defaults that hfile. */
-	private class HierarchyListener
-	    implements ItemListener {
-	    /** Any implementation of ItemListener must include this method so that we can be informed when an item from the list is selected, and generate a predetermined hfile for that selection.
-	     * @param event An <strong>ItemEvent</strong> containing information about the selection.
-	     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl
-	     */
-	    public void itemStateChanged(ItemEvent event) {
-		// Determine if the selected element represents a hierarchy.
-		Object temp = ((JComboBox)value).getSelectedItem();
-		String filename = temp.toString();
-		// Search for a argument control called hfile and enable and set value.
-		for(int i = 0; i < central_pane.getComponentCount(); i++) {
-		    Object object = central_pane.getComponent(i);
-		    if(object instanceof ArgumentControl) {
-			ArgumentControl control = (ArgumentControl) object;
-			if(control.toString().equals("hfile")) {
-			    control.setValue(filename + ".txt");
-			    control.setEnabled(true);
-			}
-		    }
-		}
-	    }
-	}
+// 	private class HierarchyListener
+// 	    implements ItemListener {
+// 	    /** Any implementation of ItemListener must include this method so that we can be informed when an item from the list is selected, and generate a predetermined hfile for that selection.
+// 	     * @param event An <strong>ItemEvent</strong> containing information about the selection.
+// 	     * @see org.greenstone.gatherer.cdm.ArgumentConfiguration.ArgumentControl
+// 	     */
+// 	    public void itemStateChanged(ItemEvent event) {
+// 		// Determine if the selected element represents a hierarchy.
+// 		Object temp = ((JComboBox)value).getSelectedItem();
+// 		String filename = temp.toString();
+// 		// Search for a argument control called hfile and enable and set value.
+// 		for(int i = 0; i < central_pane.getComponentCount(); i++) {
+// 		    Object object = central_pane.getComponent(i);
+// 		    if(object instanceof ArgumentControl) {
+// 			ArgumentControl control = (ArgumentControl) object;
+// 			if(control.toString().equals("hfile")) {
+// 			    control.setValue(filename + ".txt");
+// 			    control.setEnabled(true);
+// 			}
+// 		    }
+// 		}
+// 	    }
+// 	}
 	/** A ListOption is a compound item which is constructed from several Strings. That magic part is that the length of screen real-estate used by the text version of this item is limited. */
 	private class ListOption
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/CollectionConfiguration.java	(revision 8313)
@@ -36,4 +36,6 @@
 import org.greenstone.gatherer.Gatherer;
 import org.greenstone.gatherer.gui.GLIButton;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataTools;
 import org.greenstone.gatherer.util.DOMTree;
 import org.greenstone.gatherer.util.Codec;
@@ -538,17 +540,22 @@
 
 		// Remove the extracted metadata namespaces if required
-		if (!show_extracted_namespace && value_str.length() > 0) {
+		if (value_str.length() > 0) {
 		    StringTokenizer string_tokenizer = new StringTokenizer(value_str, ",");
 		    value_str = "";
 		    while (string_tokenizer.hasMoreElements()) {
 			String token = (String) string_tokenizer.nextElement();
+			MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName(token);
+			if (metadata_element != null) {
+			    token = metadata_element.getFullName();
+			}
+
 			if (token.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
 			    token = token.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
 			}
 
-			if (!value_str.equals("")) {
+			value_str = value_str + token;
+			if (string_tokenizer.hasMoreElements()) {
 			    value_str = value_str + ",";
 			}
-			value_str = value_str + token;
 		    }
 		}
@@ -1138,6 +1145,13 @@
 			while (string_tokenizer.hasMoreElements()) {
 			    String token = (String) string_tokenizer.nextElement();
+
 			    if (token.indexOf(StaticStrings.NS_SEP) == -1) {
 				token = StaticStrings.EXTRACTED_NAMESPACE + token;
+			    }
+			    else {
+				MetadataElement metadata_element = MetadataTools.getMetadataElementWithName(token);
+				if (metadata_element != null) {
+				    token = metadata_element.getDisplayName();
+				}
 			    }
 
@@ -1472,5 +1486,5 @@
 			}
 			if(name.equals(METADATA_ARGUMENT)) {
-				// The metadata argument must be the fully qualified name of a metadata element, so if it doesn't yet have a namespace, append the extracted metadata namespace.
+			    // The metadata argument must be the fully qualified name of a metadata element, so if it doesn't yet have a namespace, append the extracted metadata namespace.
 			    if(value.indexOf(StaticStrings.NS_SEP) == -1) {
 				value = StaticStrings.EXTRACTED_NAMESPACE + value;
Index: unk/gli/src/org/greenstone/gatherer/cdm/ElementWrapper.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/ElementWrapper.java	(revision 8312)
+++ 	(revision )
@@ -1,49 +1,0 @@
-package org.greenstone.gatherer.cdm;
-
-import org.greenstone.gatherer.msm.MSMUtils;
-import org.w3c.dom.*;
-/** For even more confusion this class provides a convience wrapper around an element, to allow it to appear in the <strong>JList</strong> with both name and description. However this class has nothing to do with its namesake.
- */
-public class ElementWrapper
-    implements Comparable {
-    /** The element as the data from this object. */
-    private Element element = null;
-    /** Constructor.
-     * @param node the Node this object is wrapped around
-     */
-    public ElementWrapper(Node node) {
-	this.element = (Element) node;
-    }
-    /** Compare two objects for ordering.
-     * @param object The other <strong>Object</strong> to compare to.
-     * @return An <i>int</i> indicating the ordering as is String.compareTo
-     */
-    public int compareTo(Object object) {
-	if(object == null) {
-	    return 1;
-	}
-	return toString().compareTo(object.toString());
-    }
-    /** Compare two objects for equality.
-     * @param object The <strong>Object</strong> to compare to.
-     * @return <i>true</i> if the objects are equal, <i>false</i> otherwise.
-     */
-    public boolean equals(Object object) {
-	if(compareTo(object) == 0) {
-	    return true;
-	}
-	return false;
-    }
-    /** Retrieve the name of the element.
-     * @return The fully qualified name as a <strong>String</strong>.
-     */
-    public String name() {
-	return MSMUtils.getFullName(element);
-    }
-    /** Retrieve a textual representation of this object.
-     * @return A <strong>String</strong>.
-     */
-    public String toString() {
-	return MSMUtils.getIdentifier(element) + ": " + MSMUtils.getDescription(element);
-    }
-}
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/FormatManager.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/FormatManager.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/FormatManager.java	(revision 8313)
@@ -27,9 +27,5 @@
 package org.greenstone.gatherer.cdm;
 
-/**************************************************************************************
- * Written:     06/05/02
- * Revised:     04/10/02 - Commented
- *              14/07/03 - DOM support
- **************************************************************************************/
+
 import java.awt.*;
 import java.awt.event.*;
@@ -42,5 +38,6 @@
 import org.greenstone.gatherer.Gatherer;
 import org.greenstone.gatherer.gui.GLIButton;
-import org.greenstone.gatherer.msm.ElementWrapper;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
 import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.Utility;
@@ -208,4 +205,8 @@
 	ArrayList variable_model = new ArrayList();
 	variable_model.add("[Text]");
+	ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	for (int i = 0; i < every_metadata_set_element.size(); i++) {
+	    variable_model.add("[" + ((MetadataElement) every_metadata_set_element.get(i)).getFullName() + "]");
+	}
 	variable_model.add("[link]");
 	variable_model.add("[/link]");
@@ -216,9 +217,4 @@
 	variable_model.add("[parent(Top):_]");
 	variable_model.add("[parent(All'_'):_]");
-	Vector elements = Gatherer.c_man.getCollection().msm.getAssignedElements();
-	for(int i = 0; i < elements.size(); i++) {
-	    variable_model.add("[" + ((ElementWrapper)elements.get(i)).getName() + "]");
-	}
-	Collections.sort(variable_model);
 	return variable_model;
     }
@@ -236,5 +232,4 @@
 	private HashMap default_mappings;
 	private JButton add_button;
-	//private JButton default_button;
 	private JButton insert_button;
 	private JButton remove_button;
@@ -311,9 +306,4 @@
 	    Dictionary.registerText(editor_label, "CDM.FormatManager.Editor");
 
-	    //default_button = new GLIButton();
-	    //default_button.setEnabled(false);
-	    //default_button.setMnemonic(KeyEvent.VK_D);
-	    //Dictionary.registerBoth(default_button, "CDM.FormatManager.Default_Format", "CDM.FormatManager.Default_Format_Tooltip");
-	    
 	    editor_textarea = new JTextArea();
 	    editor_textarea.setBackground(Configuration.getColor("coloring.editable_background", false));
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/Index.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/Index.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/Index.java	(revision 8313)
@@ -30,5 +30,8 @@
 import org.greenstone.gatherer.DebugStream;
 import org.greenstone.gatherer.Gatherer;
-import org.greenstone.gatherer.msm.ElementWrapper;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
 import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.Utility;
@@ -73,10 +76,10 @@
 	    Element content_element = document.createElement(CollectionConfiguration.CONTENT_ELEMENT);
 	    Object source_object = sources.get(i);
-	    if(source_object instanceof ElementWrapper) {
-		///DebugStream.println("Found ElementWrapper as source: " + ((ElementWrapper)source_object).getName());
-		content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, ((ElementWrapper)source_object).getName());
+	    if (source_object instanceof MetadataElement) {
+		// System.err.println("Constructing new Index with MetadataElement source...");
+		content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, ((MetadataElement) source_object).getFullName());
 	    }
 	    else {
-		///DebugStream.println("Found String as source: " + source_object.toString());
+		// System.err.println("Constructing new Index with String source...");
 		content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, source_object.toString());
 	    }
@@ -166,7 +169,6 @@
 	    for(int i = 0; i < sources_size; i++) {
 		Object source_object = sources.get(i);
-		// If its an element wrapper use the unique name rather than the 
-		if(source_object instanceof ElementWrapper) {
-		    String full_element_name = ((ElementWrapper)source_object).getName();
+		if (source_object instanceof MetadataElement) {
+		    String full_element_name = ((MetadataElement)source_object).getFullName();
 		    if(full_element_name.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
 		       id_buffer.append(full_element_name.substring(StaticStrings.EXTRACTED_NAMESPACE.length()));
@@ -206,11 +208,11 @@
 	    for(int i = 0; i < content_elements_length; i++) {
 		Element content_element = (Element) content_elements.item(i);
-		String source_str = (String) content_element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
-		ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(source_str);
-		if(element_wrapper != null) {
-		    sources.add(element_wrapper);
+		String metadata_element_name_full = (String) content_element.getAttribute(CollectionConfiguration.NAME_ATTRIBUTE);
+		MetadataElement metadata_element = MetadataTools.getMetadataElementWithDisplayName(metadata_element_name_full);
+		if (metadata_element != null) {
+		    sources.add(metadata_element);
 		}
 		else {
-		    sources.add(source_str);
+		    sources.add(metadata_element_name_full);
 		}
 	    }
@@ -267,7 +269,6 @@
 		Element content_element = element.getOwnerDocument().createElement(CollectionConfiguration.CONTENT_ELEMENT);
 		Object source_object = sources.get(i);
-		if(source_object instanceof ElementWrapper) {
-		    //DebugStream.println("Found ElementWrapper as source: " + ((ElementWrapper)source_object).getName());
-		    String name = ((ElementWrapper)source_object).getName();
+		if (source_object instanceof MetadataElement) {
+		    String name = ((MetadataElement) source_object).getFullName();
 		    content_element.setAttribute(CollectionConfiguration.NAME_ATTRIBUTE, name);
 		    name = null;
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/IndexManager.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/IndexManager.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/IndexManager.java	(revision 8313)
@@ -39,5 +39,6 @@
 import org.greenstone.gatherer.gui.GComboBox;
 import org.greenstone.gatherer.gui.GLIButton;
-import org.greenstone.gatherer.msm.ElementWrapper;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
 import org.greenstone.gatherer.util.ExclusiveListSelectionListener;
 import org.greenstone.gatherer.util.StaticStrings;
@@ -383,6 +384,6 @@
 			Object source_object = sources_list.get(j);
 			String source_str = null;
-			if(source_object instanceof ElementWrapper) {
-			    source_str = ((ElementWrapper)source_object).getName();
+			if(source_object instanceof MetadataElement) {
+			    source_str = ((MetadataElement) source_object).getFullName();
 			}
 			else {
@@ -519,6 +520,5 @@
 	    ArrayList new_data = new ArrayList();
 	    new_data.add(CollectionConfiguration.TEXT_STR);
-	    new_data.addAll(Gatherer.c_man.getCollection().msm.getAssignedElements());
-
+	    new_data.addAll(MetadataSetManager.getEveryMetadataSetElement());
 	    // Creation
 	    JPanel mgindexes_panel = new JPanel();
@@ -688,5 +688,5 @@
 		ArrayList new_data = new ArrayList();
 		new_data.add(CollectionConfiguration.TEXT_STR);
-		new_data.addAll(Gatherer.c_man.getCollection().msm.getAssignedElements());
+		new_data.addAll(MetadataSetManager.getEveryMetadataSetElement());
 		// reset the model in the list and combobox
 		source_list.setListData(new_data.toArray());
@@ -772,5 +772,10 @@
 	     * @param event A <strong>ListSelectionEvent</strong> containing further information about the list selection.
 	     */
-	    public void valueChanged(ListSelectionEvent event) {
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		if (event.getValueIsAdjusting()) {
+		    return;
+		}
+
 		Object value = index_list.getSelectedValue();
 		move_down_button.setEnabled(value != null);
@@ -1200,10 +1205,8 @@
 	    index_combobox.addItem(CollectionConfiguration.METADATA_STR);
 	    index_combobox.addItem(CollectionConfiguration.TEXT_STR);
-	    java.util.List assigned_elements = Gatherer.c_man.getCollection().msm.getAssignedElements();
-	    int assigned_elements_size = assigned_elements.size();
-	    for(int i = 0; i < assigned_elements_size; i++) {
-		index_combobox.addItem(assigned_elements.get(i));
-	    }
-	    assigned_elements = null;
+	    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	    for(int i = 0; i < every_metadata_set_element.size(); i++) {
+		index_combobox.addItem(every_metadata_set_element.get(i));
+	    }
 	    // Ensure the level manager has at least documents assigned
 	    if(levels_model.getSize() == 0) {
@@ -1383,6 +1386,6 @@
 		    // Unfortunately we have to generate a valid id
 		    String id = null;
-		    if(selected_object instanceof ElementWrapper) {
-			id = ((ElementWrapper)selected_object).getName();
+		    if (selected_object instanceof MetadataElement) {
+			id = ((MetadataElement) selected_object).getFullName();
 		    }
 		    else {
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/MetadataSetView.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/MetadataSetView.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/MetadataSetView.java	(revision 8313)
@@ -29,7 +29,9 @@
 import java.awt.*;
 import java.awt.event.*;
+import java.io.File;
 import java.util.*;
 import javax.swing.*;
 import javax.swing.event.*;
+import javax.swing.filechooser.*;
 import org.greenstone.gatherer.Configuration;
 import org.greenstone.gatherer.DebugStream;
@@ -37,9 +39,12 @@
 import org.greenstone.gatherer.Gatherer;
 import org.greenstone.gatherer.gui.GLIButton;
-import org.greenstone.gatherer.mem.MetadataEditorManager;
-import org.greenstone.gatherer.msm.MetadataSet;
-import org.greenstone.gatherer.msm.MSMEvent;
-import org.greenstone.gatherer.msm.MSMListener;
-import org.w3c.dom.*;
+import org.greenstone.gatherer.gui.MetadataElementListCellRenderer;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
+import org.greenstone.gatherer.util.Utility;
+
 
 /** This class only knows how to produce a simple visual representation of the currently imported metadata sets. It is also read-only, so should be fairly straight forward.
@@ -48,6 +53,6 @@
  */
 public class MetadataSetView
-    extends DynamicListModel
-    implements MSMListener {
+    extends DynamicListModel {
+
     /** The visual contols used to review the metadata sets. */
     private Control controls = null;
@@ -55,38 +60,26 @@
     private DynamicListModel model = null;
 
-    /** Constructor.
-     */
-    public MetadataSetView() {
-	DebugStream.println("MetadataSetView: Initialized.");
+
+    public MetadataSetView()
+    {
 	model = this;
-	Gatherer.c_man.getCollection().msm.addMSMListener(this);
-	loadMetadataSets();
+
+	// Initialise the model
+	refreshModel();
+
 	// Build the controls
-	controls = new MetadataSetControl();
-    }
-
-    /** Destructor. Remove any references of this class from persistant objects.
-     * @see org.greenstone.gatherer.Gatherer
-     * @see org.greenstone.gatherer.collection.CollectionManager
-     */
-    public void destroy() {
+	controls = new MetadataSetViewControls();
+    }
+
+
+    public void destroy()
+    {
 	controls.destroy();
 	controls = null;
-	Gatherer.c_man.msm.removeMSMListener(this);
 	model = null;
     }
 
-    /** Called when an element is changed within a set in the MSM, prompting us to refresh our list of elements being shown.
-     * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
-     * @see org.greenstone.gatherer.cdm.MetadataSetView.MetadataSetControl
-     */
-    public void elementChanged(MSMEvent event) {
-	// Get the controls to refresh element list.
-	((MetadataSetControl)controls).refreshElementList();
-    }
 
     /** A method for retrieve the controls for this manager.
-     * @see org.greenstone.gatherer.Dictionary
-     * @see org.greenstone.gatherer.gui.Coloring
      */
     public Control getControls() {
@@ -94,64 +87,43 @@
     }
 
-    /** Called when a metadata value has undergone significant change.
-     * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
-     */
-    public void metadataChanged(MSMEvent event) {
-	// Couldn't care less.
-    }
-
-    /** Called when a set is added or removed from the MSM.
-     * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
-     */
-    public void setChanged(MSMEvent event) {
-	// Reload model.
-	clear();
-	loadMetadataSets();
-    }
-
-
-    /** Prints out the contents of this manager, as they would appear in the collection configuration file.
-     * @return A <strong>String</strong> containing a block of commands.
-     * @see org.greenstone.gatherer.cdm.MetadataSetView.SetWrapper
-     */
-    public String toString() {
-	String text = "";
-	for(int i = 0; i < size(); i++) {
-	    SetWrapper set = (SetWrapper)get(i);
-	    text = text + set.toString() + "\n";
-	}
-	text = text + "\n";
-	return text;
-    }
-
-    /** Called when a significant change has occured to a value tree for a certain element, however we take no further action.
-     * @param event A <strong>MSMEvent</strong> containing information relevant to the event.
-     */
-    public void valueChanged(MSMEvent event) {
-    }
-
-    /** Retrieves the current list of loaded metadata sets, and builds a list model around them.
-     * @see org.greenstone.gatherer.Gatherer
-     * @see org.greenstone.gatherer.cdm.MetadataSetView.SetWrapper
-     * @see org.greenstone.gatherer.collection.CollectionManager
-     */
-    private void loadMetadataSets() {
-	// We initialize the set_model with wrapped metadata sets. Note that when we call getSets() we also end up adding ourselves as a listener to the metadata set manager.
-	Vector sets = Gatherer.c_man.getCollection().msm.getSets();
-	for(int i = 0; i < sets.size(); i++) {
-	    addElement(new SetWrapper((MetadataSet)sets.get(i)));
-	}
-    }
+
+    public void refreshModel()
+    {
+	// Remove any metadata sets from the model that are no longer loaded
+	ArrayList loaded_metadata_sets = MetadataSetManager.getMetadataSets();
+	for (int i = size() - 1; i >= 0; i--) {
+	    MetadataSet metadata_set = (MetadataSet) get(i);
+	    if (loaded_metadata_sets.contains(metadata_set) == false) {
+		// System.err.println("Metadata set in list no longer loaded...removing.");
+		remove(i);
+	    }
+	}
+
+	// Add any metadata sets that are loaded but not in the model
+	for (int i = 0; i < loaded_metadata_sets.size(); i++) {
+	    MetadataSet loaded_metadata_set = (MetadataSet) loaded_metadata_sets.get(i);
+	    boolean in_model = false;
+	    for (int j = 0; j < size(); j++) {
+		MetadataSet metadata_set = (MetadataSet) get(j);
+		if (metadata_set.equals(loaded_metadata_set)) {
+		    in_model = true;
+		    break;
+		}
+	    }
+
+	    if (in_model == false) {
+		// System.err.println("Metadata set loaded but not in list...adding.");
+		addElement(loaded_metadata_set);
+	    }
+	}
+    }
+
 
     /** This class creates and lays-out the various controls for reviewing the metadata sets, and their commands as they would appear in the collection configuration file. */
-    private class MetadataSetControl
+    private class MetadataSetViewControls
 	extends JPanel
 	implements Control {
-	/** Listens for clicks upon the configure button, or double clicks from the metadata set list. */
-	private ConfigureActionListener configure_action_listener;
 	/** Opens the MEM and systematically performs as if the add set button were clicked. */
 	private JButton add_button;
-	/** Opens the MEM with the appropriate set open for editing. */
-	private JButton configure_button;
 	/** Opens the MEM and systematically performs as if the remove set button were clicked. */
 	private JButton remove_button;
@@ -179,10 +151,6 @@
 	private JTextArea instructions = null;
 
-	private ListListener list_listener;
-
-	private MultilingualListCellRenderer element_list_cell_renderer;
-
-	/** The element model for the currently selected set. */
-	private Vector element_model = null;
+	private MetadataElementListCellRenderer element_list_cell_renderer;
+	private MetadataSetListSelectionListener list_listener;
 
 	/* Constructor.
@@ -191,5 +159,6 @@
 	 * @see org.greenstone.gatherer.cdm.MetadataSetView.ListListener
 	 */
-	public MetadataSetControl() {
+	public MetadataSetViewControls()
+	{
 	    // Create visual components
 	    central_pane = new JPanel();
@@ -198,8 +167,8 @@
 	    element_label.setOpaque(true);
 	    Dictionary.registerText(element_label, "CDM.MetadataSetManager.Elements");
+	    element_list = new JList();
 	    element_list_scroll_pane = new JScrollPane();
-	    element_list_cell_renderer = new MultilingualListCellRenderer(element_list_scroll_pane);
-	    element_list = new JList();
 	    element_list_scroll_pane.setViewportView(element_list);
+	    element_list_cell_renderer = new MetadataElementListCellRenderer();
 	    element_list.setCellRenderer(element_list_cell_renderer);
 	    element_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -218,8 +187,6 @@
 	    Dictionary.registerText(set_label, "CDM.MetadataSetManager.Sets");
 	    set_list = new JList(model);
+	    set_list.setCellRenderer(new MetadataSetListCellRenderer());
 	    set_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-	    if(model.size() > 0) {
-		set_list.setSelectedIndex(0);
-	    }
 
 	    set_pane = new JPanel();
@@ -234,21 +201,14 @@
 	    add_button.setMnemonic(KeyEvent.VK_A);
 	    Dictionary.registerBoth(add_button, "CDM.MetadataSetManager.Add", "CDM.MetadataSetManager.Add_Tooltip");
-	    configure_button = new GLIButton();
-	    configure_button.setEnabled(false);
-	    configure_button.setMnemonic(KeyEvent.VK_C);
-	    Dictionary.registerBoth(configure_button, "CDM.MetadataSetManager.Configure", "CDM.MetadataSetManager.Configure_Tooltip");
 	    remove_button = new GLIButton();
 	    remove_button.setEnabled(false);
 	    remove_button.setMnemonic(KeyEvent.VK_R);
 	    Dictionary.registerBoth(remove_button, "CDM.MetadataSetManager.Remove", "CDM.MetadataSetManager.Remove_Tooltip");
-	    configure_action_listener = new ConfigureActionListener();
-	    list_listener = new ListListener();
+	    list_listener = new MetadataSetListSelectionListener();
 
 	    // Add listeners
 	    add_button.addActionListener(new AddButtonListener());
-	    configure_button.addActionListener(configure_action_listener);
 	    remove_button.addActionListener(new RemoveButtonListener());
 	    set_list.addListSelectionListener(list_listener);
-	    set_list.addMouseListener(configure_action_listener);
 	    // Layout
 	    instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
@@ -273,5 +233,4 @@
 	    button_pane.setLayout(new GridLayout(1,3,0,0));
 	    button_pane.add(add_button);
-	    button_pane.add(configure_button);
 	    button_pane.add(remove_button);
 
@@ -282,20 +241,18 @@
 	    add(button_pane, BorderLayout.SOUTH);
 	}
-	/** Destructor. */
-	public void destroy() {
-	}
-	/** Update the element list. */
-	public void refreshElementList() {
-	    element_list.updateUI();
-	}
-
-	/** Overriden to ensure the instruction area is scrolled to top.
-	 */
-	public void gainFocus() {
-	    if(instructions != null) {
+
+
+	public void destroy() { }
+
+
+	public void gainFocus()
+	{
+	    // Ensure the instructions area is scrolled to the top
+	    if (instructions != null) {
 		instructions.setCaretPosition(0);
 	    }
+
 	    // If no current selection, select first available set
-	    if(set_list.isSelectionEmpty() && set_list.getModel().getSize() > 0) {
+	    if (set_list.isSelectionEmpty() && set_list.getModel().getSize() > 0) {
 		set_list.setSelectedIndex(0);
 		list_listener.valueChanged(new ListSelectionEvent(set_list, 0, 0, true));
@@ -303,185 +260,98 @@
 	}
 
-	public void loseFocus() {
-	}
-
-	/** Listens for clicks on the add button, and actions them accordingly by opening the MEM and clicking add set. */
+
+	public void loseFocus() { }
+
+
+	/** Listens for clicks on the add button. */
 	private class AddButtonListener
 	    implements ActionListener {
+
 	    /** Called when the add button is clicked.
 	     * @param event an ActionEvent containing information about the mouse click
-	     * @see org.greenstone.gatherer.Gatherer
-	     * @see org.greenstone.gatherer.collection.Collection
-	     * @see org.greenstone.gatherer.collection.CollectionManager
-	     * @see org.greenstone.gatherer.mem.MetadataEditorManager
 	     */
-	    public void actionPerformed(ActionEvent event) {
-		Gatherer.c_man.getCollection().msm.editMDS(null, MetadataEditorManager.ADD_SET);
-	    }
-	}
-
-	/** Listens for clicks on the configure button or double clicks upon the metadata set list and chains to the MEM as appropriate. */
-	private class ConfigureActionListener
-	    extends MouseAdapter 
+	    public void actionPerformed(ActionEvent event)
+	    {
+		JFileChooser chooser = new JFileChooser(new File(Utility.METADATA_DIR));
+		chooser.setFileFilter(new MetadataSet.MetadataSetFileFilter());
+		int return_val = chooser.showDialog(Gatherer.g_man, Dictionary.get("MSMPrompt.File_Import"));
+		if (return_val == JFileChooser.APPROVE_OPTION) {
+		    Gatherer.c_man.importMetadataSet(new MetadataSet(chooser.getSelectedFile()));
+		    refreshModel();
+
+		    // The metadata.xml files may possibly contain metadata for this newly added metadata set
+		    // Re-read all the metadata.xml files to account for this case
+		    MetadataXMLFileManager.clearMetadataXMLFiles();
+		    MetadataXMLFileManager.loadMetadataXMLFiles(new File(Gatherer.c_man.getCollectionImport()));
+		}
+	    }
+	}
+
+
+	private class MetadataSetListCellRenderer
+	    implements ListCellRenderer
+	{
+	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
+	    {
+		DefaultListCellRenderer default_list_cell_renderer = new DefaultListCellRenderer();
+		JLabel list_cell_label = (JLabel) default_list_cell_renderer.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+
+		if (value instanceof MetadataSet) {
+		    MetadataSet metadata_set = (MetadataSet) value;
+		    String metadata_set_name = MetadataTools.getMetadataSetAttribute(metadata_set, "Name", Configuration.getLanguage(), "en");
+		    list_cell_label.setText("metadataset " + metadata_set.getNamespace() + " \"" + metadata_set_name + "\"");
+		}
+
+		return list_cell_label;
+	    }
+	}
+
+
+	private class MetadataSetListSelectionListener
+	    implements ListSelectionListener {
+
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		// Wait until we get a stable event
+		if (event.getValueIsAdjusting()) {
+		    return;
+		}
+
+		// Now we can process it
+		if (!set_list.isSelectionEmpty()) {
+		    MetadataSet metadata_set = (MetadataSet) set_list.getSelectedValue();
+		    element_list.setListData(new Vector(metadata_set.getMetadataSetElements()));
+  		    remove_button.setEnabled(true);
+
+  		    // Finally check the directionality and scroll as necessary
+  		    JScrollBar scroll_bar = element_list_scroll_pane.getHorizontalScrollBar();
+  		    if (element_list_cell_renderer.getDirectionality() == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
+			scroll_bar.setValue(scroll_bar.getMaximum());
+  		    }
+  		    else {
+			scroll_bar.setValue(scroll_bar.getMinimum());
+		    }
+		}
+		else {
+		    remove_button.setEnabled(false);
+		}
+	    }
+	}
+
+
+	/** Listens for clicks on the remove button. */
+	private class RemoveButtonListener
 	    implements ActionListener {
-	    /** Called when the configure button is clicked.
+
+	    /** Called when the remove button is clicked.
 	     * @param event an ActionEvent containing information about the mouse click
 	     */
-	    public void actionPerformed(ActionEvent event) {
-		configureSet();
-	    }
-
-	    /** Called whenever the mouse is clicked over a registered component, we use this to chain through to the configure prompt.
-	     * @param event a MouseEvent containing information about the mouse click
-	    */
-	    public void mouseClicked(MouseEvent event) {
-		if(event.getClickCount() == 2 ) {
-		    configureSet();
-		}
-	    }
-	    /** If some set is selected, then open the metadata set manager with the current set selected and expanded 
-	     * @see org.greenstone.gatherer.Gatherer
-	     * @see org.greenstone.gatherer.collection.Collection
-	     * @see org.greenstone.gatherer.collection.CollectionManager
-	     * @see org.greenstone.gatherer.cdm.MetadataSetView.SetWrapper
-	     * @see org.greenstone.gatherer.mem.MetadataEditorManager
-	     */
-	    private void configureSet() {
-		if(!set_list.isSelectionEmpty()) {
-		    MetadataSet set = ((SetWrapper)set_list.getSelectedValue()).getSet();
-		    Gatherer.c_man.getCollection().msm.editMDS(set, MetadataEditorManager.NORMAL);
-		}
-		else {
-		    configure_button.setEnabled(false);
-		}
-	    }
-	}
-
-	private class ListListener
-	    implements ListSelectionListener {
-	    public void valueChanged(ListSelectionEvent event) {
-		// Wait until we get a stable event
-		if(event.getValueIsAdjusting()) {
-		    return;
-		}
-		// Now we can process it
-		if(!set_list.isSelectionEmpty()) {
-		    MetadataSet set = ((SetWrapper)set_list.getSelectedValue()).getSet();
-		    NodeList elements = set.getElements();
-		    element_model = new Vector();
-		    for(int i = 0; i < elements.getLength(); i++) {
-			element_model.add(new ElementWrapper(elements.item(i)));
-		    }
-		    //Collections.sort(element_model);
-		    element_list.setListData(element_model);
-		    configure_button.setEnabled(true);
-		    remove_button.setEnabled(true);
-
-		    // Finally check the directionality and scroll as necessary
-		    JScrollBar scroll_bar = element_list_scroll_pane.getHorizontalScrollBar();
-		    if(element_list_cell_renderer.getDirectionality() == Character.DIRECTIONALITY_RIGHT_TO_LEFT) {
-			scroll_bar.setValue(scroll_bar.getMaximum());
-		    }
-		    else {
-			scroll_bar.setValue(scroll_bar.getMinimum());
-		    }
-
-		}
-		else {
-		    configure_button.setEnabled(false);
-		    remove_button.setEnabled(false);
-		}
-	    }
-	}
-
-	/** Listens for clicks on the remove button, and actions them accordingly by opening the MEM and clicking remove set. */
-	private class RemoveButtonListener
-	    implements ActionListener {
-	    /** Called when the remove button is clicked.
-	     * @param event an ActionEvent containing information about the mouse click
-	     * @see org.greenstone.gatherer.Gatherer
-	     * @see org.greenstone.gatherer.collection.Collection
-	     * @see org.greenstone.gatherer.collection.CollectionManager
-	     * @see org.greenstone.gatherer.cdm.MetadataSetView.SetWrapper
-	     * @see org.greenstone.gatherer.mem.MetadataEditorManager
-	     */
-	    public void actionPerformed(ActionEvent event) {
-		if(!set_list.isSelectionEmpty()) {
-		    MetadataSet set = ((SetWrapper)set_list.getSelectedValue()).getSet();
-		    Gatherer.c_man.getCollection().msm.editMDS(set, MetadataEditorManager.REMOVE_SET);
-		}
-		else {
-		    remove_button.setEnabled(false);
-		}
-	    }
-	}
-
-	private class MultilingualListCellRenderer
-	    extends DefaultListCellRenderer {
-	    private byte previous_directionality = Character.DIRECTIONALITY_UNDEFINED;
-	    private JScrollPane scroll_pane;
-	    public MultilingualListCellRenderer(JScrollPane scroll_pane) {
-		super();
-		this.scroll_pane = scroll_pane;
-	    }
-
-	    public byte getDirectionality() {
-		if(previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT || previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC || previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING || previous_directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE) {
-		    return Character.DIRECTIONALITY_RIGHT_TO_LEFT;
-		}
-		else {
-		    return Character.DIRECTIONALITY_LEFT_TO_RIGHT;
-		}
-	    }
-	    
-	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-		JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-		// Determine if the text should be left aligned or right aligned
-		String text = value.toString();
-		int text_index = 0;
-		byte directionality = Character.DIRECTIONALITY_UNDEFINED;
-		while(directionality == Character.DIRECTIONALITY_UNDEFINED && text_index < text.length()) {
-		    directionality = Character.getDirectionality(text.charAt(text_index));
-		    text_index++;
-		}
-		if(directionality != previous_directionality) {
-		    previous_directionality = directionality;
-		    if(directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT || directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC || directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING || directionality == Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE) {
-			///ystem.err.println("R2L for: " + text);
-			component.setHorizontalAlignment(JLabel.TRAILING);
-			component.setHorizontalTextPosition(JLabel.TRAILING);
-			component.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
-			//scroll_pane.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
-		    }
-		    else {
-			component.setHorizontalAlignment(JLabel.LEADING);
-			component.setHorizontalTextPosition(JLabel.LEADING);
-			///ystem.err.println("L2R for: " + text);
-			component.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
-			//scroll_pane.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
-		    }
-		}
-
-		text = null;
-		return component;
-	    }
-
-	}
-	
-    }
-
-    /** Provides a convience wrapper around a metadata set, that allows it to appear in the <strong>JList</strong> the same way it would in the collection configuration file. */
-    private class SetWrapper {
-	private MetadataSet set = null;
-	public SetWrapper(MetadataSet set) {
-	    this.set = set;
-	}
-	public MetadataSet getSet() {
-	    return set;
-	}
-	public String toString() {
-	    String namespace = set.getNamespace();
-	    // Watch out for the greenstone set, with its namespace of ""
-	    return "metadataset " + namespace + " \"" + set.getName() + "\"";
+	    public void actionPerformed(ActionEvent event)
+	    {
+		MetadataSet metadata_set = (MetadataSet) set_list.getSelectedValue();
+		Gatherer.c_man.removeMetadataSet(metadata_set);
+		refreshModel();
+		element_list.setListData(new Vector());
+	    }
 	}
     }
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/Subcollection.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/Subcollection.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/Subcollection.java	(revision 8313)
@@ -28,5 +28,4 @@
 
 import org.greenstone.gatherer.Gatherer;
-import org.greenstone.gatherer.msm.ElementWrapper;
 import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.Troolean;
@@ -154,15 +153,10 @@
      * @return a String which is either the fully qualified name of a metadata element, or filename
      */
-    public String getSource() {
-	if(source == null &&element != null) {
+    public String getSource()
+    {
+	if (source == null && element != null) {
 	    source = element.getAttribute(StaticStrings.CONTENT_ATTRIBUTE);
-	    // If this is a metadata element then retrieve the appropriate ElementWrapper and use the language specific name
-	    if(!source.equals(StaticStrings.FILENAME_STR)) {
-		ElementWrapper element_wrapper = Gatherer.c_man.getCollection().msm.getElement(source);
-		if(element_wrapper != null) {
-		    source = element_wrapper.toString();
-		}
-	    }
-	}
+	}
+
 	return source;
     }
Index: /trunk/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java	(revision 8313)
@@ -27,8 +27,5 @@
 package org.greenstone.gatherer.cdm;
 
-/**************************************************************************************
- * Written:      ??/??/02
- * Revised:      04/07/03 - DOM support
- **************************************************************************************/
+
 import java.awt.*;
 import java.awt.event.*;
@@ -42,5 +39,6 @@
 import org.greenstone.gatherer.gui.GLIButton;
 import org.greenstone.gatherer.gui.NonWhitespaceField;
-import org.greenstone.gatherer.msm.ElementWrapper;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
 import org.greenstone.gatherer.util.ExclusiveListSelectionListener;
 import org.greenstone.gatherer.util.StaticStrings;
@@ -245,5 +243,6 @@
 	    JLabel source_label = new JLabel();
 	    Dictionary.registerText(source_label, "CDM.SubcollectionManager.Source");
-	    Vector source_model = Gatherer.c_man.getCollection().msm.getAssignedElements();
+	    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	    Vector source_model = new Vector(every_metadata_set_element);
 	    source_model.add(0, StaticStrings.FILENAME_STR);
 	    source_combobox = new JComboBox(source_model);
@@ -364,5 +363,6 @@
 	public void gainFocus() {
 	    // Rebuild the sources combobox
-	    Vector source_model = Gatherer.c_man.getCollection().msm.getAssignedElements();
+	    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+	    Vector source_model = new Vector(every_metadata_set_element);
 	    source_model.add(0, "Filename"); // Add filename as a possible source.
 	    source_combobox.setModel(new DefaultComboBoxModel(source_model));
@@ -395,10 +395,7 @@
 		String source = null;
 		Object object = source_combobox.getSelectedItem();
-		if(object instanceof ElementWrapper) {
-		    ElementWrapper element_wrapper = (ElementWrapper)object;
-		    source = element_wrapper.getName();
-		    if(source.indexOf(StaticStrings.NS_SEP) == -1) {
-			source = StaticStrings.EXTRACTED_NAMESPACE + source;
-		    }
+		if (object instanceof MetadataElement) {
+		    MetadataElement metadata_element = (MetadataElement) object;
+		    source = metadata_element.getFullName();
 		}
 		else {
@@ -481,10 +478,7 @@
 		    String source = null;
 		    Object object = source_combobox.getSelectedItem();
-		    if(object instanceof ElementWrapper) {
-			ElementWrapper element_wrapper = (ElementWrapper)object;
-			source = element_wrapper.getName();
-			if(source.indexOf(StaticStrings.NS_SEP) == -1) {
-			    source = StaticStrings.EXTRACTED_NAMESPACE + source;
-			}
+		    if (object instanceof MetadataElement) {
+			MetadataElement metadata_element = (MetadataElement) object;
+			source = metadata_element.getFullName();
 		    }
 		    else {
@@ -508,4 +502,8 @@
 	     */
 	    public void valueChanged(ListSelectionEvent event) {
+		// Wait until the event stabilises to avoid processing it multiple times
+		if (event.getValueIsAdjusting() == true) {
+		    return;
+		}
 		// Now the entry
 		if(!subcollection_list.isSelectionEmpty()) {
@@ -520,13 +518,10 @@
 		    Object value = source_combobox.getItemAt(pos);
 		    //ystem.err.println("Search for: " + s);
-		    while(value != null) {
-			if(value instanceof ElementWrapper) {
-			    ElementWrapper e = (ElementWrapper) value;
-			    String e_name = e.getName();
-			    if(e_name.indexOf(StaticStrings.NS_SEP) == -1) {
-				e_name = StaticStrings.EXTRACTED_NAMESPACE + e_name;
-			    }
+		    while (value != null) {
+			if (value instanceof MetadataElement) {
+			    MetadataElement metadata_element = (MetadataElement) value;
+			    String metadata_element_name = metadata_element.getFullName();
 			    //ystem.err.print("Compare to: " + e_name);
-			    if(e_name.equals(s)) {
+			    if (metadata_element_name.equals(s)) {
 				source_combobox.setSelectedIndex(pos);
 				value = null;
Index: /trunk/gli/src/org/greenstone/gatherer/collection/Collection.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/collection/Collection.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/collection/Collection.java	(revision 8313)
@@ -48,6 +48,4 @@
 import org.greenstone.gatherer.cdm.CollectionMetaManager;
 import org.greenstone.gatherer.file.FileNode;
-import org.greenstone.gatherer.msm.MetadataXMLFileManager;
-import org.greenstone.gatherer.msm.MetadataSetManager;
 import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.Utility;
@@ -64,8 +62,4 @@
     /** A reference to the Collection Design Manager. */
     public CollectionDesignManager cdm;
-    /** A reference to the Greenstone Directory Metadata Manager. */
-    public MetadataXMLFileManager gdm;
-    /** A reference to the Metadata Set Manager. */
-    public MetadataSetManager msm;
     /** true if an error has occurred during construction */
     public boolean error = false;
@@ -119,6 +113,4 @@
     public void destroy() {
 	cdm.destroy();
-	gdm.destroy();
-	msm.destroy();
 	Configuration.setCollectionConfiguration(null);
 	if (Gatherer.g_man != null) {
@@ -127,6 +119,4 @@
 	cdm = null;
 	document = null;
-	gdm = null;
-	msm = null;
     }
     
@@ -170,8 +160,4 @@
     }
 
-    public MetadataXMLFileManager getGDM() {
-	return gdm;
-    }
-    
     /** Retrieve the short name for this collection.
      * @return The name as a <strong>String</strong>.
Index: /trunk/gli/src/org/greenstone/gatherer/collection/CollectionManager.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/collection/CollectionManager.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/collection/CollectionManager.java	(revision 8313)
@@ -62,13 +62,9 @@
 import org.greenstone.gatherer.gui.WarningDialog;
 import org.greenstone.gatherer.gui.tree.WorkspaceTree;
-import org.greenstone.gatherer.msm.ElementWrapper;
-import org.greenstone.gatherer.msm.MetadataXMLFileManager;
-import org.greenstone.gatherer.msm.GreenstoneArchiveParser;
-import org.greenstone.gatherer.msm.LegacyCollectionImporter;
-import org.greenstone.gatherer.msm.MetadataSet;
-import org.greenstone.gatherer.msm.MetadataSetManager;
-import org.greenstone.gatherer.msm.MSMEvent;
-import org.greenstone.gatherer.msm.MSMListener;
-import org.greenstone.gatherer.msm.MSMProfiler;
+import org.greenstone.gatherer.metadata.DocXMLFileManager;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
+import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
 import org.greenstone.gatherer.shell.GShell;
 import org.greenstone.gatherer.shell.GShellEvent;
@@ -89,7 +85,6 @@
  */
 public class CollectionManager
-    implements GShellListener, MSMListener {
-    /** A reference to the metadata set manager. */
-    public MetadataSetManager msm;
+    implements GShellListener {
+
     /** Are we currently in the process of building? */
     private boolean building = false;
@@ -100,6 +95,4 @@
     /** The collection_model. */
     private FileSystemModel collection_model = null;
-    /** The workspace model. This becomes invalid on a collection change. */
-    // private FileSystemModel workspace_model = null;
     /** An inner class listener responsible for noting tree changes and resetting saved when they occur. */
     private FMTreeModelListener fm_tree_model_listener = null;
@@ -127,9 +120,12 @@
 	this.collection = null;
     }
+
+
     /** Add a special directory mapping.
      * @param name The name for this directory mapping as a <strong>String</strong>.
      * @param file The directory this mapping maps to as a <strong>File</strong>.
      */
-    public void addDirectoryMapping(String name, File file) {
+    public void addDirectoryMapping(String name, File file)
+    {
 	// Update the information stored in the Gatherer config
 	Configuration.addDirectoryMapping(name, file);
@@ -137,4 +133,6 @@
 	Gatherer.g_man.refreshWorkspaceTree(WorkspaceTree.FOLDER_SHORTCUTS_CHANGED);
     }
+
+
     /** This method calls the builcol.pl scripts via a GShell so as to not lock up the processor.
      * @see org.greenstone.gatherer.Configuration
@@ -147,5 +145,5 @@
      * @see org.greenstone.gatherer.util.Utility
      */
-    public void buildCollection() {
+    private void buildCollection() {
 	DebugStream.println("CollectionManager.buildCollection()");
 	building = true;
@@ -227,7 +225,12 @@
 	lock_file.delete();
 	if(lock_file.exists()) {
-	   System.err.println("Lockfile was not successfully deleted.");
-	}
-	collection.msm.destroy();
+	    System.err.println("Lockfile was not successfully deleted.");
+	}
+
+	MetadataSetManager.clearMetadataSets();
+	MetadataXMLFileManager.clearMetadataXMLFiles();
+	DocXMLFileManager.clearDocXMLFiles();
+	ProfileXMLFileManager.clearProfileXMLFile();
+
 	collection = null;
 	collection_model = null;
@@ -324,7 +327,6 @@
      * @param metadata_sets if the user has decided to select several metadata sets with which to initially populate the GLI then this is an ArrayList of metadata set file names, otherwise its null
      */
-    public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets) {
-	boolean cancelled = false;
-
+    public void createCollection(String description, String email, String name, String title, File base_collection_directory, ArrayList metadata_sets)
+    {
 	try {
 	    // first make sure that the collect directory exists
@@ -340,11 +342,11 @@
 	    // *******************
 	    //check that this creation has worked - simply by checking for the existence of the collect.cfg file
-	    String a_dir;
+	    String collection_dir;
 	    if (Gatherer.GS3) {
-		a_dir = Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, name);
+		collection_dir = Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, name);
 	    } else {
-		a_dir = Utility.getCollectionDir(Configuration.gsdl_path, name);
-	    }
-	    File config_file = new File(Utility.getConfigFile(a_dir));
+		collection_dir = Utility.getCollectionDir(Configuration.gsdl_path, name);
+	    }
+	    File config_file = new File(Utility.getConfigFile(collection_dir));
 	    if (!config_file.exists()) {
 		// no point continuing
@@ -356,5 +358,5 @@
  	    
 	    // ACTIVE_DIR/log/
-	    File log_dir_temp = new File(Utility.getLogDir(a_dir)+"temp.dat");
+	    File log_dir_temp = new File(Utility.getLogDir(collection_dir)+"temp.dat");
 	    File log_dir = log_dir_temp.getParentFile();
 	    log_dir.mkdirs();
@@ -364,5 +366,5 @@
 
 	    // Make sure an import folder exists
-	    File import_directory = new File(Utility.getImportDir(a_dir));
+	    File import_directory = new File(Utility.getImportDir(collection_dir));
 	    if (!import_directory.exists()) {
 		import_directory.mkdirs();
@@ -372,35 +374,30 @@
 
 	    // Now create the collection object around the directory.
-	    collection = new Collection(new File(a_dir, name + ".col"));
-	    collection.msm = new MetadataSetManager();
-	    msm = collection.msm; // Legacy
-	    collection.msm.load();
-
-	    // Import default metadata sets if any.
-	    for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
-		MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
-		collection.msm.importMDS(metadata_set.getFile(), false);
-	    }
-
-	    boolean skip_import_phase = false;
+	    collection = new Collection(new File(collection_dir, name + ".col"));
+
+	    MetadataSetManager.clearMetadataSets();
+	    MetadataXMLFileManager.clearMetadataXMLFiles();
+	    DocXMLFileManager.clearDocXMLFiles();
+
+	    // Import default metadata sets, if any
+	    for (int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
+		importMetadataSet((MetadataSet) metadata_sets.get(i));
+	    }
+
+	    ProfileXMLFileManager.loadProfileXMLFile(new File(collection_dir, Utility.META_DIR));
 
 	    // Before we create the CollectionDesignManager we have to check if we are basing it upon some other collection.
-	    if(base_collection_directory != null) {
-	       DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
-	       collection.setBaseCollection(base_collection_directory.getAbsolutePath());
-	       // copy over other needed directories
-	       copyExtraBaseCollStuff(new File(a_dir), base_collection_directory);
-		// Try to import any existing metadata sets for this collection. Look in base_collection_directory/metadata and import any metadata sets found.
-		File base_metadata = new File(base_collection_directory, Utility.META_DIR);
-		if(base_metadata.exists()) {
-		    DebugStream.println("Found the metadata directory.");
-		    File[] possible_metadata_sets = base_metadata.listFiles();
-		    for(int i = 0; possible_metadata_sets != null && i < possible_metadata_sets.length; i++) {
-			String filename = possible_metadata_sets[i].getName();
-			if(filename.endsWith(".mds")) {
-			    DebugStream.println("+ Found a metadata set. Importing: " + possible_metadata_sets[i].getAbsolutePath());
-			    collection.msm.importMDS(possible_metadata_sets[i], false);
-			    skip_import_phase = true;
-			}
+	    if (base_collection_directory != null) {
+		DebugStream.println("Basing new collection on existing one: " + base_collection_directory);
+		collection.setBaseCollection(base_collection_directory.getAbsolutePath());
+		// copy over other needed directories
+		copyExtraBaseCollStuff(new File(collection_dir), base_collection_directory);
+		// Try to import any existing metadata sets for this collection
+		// Look in base_collection_directory/metadata and import any metadata sets found.
+		File base_metadata_directory = new File(base_collection_directory, Utility.META_DIR);
+		ArrayList base_metadata_sets = MetadataSetManager.listMetadataSets(base_metadata_directory);
+		if (base_metadata_sets != null) {
+		    for (int i = 0; i < base_metadata_sets.size(); i++) {
+			importMetadataSet((MetadataSet) base_metadata_sets.get(i));
 		    }
 		}
@@ -408,68 +405,36 @@
 		    DebugStream.println("This base collection has no metadata directory.");
 		}
-		// If no sets were imported, then create a new metadata with this new collections name.
-		if(collection.msm.getSets().size() == 0) {
+
+		// If no sets were imported...
+		if (MetadataSetManager.getMetadataSets().size() == 0) {
 		    // Prompt the user so that they can choose at least one initial metadata set. We're sneaky here and just create a ncm_prompt
 		    DebugStream.println("This collection has no metadata sets. Present the user with the metadata set selection prompt.");
 		    NewCollectionMetadataPrompt ncm_prompt = new NewCollectionMetadataPrompt();
 		    // If cancelled then they really do mean to start a collection with no metadata sets.
-		    if(!ncm_prompt.isCancelled()) {
+		    if (!ncm_prompt.isCancelled()) {
 			ArrayList initial_sets = ncm_prompt.getSets();
-			for(int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
-			    MetadataSet metadata_set = (MetadataSet) initial_sets.get(i);
-			    collection.msm.importMDS(metadata_set.getFile(), false);
-			    metadata_set = null;
+			for (int i = 0; initial_sets != null && i < initial_sets.size(); i++) {
+			    importMetadataSet((MetadataSet) initial_sets.get(i));
 			}
-			initial_sets = null;
 		    }
 		    ncm_prompt.dispose();
 		    ncm_prompt = null;
 		}
-		// Do a dry metadata import run over the entire base collection, recording profile mappings. We do this by finding the archive files, and then iterating over them using the GreenstoneArchiveParser to retrieve metadata from them. We then process the importing of new metadata elements using the selectElement prompt used in a file action metadata import. However the big change is that we don't actually import any metadata, just create importing profiles.
-		if(!skip_import_phase) {
-		    File base_archive = new File(base_collection_directory, Utility.ARCHIVES_DIR);
-		    if(base_archive.exists()) {
-			DebugStream.println("+ Archive directory found. Inspecting archives for metadata information.");
-			ArrayList metadata_elements = GreenstoneArchiveParser.extractMetadataElements(base_archive);
-			for(int i = 0; !cancelled && i < metadata_elements.size(); i++) {
-			    String metadata_name = (String) metadata_elements.get(i);
-			    ElementWrapper target = collection.msm.prompt.selectElement(metadata_name);
-			    cancelled = Gatherer.c_man.getCollection().msm.prompt.wasDialogCancelled();
-			    if(!cancelled) {
-				if(target != null) {
-				    collection.msm.profiler.addAction(base_collection_directory.getAbsolutePath(), metadata_name, target.getName());
-				}
-				else {
-				    collection.msm.profiler.addAction(base_collection_directory.getAbsolutePath(), metadata_name, null);
-				}
-			    }
-			}
-			// Hopefully mappings should now be in place for metadata extracted from this collection.
-		    }
-		    else {
-			DebugStream.println("+ Searching files for metadata.xml information.");
-			// Find the import directory
-			File base_import = new File(base_collection_directory, Utility.IMPORT_DIR);
-			if(base_import.exists()) {
-			    searchForMetadata(base_import);
-			}
-		    }
-		}
-		// And if that fails then we must have been asked by Satan himself to build the very digital collections of hell, because they don't match any goodly greenstone collection I have ever seen, so you can't blame me if I can't import them.
 
 		// Now we update our collect.cfg
 		DebugStream.println("Copy and update collect.cfg from base collection.");
-		updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE), new File(a_dir, Utility.CONFIG_FILE), description, email, title);
+		updateCollectionCFG(new File(base_collection_directory, Utility.CONFIG_FILE), new File(collection_dir, Utility.CONFIG_FILE), description, email, title);
 	    }
 
 	    // Always import the extracted metadata set if we didn't already
-	    if(collection.msm.getSet(Utility.EXTRACTED_METADATA_NAMESPACE) == null) {
-	       collection.msm.importMDS(new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION), false);
+	    if (MetadataSetManager.getMetadataSet(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE) == null) {
+		File extracted_metadata_set_file = new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
+		importMetadataSet(new MetadataSet(extracted_metadata_set_file));
 	    }
 
 	    collection.cdm = new CollectionDesignManager(new File(getCollectionConfig()));
-	    
+
 	    // Now that we have a CDM, update several settings, such as if we created this collection by basing it on another, set it as public automatically
-	    if(base_collection_directory != null) {
+	    if (base_collection_directory != null) {
 		// Update the creator and maintainer
 		CollectionMeta creator_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getCreator());
@@ -479,16 +444,20 @@
 		maintainer_collectionmeta.setValue(email);
 		maintainer_collectionmeta = null;
+
 		// Update the collection title
 		CollectionMeta collection_name_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONNAME_STR);
 		collection_name_collectionmeta.setValue(title);
 		collection_name_collectionmeta = null;
+
 		// And now the description
 		CollectionMeta collection_extra_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_COLLECTIONEXTRA_STR);
 		collection_extra_collectionmeta.setValue(description);
 		collection_extra_collectionmeta = null;
+
 		// All collections based on others are automatically public
 		CollectionMeta public_collectionmeta = new CollectionMeta(collection.cdm.collect_config.getPublic());
 		public_collectionmeta.setValue(StaticStrings.TRUE_STR);
 		public_collectionmeta = null;
+
 		// Finally reset the icons
 		CollectionMeta icon_collection_collectionmeta = collection.cdm.collectionmeta_manager.getMetadatum(StaticStrings.COLLECTIONMETADATA_ICONCOLLECTION_STR);
@@ -499,31 +468,16 @@
 		icon_collection_small_collectionmeta = null;
 	    }
-	    
-	    collection.gdm = new MetadataXMLFileManager();
 
 	    progress.setProgress(3);
 
-	    // Has to be done after creating metadata set manager.
-	    File gmeta_dir_temp = new File(getCollectionMetadata()+"temp.dat");
-	    File gmeta_dir = gmeta_dir_temp.getParentFile();
-	    gmeta_dir.mkdirs();
-	    if(progress != null) {
-		progress.setNote("GMeta created");
-	    }
-	    progress.setProgress(4);
-
-	    progress.setProgress(6);
-	    // Register ourselves as being interested in what the msm has to say.
-	    collection.msm.addMSMListener(this);
 	    // Create a lock file.
-	    File lock_file = new File(a_dir, LOCK_FILE);
+	    File lock_file = new File(collection_dir, LOCK_FILE);
 	    FileOutputStream out = new FileOutputStream(lock_file);
 	    out.write(LOCK_FILE.getBytes());
 	    out.close();
 	    out = null;
+
 	    progress.setProgress(7);
-	    String args[] = new String[1];
-	    args[0] = name;
-	    progress.setNote(Dictionary.get("CollectionManager.Session_Ready", args));
+	    progress.setNote(Dictionary.get("CollectionManager.Session_Ready", name));
 	    progress.close();
 	}
@@ -543,4 +497,5 @@
 	}
     }
+
 
     public void createLockFile(File destination) {
@@ -569,19 +524,4 @@
     }
 
-    /** Method that is called whenever an element within a set is changed or modified. We want to mark the collection so that it needs saving again.
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
-     * @see org.greenstone.gatherer.collection.Collection
-     */
-    public void elementChanged(MSMEvent event) {
-	// This means the state of the collections has changed, so we should set saved to false.
-	collection.setSaved(false);
-    }
-    /** Used to retrieve the build options associated with the currently loaded collection. If none yet exist, default ones are created.
-     * @return A <strong>BuildOptions</strong> object containing the build options for the current collection.
-     * @see org.greenstone.gatherer.collection.Collection
-     */
-    /* private BuildOptions getBuildOptions() {
-	return collection.build_options;
-	} */
 
     /** Retrieve the current collection.
@@ -591,4 +531,6 @@
 	return collection;
     }
+
+
     /** Constructs the absolute filename of the collection archive directory, which should resemble "$GSDLHOME/collect/&lt;col_name&gt;/archive/"
      * @return A <strong>String</strong> containing the filename.
@@ -630,5 +572,5 @@
 	    return Utility.getConfigFile(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
 	} else {
-	return Utility.getConfigFile(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
+	    return Utility.getConfigFile(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
 	}
     }
@@ -660,5 +602,5 @@
 	    return Utility.getEtcDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
 	} else {
-	return Utility.getEtcDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
+	    return Utility.getEtcDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
 	}
     }
@@ -674,5 +616,5 @@
 	    return Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()) + collection.getName() + ".col";
 	} else {
-	return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + collection.getName() + ".col";
+	    return Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()) + collection.getName() + ".col";
 	}
     }
@@ -688,5 +630,5 @@
 	    return Utility.getImagesDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
 	} else {
-	return Utility.getImagesDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
+	    return Utility.getImagesDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
 	}
     }
@@ -748,14 +690,14 @@
     }
 
-    /** This method either returns the title of the current collection, or a placeholder string of 'No Collection'.
-     * @return A <strong>String</strong> which represents what we wish to display for a collection title.
-     * @see org.greenstone.gatherer.collection.Collection
-     */
-    /* private String getCollectionTitle() {
-	if(collection != null) {
-	    return collection.getTitle();
-	}
-	return Dictionary.get("Collection.No_Collection");
-	} */
+
+    static public String getCollectionMetadataDirectory()
+    {
+	if (Gatherer.GS3) {
+	    return Utility.getMetadataDir(Utility.getCollectionDir(Configuration.gsdl3_path, Configuration.site_name, collection.getName()));
+	} else {
+	    return Utility.getMetadataDir(Utility.getCollectionDir(Configuration.gsdl_path, collection.getName()));
+	}
+    }
+	
 
     /** Retrieve the record set (tree model) associated with the current collection. */
@@ -827,18 +769,17 @@
 	    index_dir = index_dir.getParentFile();
 	    if(index_dir.exists()) {
-	       DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
-	       if (!canDelete(index_dir)) {
-		   // tell the user
-		   JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE); 
-		   // tell the gui manager
-		   // a message for the building log 
-		   GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
-		   Gatherer.g_man.create_pane.message(event);
-		   event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
-		   Gatherer.g_man.create_pane.processComplete(event);
-		   importing = false;
-		   return;
-	       }
-	       
+		DebugStream.println("Old Index = " + index_dir.getAbsolutePath()+", testing for deletability");
+		if (!canDelete(index_dir)) {
+		    // tell the user
+		    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Delete_Index"), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE); 
+		    // tell the gui manager
+		    // a message for the building log 
+		    GShellEvent event = new GShellEvent(this, 0, GShell.IMPORT, Dictionary.get("CollectionManager.Cannot_Delete_Index_Log"), GShell.ERROR);
+		    Gatherer.g_man.create_pane.message(event);
+		    event = new GShellEvent(this, 0, GShell.IMPORT, "", GShell.ERROR);
+		    Gatherer.g_man.create_pane.processComplete(event);
+		    importing = false;
+		    return;
+		}
 	    }
 
@@ -879,4 +820,31 @@
     }
 
+
+    public void importMetadataSet(MetadataSet external_metadata_set)
+    {
+	// Copy the .mds file into the collection's "metadata" folder...
+	File external_metadata_set_file = external_metadata_set.getMetadataSetFile();
+
+	// ...but not if it is the redundant "hidden.mds" file
+	if (external_metadata_set_file.getName().equals("hidden.mds")) {
+	    return;
+	}
+
+	// ...and only if it doesn't already exist
+	File metadata_set_file = new File(getCollectionMetadata(), external_metadata_set_file.getName());
+	if (!metadata_set_file.exists()) {
+	    try {
+		Gatherer.f_man.getQueue().copyFile(external_metadata_set_file, metadata_set_file, null);
+	    }
+	    catch (Exception ex) {
+		ex.printStackTrace();
+	    }
+
+	    // Load it into the MetadataSetManager
+	    MetadataSetManager.loadMetadataSet(metadata_set_file);
+	}
+    }
+
+
     /** Determine if we are currently in the middle of importing (and thus, in this case, we can't allow the log writer to exit). Boy was this a mission to track down. The cascade of crap rolls out something like this: Joe Schmo clicks 'Build Collection', which calls the importCollection() method above, which in turn saves the collection with a saveTask, which fires a collectionChanged message once its finished, which drives the list of logs shown on the create pane to update, which fires a itemChanged() event to the OptionsPane who dutifully tells the current log writer thread to finish up writing (all zero lines its been asked to write) and then die. Wereapon Joe Schmo gets a pretty log to look at, but it isn't actually being written to file so the next time he tries to view it faeces hits the air motion cooling device. Joy.
      * @return true if the gli is currently importing
@@ -891,26 +859,23 @@
      * @see org.greenstone.gatherer.Gatherer
      * @see org.greenstone.gatherer.collection.Collection
-     * @see org.greenstone.gatherer.msm.MetadataSetManager
-     * @see org.greenstone.gatherer.msm.MSMListener
      * @see org.greenstone.gatherer.util.Utility
      */
-    public boolean loadCollection(String location) {
-	DebugStream.println("Load Collection '" + location + "'");
-	String[] args2 = new String[1];
-	args2[0] = location;
-	boolean result = false;
+    public boolean loadCollection(String location)
+    {
+	DebugStream.println("Loading collection " + location + "...");
 	boolean non_gatherer_collection = false;
+
 	// Check we have actually been given a .col file.
-	if(!location.endsWith(".col")) {
-	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", args2), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+	if (!location.endsWith(".col")) {
+	    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Not_Col_File", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
 	    DebugStream.println("CollectionManager.loadCollection: Haven't been given a .col file.");
 	    return false;
 	}
+
 	// Check that there is the collection configuration file available
-
 	File collection_file = new File(location);
 	// Ensure that the directory exists.
 	File collection_directory = collection_file.getParentFile();
-	if(!collection_directory.exists()) {
+	if (!collection_directory.exists()) {
 	    // we cant open this
 	    collection_directory = null;
@@ -926,35 +891,32 @@
 
 	// Special case of a user trying to open an old greenstone collection.
-	File metadata_directory = new File(collection_directory, Utility.META_DIR);
-	if(!metadata_directory.exists()) {
-
-	    DebugStream.println("CollectionManager.loadCollection: trying to load up a non-gatherer collection");
+	File collection_metadata_directory = new File(collection_directory, Utility.META_DIR);
+	if (!collection_metadata_directory.exists()) {
+	    DebugStream.println("Loading non-gatherer collection...");
 	    non_gatherer_collection = true;
 	}
 
+	// Now determine if a lock already exists on this collection.
 	String name = collection_directory.getName();
 	File lock_file = new File(collection_file.getParentFile(), LOCK_FILE);
-	// Now determine if a lock already exists on this collection.
-	int choice = LockFileDialog.YES_OPTION;
-	if(lock_file.exists()) {
+	if (lock_file.exists()) {
 	    LockFileDialog dialog = new LockFileDialog(Gatherer.g_man, name, lock_file);
-	    choice = dialog.getChoice();
+	    int choice = dialog.getChoice();
 	    dialog.dispose();
 	    dialog = null;
-	}
-
-	if(choice != LockFileDialog.YES_OPTION) {
-	    // user has cancelled
-	    lock_file = null;
-	    collection_directory = null;
-	    collection_config_file = null;
-	    return false;
-	}
-
-
+
+	    if (choice != LockFileDialog.YES_OPTION) {
+		// user has cancelled
+		lock_file = null;
+		collection_directory = null;
+		collection_config_file = null;
+		return false;
+	    }
+
+	    lock_file.delete();
+	}
+
+	boolean result = false;
 	try {
-	    if(lock_file.exists()) {
-		lock_file.delete();
-	    }
 	    // Create a lock file.
 	    createLockFile(lock_file);
@@ -964,5 +926,5 @@
 		System.err.println("Cannot write lock file!");
 		String args[] = new String[2];
-		args[0] = args2[0];
+		args[0] = location;
 		args[1] = Dictionary.get("FileActions.Write_Not_Permitted_Title");
 		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
@@ -970,4 +932,5 @@
 		return false;
 	    }
+
 	    // Open the collection file
 	    this.collection = new Collection(collection_file);
@@ -975,5 +938,5 @@
 		collection = null;
 		// Remove lock file
-		if(lock_file.exists()) {
+		if (lock_file.exists()) {
 		    lock_file.delete();
 		}
@@ -981,11 +944,12 @@
 	    }
 
-	    collection.msm = new MetadataSetManager();
-	    msm = collection.msm; // Legacy
-	    collection.msm.load();
-	    // if non-gatherer collection, need to add some metadata sets
+	    MetadataSetManager.clearMetadataSets();
+	    MetadataSetManager.loadMetadataSets(collection_metadata_directory);
+
+	    ProfileXMLFileManager.loadProfileXMLFile(collection_metadata_directory);
+ 
+	    // If this is a non-GLI (legacy) collection, ask the user to choose some metadata sets
 	    if (non_gatherer_collection) {
 		if (!addSomeMetadataSets(collection_directory)) {
-		    // for now - return of false means its been cancelled. Any error messages should be sent from the function itself
 		    lock_file = null;
 		    collection_directory = null;
@@ -993,41 +957,45 @@
 		    return false;
 		}
-	    }
+
+		// Recurse the import folder tree, backing up the metadata.xml files before they are edited
+		LegacyCollectionImporter.backupMetadataXMLFiles(collection_directory);
+	    }
+
+	    // Read through the metadata.xml files in the import directory, building up the metadata value trees
+	    File collection_import_directory = new File(collection_directory, Utility.IMPORT_DIR);
+	    MetadataXMLFileManager.clearMetadataXMLFiles();
+	    MetadataXMLFileManager.loadMetadataXMLFiles(collection_import_directory);
+
+	    // Read through the doc.xml files in the archives directory
+	    File collection_archives_directory = new File(collection_directory, Utility.ARCHIVES_DIR);
+	    DocXMLFileManager.clearDocXMLFiles();
+	    DocXMLFileManager.loadDocXMLFiles(collection_archives_directory);
 
 	    collection.cdm = new CollectionDesignManager(collection_config_file);
 	    if (non_gatherer_collection) {
-		// We first recurse the Import folder tree, reading in any metadata.xml files, and then altering the non-namespaced element names to be valid GLI names
-		LegacyCollectionImporter lci = new LegacyCollectionImporter(collection_directory, collection.cdm);
-		lci.backupMetadataXMLFiles(collection_directory);
-		lci.importMetadata();
-		lci.updateClassifiers();
-		lci = null;
-	    }
-	    // Whether the collection is legacy or not, we should now be able to prepare the MetadataXMLFileManager
-	    collection.gdm = new MetadataXMLFileManager();
+		// Change the classifiers to use the namespaced element names
+		LegacyCollectionImporter.updateClassifiers(collection.cdm);
+	    }
 
 	    // Tell everyone that it worked.
-	    String[] args = new String[1];
-	    args[0] = name;
-	    DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", args));
-	    // Now we need to hook up classes that depend on messages from the metadata set manager to keep their content fresh.
-	    collection.msm.addMSMListener(this);
+	    DebugStream.println(Dictionary.get("CollectionManager.Loading_Successful", name));
+
 	    // We're done. Let everyone know.
-	    if(Gatherer.g_man != null) {
-		// workspace_model = null;
+	    if (Gatherer.g_man != null) {
 		Gatherer.g_man.collectionChanged(ready());
 	    }
 	    result = true;
-	} catch (Exception error) {
+	}
+	catch (Exception error) {
 	    // There is obviously no existing collection present.
 	    DebugStream.printStackTrace(error);
 	    if(error.getMessage() != null) {
 		String[] args = new String[2];
-		args[0] = args2[0];
+		args[0] = location;
 		args[1] = error.getMessage();
 		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open_With_Reason", args), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
 	    }
 	    else {
-		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", args2), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
+		JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("CollectionManager.Cannot_Open", location), Dictionary.get("General.Error"), JOptionPane.ERROR_MESSAGE);
 	    }
 	}
@@ -1037,5 +1005,4 @@
 	collection_config_file = null;
 
-	args2 = null;
 	return result;
     }
@@ -1147,12 +1114,5 @@
     public synchronized void message(GShellEvent event) {
     }
-    /** Called whenever the metadata value changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
-     * @see org.greenstone.gatherer.collection.Collection
-     */
-    public void metadataChanged(MSMEvent event) {
-	// Again this change means we need to save the collection again.
-	collection.setSaved(false);
-    }
+
     /** This call is fired whenever a process within a GShell created by this class begins.
      * @param event A <strong>GShellEvent</strong> containing information about the GShell process.
@@ -1282,4 +1242,28 @@
 	return file;
     }
+
+
+    public void removeMetadataSet(MetadataSet metadata_set)
+    {
+	System.err.println("Removing metadata set...");
+
+	// Delete the .mds file from the collection's "metadata" folder...
+	File metadata_set_file = metadata_set.getMetadataSetFile();
+
+	// ...but not if it is the "ex.mds" file
+	if (metadata_set_file.getName().equals("ex.mds")) {
+	    return;
+	}
+
+	// ...and only if it exists
+	if (metadata_set_file.exists()) {
+	    metadata_set_file.delete();
+
+	    // Unload it from the MetadataSetManager
+	    MetadataSetManager.unloadMetadataSet(metadata_set);
+	}
+    }
+
+
     /** Used to check whether all open collections have a 'saved' state.
      * @return A <i>boolean</i> which is <i>true</i> if the collection has been saved.
@@ -1313,13 +1297,4 @@
     }
 
-    /** Method that is called whenever the metadata set collection changes in some way, such as the addition of a new set or the merging of two sets. We want to mark the collection so that it needs saving again.
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
-     * @see org.greenstone.gatherer.collection.Collection
-     */
-    public void setChanged(MSMEvent event) {
-	// Invalidate saved
-	collection.setSaved(false);
-    }
-
     public void setClosingThread(boolean set) {
 	if(set) {
@@ -1331,24 +1306,4 @@
     }
 
-    /** Updates the given workspace tree model to reference the private cache of the currently loaded collection. */
-    /* private void updatePrivateWorkspace(DefaultTreeModel model) {
-	// Add Private workspace if a collection has been loaded.
-	if(ready() && !Configuration.get("workflow.mirror", true)) {
-	    FileNode root = (FileNode)model.getRoot();
-				// Remove old private workspace
-	    FileNode old = (FileNode)model.getChild(root, 2);
-	    model.removeNodeFromParent(old);
-				// Create and insert new.
-	    FileNode private_workspace = new FileNode(new File(getCollectionCache()), Dictionary.get("Tree.Private"));
-	    model.insertNodeInto(private_workspace, root, 2);
-	}
-	} */
-    /** Called whenever the value tree of an metadata element changes in some way, such as the addition of a new value. We want to mark the collection so that it needs saving again.
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
-     * @see org.greenstone.gatherer.collection.Collection
-     */
-    public void valueChanged(MSMEvent event) {
-	collection.setSaved(false);
-    }
 
     /** I started giving the user the choice of using an existing meta set or creating a new one. The second option being so that they didn't have to add/merge/ignore each element, they could all be added automatically. However, I am not sure where the merge prompt gets called from, and it is not essential, so I am leaving it for now - it should be added back in and finished. [kjdon] */
@@ -1364,12 +1319,12 @@
 
 	/*if (meta_choice == ExternalCollectionPrompt.NEW_META_SET) {
-	    NewMetaSetPrompt nmsp = new NewMetaSetPrompt();
-	    if (nmsp.isCancelled()) {
-	    return false;
-}
-	    String namespace_str = nmsp.getNamespace();
-	    String name_str = nmsp.getName();
-	    MetadataSet set = Gatherer.c_man.msm.addSet(namespace_str, name_str);
-	} else if (meta_choice == ExternalCollectionPrompt.EXISTING_META_SET) {
+	  NewMetaSetPrompt nmsp = new NewMetaSetPrompt();
+	  if (nmsp.isCancelled()) {
+	  return false;
+	  }
+	  String namespace_str = nmsp.getNamespace();
+	  String name_str = nmsp.getName();
+	  // MetadataSet set = Gatherer.c_man.msm.addSet(namespace_str, name_str);
+	  } else if (meta_choice == ExternalCollectionPrompt.EXISTING_META_SET) {
 	*/
 	// now we reuse the newcoll metadata prompt for the user to select metadata sets
@@ -1381,28 +1336,14 @@
 	// Import default metadata sets if any.
 	for(int i = 0; metadata_sets != null && i < metadata_sets.size(); i++) {
-	    MetadataSet metadata_set = (MetadataSet) metadata_sets.get(i);
-	    collection.msm.importMDS(metadata_set.getFile(), false);
-	}
-	/*} else {
-	  return false;
-	  }*/
+	    importMetadataSet((MetadataSet) metadata_sets.get(i));
+	}
+
 	// Always import the extracted metadata set
-	collection.msm.importMDS(new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION), false);
+	File extracted_metadata_set_file = new File(Utility.METADATA_DIR + Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION);
+	importMetadataSet(new MetadataSet(extracted_metadata_set_file));
 
 	return true;
     }
 
-
-//      // now try to load in existing metadata, delete the existing metadata.xml files, then save the new ones.
-//      private boolean findAndLoadExistingMetadata(File collection_dir)
-//      {
-//  	TreeModel collection_tree = getRecordSet();
-//  	FileNode root_node = (FileNode) collection_tree.getRoot();
-//  	if (searchForMetadata(collection_tree, root_node) == false) {
-//  	    return false;
-//  	}
-//  	collection.gdm.save(root_node);
-//  	return true;
-//      }
 
     // used as arg in the perl scripts
@@ -1423,9 +1364,11 @@
     }
 
+
     /** Install collection by moving its files from building to index after a successful build.
      * @see org.greenstone.gatherer.Gatherer
      * @see org.greenstone.gatherer.util.Utility
      */
-    private boolean installCollection() {
+    private boolean installCollection()
+    {
 	DebugStream.println("Build complete. Moving files.");
 
@@ -1506,53 +1449,10 @@
 
 
-    private boolean searchArchivesForMetadata(File archive_directory) {
-	/** @todo - ensure GreenstoneArchiveParser works as expected. */
-	return true;
-    }
-
-    /** now this returns true if successful, false if unsuccessful or cancelled */
-    private boolean searchForMetadata(File current_file) {
-	boolean success = true;
-       if(current_file.isFile() && current_file.getName().equals(Utility.METADATA_XML)) {
-           success = collection.msm.searchForMetadata(null, new FileNode(current_file), false, true); // A dummy run only.
-       }
-       else {
-           File[] children_files = current_file.listFiles();
-           for(int i = 0; success && children_files != null && i < children_files.length; i++) {
-               success = searchForMetadata(children_files[i]);
-           }
-       }
-       return success;
-     }
-    
-    private boolean searchForMetadata(TreeModel collection_tree, FileNode current_node) {
-	File source_file = current_node.getFile();
-	String source_file_name = source_file.getName();
-	if (source_file_name.equals(Utility.METADATA_XML) || source_file_name.equals("CVS")) {
-	    return true;
-	}
-	if (collection.msm.searchForMetadata(current_node, current_node, false)== false) {
-	    return false;
-	}
-	int num_children = collection_tree.getChildCount(current_node);
-	for (int i=0; i<num_children; i++) {
-	    FileNode child = (FileNode)collection_tree.getChild(current_node, i);
-	    if (searchForMetadata(collection_tree, child)==false) {
-		return false;
-	    }
-	}
-	return true;
-    }
-
-    private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title) {
+    private void updateCollectionCFG(File base_cfg, File new_cfg, String description, String email, String title)
+    {
 	boolean first_name = true;
 	boolean first_extra = true;
 	String collection_path = (base_cfg.getParentFile().getParentFile()).getAbsolutePath();
-	
-	HashMap mappings = collection.msm.profiler.getActions(collection_path);
-	if(mappings == null) {
-	    DebugStream.println("Mappings is null, which is odd. Leaving all configuration commands which use metadata as they are.");
-	}
-	
+
 	// Now read in base_cfg line by line, parsing important onces and/or replacing them with information pertinent to our collection. Each line is then written back out to the new collect.cfg file.
 	try {
@@ -1620,9 +1520,6 @@
 				text.append(token);
 				String temp_metadata = tokenizer.nextToken();
-				String replacement = null;
-				if(mappings != null) {
-				    replacement = (String) mappings.get(temp_metadata);
-				}
-				if(replacement != null) {
+				String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
+				if (replacement != null && !replacement.equals("")) {
 				    token = replacement;
 				    old_metadata = temp_metadata;
@@ -1641,9 +1538,6 @@
 				text.append(token);
 				String temp_metadata = tokenizer.nextToken();
-				String replacement = null;
-				if(mappings != null) {
-				    replacement = (String) mappings.get(temp_metadata);
-				}
-				if(replacement != null) {
+				String replacement = ProfileXMLFileManager.getMetadataElementFor(temp_metadata);
+				if (replacement != null && !replacement.equals("")) {
 				    token = replacement;
 				}
@@ -1681,6 +1575,6 @@
 		    old_metadata = null;
 		    write(out, command);
-		 } else {
-		     // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
+		} else {
+		    // the rest of the commands just want a string - we read in all the tokens from the tokeniser and get rid of it.
 		    StringBuffer new_command = new StringBuffer(command_type_str);
 		    while (tokenizer.hasMoreTokens()) {
@@ -1694,18 +1588,22 @@
 		    // we really want to build up the whole command here
 		    boolean format_command = command_type_str.equals(Utility.CFG_FORMAT);
-		    // Replace mapping strings
-		    if(mappings != null) {
-			for(Iterator keys = mappings.keySet().iterator(); keys.hasNext(); ) {
+		    HashMap metadata_mapping = ProfileXMLFileManager.getMetadataMapping();
+		    if (metadata_mapping != null) {
+			Iterator keys = metadata_mapping.keySet().iterator();
+			while (keys.hasNext()) {
 			    String target = (String) keys.next();
-			    String replacement = (String) mappings.get(target);
-			    if(format_command) {
-				target = "\\[" + target + "\\]";
-				replacement = "{Or}{[" + replacement + "]," + target + "}";
+			    String replacement = (String) metadata_mapping.get(target);
+			    if (replacement != null && !replacement.equals("")) {
+				if (format_command) {
+				    target = "\\[" + target + "\\]";
+				    replacement = "{Or}{[" + replacement + "]," + target + "}";
+				}
+				command = command.replaceAll(target, replacement);
 			    }
-			    command = command.replaceAll(target, replacement);
 			}
 		    }
+
 		    write(out, command);
-		 }
+		}
 		tokenizer = null;
 	    }
@@ -1727,4 +1625,5 @@
 	out.newLine();
     }
+
 
     /** The CollectionManager class is getting too confusing by half so I'll implement this TreeModelListener in a private class to make responsibility clear. */
Index: /trunk/gli/src/org/greenstone/gatherer/collection/LegacyCollectionImporter.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/collection/LegacyCollectionImporter.java	(revision 8313)
+++ /trunk/gli/src/org/greenstone/gatherer/collection/LegacyCollectionImporter.java	(revision 8313)
@@ -0,0 +1,138 @@
+package org.greenstone.gatherer.collection;
+
+
+import java.io.*;
+import org.greenstone.gatherer.DebugStream;
+import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.cdm.Argument;
+import org.greenstone.gatherer.cdm.Classifier;
+import org.greenstone.gatherer.cdm.CollectionDesignManager;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataTools;
+import org.greenstone.gatherer.metadata.ProfileXMLFileManager;
+import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.util.Utility;
+
+
+/**
+ * Importing legacy collections involves two main steps:
+ *
+ * 1. Read the existing metadata.xml files and namespace them, usually by prompting the user
+ *    to specify the mapping between old metadata elements and new elements.
+ *
+ * 2. Fix up the classify commands in the collect.cfg file to specify the new element names.
+ *
+ * @author Michael Dewsnip
+ */
+public class LegacyCollectionImporter 
+{
+    // This copies all the existing metadata.xml files into a backup directory
+    static public void backupMetadataXMLFiles(File collection_dir)
+    {
+	File import_dir = new File(collection_dir, Utility.IMPORT_DIR);
+	File import_bak_dir = new File(collection_dir, Utility.IMPORT_BAK_DIR);
+	import_bak_dir.mkdir();
+	copyMetadataXMLFiles(import_dir, import_bak_dir);
+    }
+
+
+    static private void copyMetadataXMLFiles(File source_dir, File backup_dir)
+    {
+	if (source_dir == null || !source_dir.exists()) {
+	    return;
+	}
+
+	// Find the metadata file in this dir
+	File metadata_xml_file_file = new File(source_dir, "metadata.xml");
+	if (metadata_xml_file_file.exists()) {
+	    File new_metadata_xml_file_file = new File(backup_dir, "metadata.xml");
+	    try {
+		backup_dir.mkdirs();
+		Gatherer.f_man.getQueue().copyFile(metadata_xml_file_file, new_metadata_xml_file_file, null);
+		if (!new_metadata_xml_file_file.exists()) {
+		    throw new Exception("");
+		}
+	    }
+	    catch (Exception e) {
+		DebugStream.println("Exception: couldn't copy the file " + metadata_xml_file_file.getPath() + e.getMessage());
+	    }
+	}
+
+	// Now go through child directories
+	File [] children = source_dir.listFiles();
+	for (int i = 0; i < children.length; i++) {
+	    File child = children[i];
+	    if (child.isDirectory()) {
+		copyMetadataXMLFiles(child, new File(backup_dir, child.getName()));
+	    }
+	}
+    }
+
+
+    static public void updateClassifiers(CollectionDesignManager cdm)
+    {
+	// Update the metadata elements in each of the classifiers
+	for (int i = 0; i < cdm.classifier_manager.getSize(); i++) {
+	    Classifier classifier = cdm.classifier_manager.getClassifier(i);
+	    // System.err.println("Classifier: " + classifier);
+
+	    // Update the "-metadata" value
+	    Argument metadata_argument = classifier.getArgument("-metadata");
+	    String metadata_argument_value = metadata_argument.getValue();
+	    String metadata_element_name_full = mapLegacyMetadataElementName(metadata_argument_value);
+	    if (metadata_element_name_full != null && !metadata_element_name_full.equals("")) {
+		String metadata_element_display_name_full = MetadataTools.getDisplayNameForMetadataElementWithName(metadata_element_name_full);
+		if (metadata_element_display_name_full != null) {
+		    metadata_argument_value = metadata_element_display_name_full;
+		    metadata_argument.setValue(metadata_argument_value);
+		}
+	    }
+
+  	    // Update the "-sort" value
+	    Argument sort_argument = classifier.getArgument("-sort");
+	    if (sort_argument != null) {
+		String sort_element_name_full = mapLegacyMetadataElementName(sort_argument.getValue());
+		if (sort_element_name_full != null && !sort_element_name_full.equals("")) {
+		    String sort_element_display_name_full = MetadataTools.getDisplayNameForMetadataElementWithName(sort_element_name_full);
+		    if (sort_element_display_name_full != null) {
+			sort_argument.setValue(sort_element_display_name_full);
+		    }
+		}
+	    }
+
+	    // Set the "-buttonname" value if it isn't already set
+	    Argument buttonname_argument = classifier.getArgument("-buttonname");
+	    if (buttonname_argument.getValue().equals("")) {
+		int namespace_index = metadata_argument_value.indexOf(".");
+		if (namespace_index != -1) {
+		    buttonname_argument.setValue(metadata_argument_value.substring(namespace_index + 1));
+		}
+		else {
+		    buttonname_argument.setValue(metadata_argument_value);
+		}
+		buttonname_argument.setAssigned(true);
+	    }
+
+	    // With Hierarchy classifiers, update the hfile arguments
+  	    if (classifier.getName().equalsIgnoreCase(StaticStrings.HIERARCHY_CLASSIFIER)) {
+		// Update the "-hfile" value
+		Argument hfile_argument = classifier.getArgument(StaticStrings.HFILE_ARGUMENT);
+		hfile_argument.setValue(metadata_element_name_full + ".txt");
+  	    }
+
+	    // System.err.println("Classifier (after): " + classifier);
+	}
+    }
+
+
+    static private String mapLegacyMetadataElementName(String metadata_element_name)
+    {
+ 	// Remove the extracted namespace if it has been added
+ 	if (metadata_element_name.startsWith(StaticStrings.EXTRACTED_NAMESPACE)) {
+ 	    metadata_element_name = metadata_element_name.substring(StaticStrings.EXTRACTED_NAMESPACE.length());
+ 	}
+
+ 	// Update the metadata value to the new (namespaced) one
+	return ProfileXMLFileManager.getMetadataElementFor(metadata_element_name);
+    }
+}
Index: /trunk/gli/src/org/greenstone/gatherer/collection/SaveCollectionTask.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/collection/SaveCollectionTask.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/collection/SaveCollectionTask.java	(revision 8313)
@@ -43,4 +43,5 @@
 import org.greenstone.gatherer.DebugStream;
 import org.greenstone.gatherer.Gatherer;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
 import org.greenstone.gatherer.util.Utility;
 
@@ -66,6 +67,4 @@
     static final private int COPY_COLLECTION      = 4;
     static final private int MAKE_COLLECTION      = 5;
-    static final private int METADATA_SAVED       = 6;
-    static final private int METADATA_XML_SAVED   = 7;
     static final private int OPEN_COLLECTION      = 8;
     static final private int RESTORE_COLLECTION   = 9;
@@ -112,5 +111,5 @@
 	// spd.setMillisToDecideToPopup(100);
 	// spd.setMillisToPopup(100);
-	// 0. Force all remaining metadata.xml files to load.
+
 	// 1. Perform a regular collection save on what we will later refer to as the origin collection.
 	///ystem.err.println("1. Save origin.");
@@ -119,10 +118,4 @@
 	args[0] = collection.getName() + ".col";
 	try {
-	    // Block until all of the metadata files have been read in.
-	    collection.gdm.waitUntilComplete();
-	    // Write out the metadata xml files. The destroy below is meant to do this, but never does.
-	    collection.gdm.save();
-	    // spd.setProgress(getValue(METADATA_XML_SAVED));
-
 	    File file = new File(tmp_loc);
 	    // Create backup
@@ -131,5 +124,5 @@
 		backup.deleteOnExit();
 		if(!file.renameTo(backup)) {
-		    DebugStream.println("Error in CollectionManager.load(): FileRenamedException");
+		    DebugStream.println("Error in SaveCollectionTask.run(): FileRenamedException");
 		}
 	    }
@@ -143,7 +136,6 @@
 	    // spd.setProgress(getValue(COLLECTION_CFG_SAVED));
 
-	    // Write out the metadata files.
-	    Gatherer.c_man.msm.save();
-	    // spd.setProgress(getValue(METADATA_SAVED));
+	    // Write hfiles for the loaded metadata elements into the collection "etc" directory
+	    MetadataSetManager.writeHierarchyFiles(new File(Gatherer.c_man.getCollectionEtc()));
 
 	    collection.setSaved(true);
@@ -307,6 +299,4 @@
 	    return (int)((double)70 * multiplier);
 	case COLLECTION_CFG_SAVED:
-	case METADATA_SAVED:
-	case METADATA_XML_SAVED:
 	    return (int)((double)10 * multiplier);
 	    // Save As
@@ -325,7 +315,2 @@
     }
 }
-
-
-
-
-
Index: /trunk/gli/src/org/greenstone/gatherer/file/FileQueue.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/file/FileQueue.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/file/FileQueue.java	(revision 8313)
@@ -38,4 +38,6 @@
 import org.greenstone.gatherer.gui.LongProgressBar;
 import org.greenstone.gatherer.gui.tree.DragTree;
+import org.greenstone.gatherer.metadata.MetadataValue;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
 import org.greenstone.gatherer.util.ArrayTools;
 import org.greenstone.gatherer.util.DragComponent;
@@ -397,9 +399,7 @@
 					    if(job.type == FileJob.COPY) {
 						// A copy is undone with a delete, so it doesn't really matter where the file originally came from (we're not moving it back there, but into the recycle bin). You may also notice we don't make use of the target parent record. This is because no undo action needs this information, and even if it did it could simply ask for records parent!
-						// Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_COPY, null, null, job.target, directory_record, job.undo);
 					    }
 					    else {
 						// Movements however do need a source and source parent so the file can be moved back to the correct place.
-						// Gatherer.c_man.undo.addUndo(job.ID(), UndoManager.FILE_MOVE, job.source, (FileNode)origin_node.getParent(), job.target, directory_record, job.undo);
 					    }
 					}
@@ -431,33 +431,31 @@
 				    // Show warning.
 				    JOptionPane.showMessageDialog(Gatherer.g_man, Dictionary.get("FileActions.File_Not_Found_Message", source_file.getName()), Dictionary.get("FileActions.File_Not_Found_Title"), JOptionPane.ERROR_MESSAGE);
-				// Force refresh of source folder.
+				    // Force refresh of source folder.
 				    source_model.refresh(new TreePath(((FileNode)origin_node.getParent()).getPath()));
 				}
 				
 				// We can't have been cancelled, and we must have created a new FileNode during the above phase, before we can handle metadata.
-				if(!cancel_action && new_node != null) {
-				/* Time to handle any existing metadata. */
-				// If the directory came from inside our collection...
+				if (!cancel_action && new_node != null) {
+				    /* Time to handle any existing metadata. */
+				    // If the directory came from inside our collection...
 				    if (job.source.toString().equals("Collection")) {
-					///ystem.err.println("Move within collection...");
-					// we just retrieve the metadata attached to the origin node...
-					ArrayList existing_metadata = Gatherer.c_man.getCollection().gdm.getMetadataOnly(source_file);
-					///atherer.println("Existing metadata for " + origin_node + ": " + gdm.toString(existing_metadata));
-					// then assign this remainder to the new folder.
-					///ystem.err.println("New metadata: " + gdm.toString(existing_metadata));
-					Gatherer.c_man.getCollection().gdm.addMetadata(new_node, existing_metadata);
-					existing_metadata = null;
-				    }
-				// If it came from the recycle bin retrieve the metadata from there, once again remembering to account for inherited metadata
-//  				    else if (job.source.toString().equals("Undo")) {
-//  					// Retrieve metadata from the recycle bin
-//  					ArrayList existing_metadata = Gatherer.c_man.undo.getMetadata(source_file);
-//  					// then assign this remainder to the new folder.
-//  					Gatherer.c_man.getCollection().gdm.addMetadata(new_node, existing_metadata);
-//  					existing_metadata = null;
-//  				    }
-				// Otherwise if it came from the workspace use the MSMs parsers to search for folder level metadata (such as metadata.xml or marc records).
+					// System.err.println("Move within collection...");
+
+					// Get the non-folder level metadata assigned to the origin node...
+					ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedDirectlyToFile(source_file);
+					// ...and remove it from the original node and assign it to the new folder
+					for (int i = 0; i < assigned_metadata.size(); i++) {
+					    MetadataValue metadata_value = (MetadataValue) assigned_metadata.get(i);
+					    MetadataXMLFileManager.removeMetadata(origin_node, metadata_value);
+					    MetadataXMLFileManager.addMetadata(new_node, metadata_value);
+					}
+				    }
+				    // If it came from the workspace search for metadata assigned to the file
 				    else if (job.source.toString().equals("Workspace")) {
-					cancel_action = !Gatherer.c_man.getCollection().msm.searchForMetadata(new_node, origin_node, job.folder_level);
+					ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedDirectlyToExternalFile(origin_node.getFile());
+					for (int i = 0; i < assigned_metadata.size(); i++) {
+					    MetadataValue metadata_value = (MetadataValue) assigned_metadata.get(i);
+					    MetadataXMLFileManager.addMetadata(new_node, metadata_value);
+					}	
 				    }
 				}
@@ -475,39 +473,33 @@
 			}
 
-			// If the source is an empty directory or a file. Don't do anything to the root node of a tree.
+			// If the source is a file or an empty directory (but not the root node of a tree)
 			File[] child_list = source_file.listFiles();
-			if(source_file.isFile() || (child_list != null && (child_list.length == 0 || (child_list.length == 1 && child_list[0].getName().equals(Utility.METADATA_XML))) && origin_node.getParent() != null)) {
-			    ///atherer.println("File or empty directory.");
-			    // Delete any metadata.xml still in the directory.
-			    if(child_list != null && child_list.length == 1) {
-				child_list[0].delete();
-			    }
-
-			    ///atherer.println("Origin is file or is directory and is empty.");
-			    // update status area
+			if (source_file.isFile() || (child_list != null && child_list.length == 0 && origin_node.getParent() != null)) {
+			    // System.err.println("Deleting file: " + source_file.getAbsolutePath());
+
+			    // Update status area
 			    String args[] = new String[1];
-			    // args[0] = "" + (queue.size() + 1) + "";
 			    args[0] = Utility.formatPath("FileActions.Deleting", source_file.getAbsolutePath(), file_status.getSize().width);
 			    file_status.setText(Dictionary.get("FileActions.Deleting", args));
-			    args = null;
-
-			    // Remove its metadata
-			    ArrayList metadatum = null;
-//  			    if(job.source == Gatherer.c_man.undo) {
-//  				Gatherer.c_man.undo.addMetadata(target_file, metadatum);
-//  			    }
-//  			    else {
-			    metadatum = Gatherer.c_man.getCollection().gdm.removeMetadata(origin_node.getFile());
-				// }
-			    // determine its parent node
-			    FileNode parent_record = (FileNode)origin_node.getParent();
+
+			    // If it is a metadata.xml file, we must unload it
+			    if (source_file.getName().equals(Utility.METADATA_XML)) {
+				MetadataXMLFileManager.unloadMetadataXMLFile(source_file);
+			    }
+
+			    // Remove the metadata assigned directly to the file
+			    ArrayList assigned_metadata = MetadataXMLFileManager.getMetadataAssignedDirectlyToFile(origin_node.getFile());
+			    for (int i = 0; i < assigned_metadata.size(); i++) {
+				MetadataValue metadata_value = (MetadataValue) assigned_metadata.get(i);
+				MetadataXMLFileManager.removeMetadata(origin_node, metadata_value);
+ 			    }
+
 			    // Remove from model
-			    if(parent_record != null) {
+			    FileNode parent_record = (FileNode) origin_node.getParent();
+			    if (parent_record != null) {
 				SynchronizedTreeModelTools.removeNodeFromParent(source_model, origin_node);
 			    }
-			    // If we are deleting
-			    File recycled_file = null;
-			    FileNode recycled_parent = null;
-			    // delete the source file
+
+			    // Delete the source file
 			    Utility.delete(source_file);
 			}
Index: /trunk/gli/src/org/greenstone/gatherer/gui/EnrichPane.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/EnrichPane.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/EnrichPane.java	(revision 8313)
@@ -37,4 +37,5 @@
 package org.greenstone.gatherer.gui;
 
+
 import java.awt.*;
 import java.awt.event.*;
@@ -42,5 +43,4 @@
 import java.util.*;
 import javax.swing.*;
-import javax.swing.border.*;
 import javax.swing.event.*;
 import javax.swing.table.*;
@@ -51,26 +51,23 @@
 import org.greenstone.gatherer.Gatherer;
 import org.greenstone.gatherer.file.FileNode;
-import org.greenstone.gatherer.gui.table.GTableModel;
-import org.greenstone.gatherer.gui.table.TableCellRenderer;
 import org.greenstone.gatherer.gui.tree.DragTree;
-import org.greenstone.gatherer.msm.ElementWrapper;
-import org.greenstone.gatherer.msm.Metadata;
-import org.greenstone.gatherer.msm.MSMEvent;
-import org.greenstone.gatherer.msm.MSMListener;
-import org.greenstone.gatherer.util.Codec;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataValue;
+import org.greenstone.gatherer.metadata.MetadataValueTableEntry;
+import org.greenstone.gatherer.metadata.MetadataValueTableModel;
+import org.greenstone.gatherer.metadata.MetadataValueTreeModel;
+import org.greenstone.gatherer.metadata.MetadataValueTreeNode;
+import org.greenstone.gatherer.metadata.MetadataXMLFileManager;
 import org.greenstone.gatherer.util.DragGroup;
 import org.greenstone.gatherer.util.PatternTokenizer;
-import org.greenstone.gatherer.util.StaticStrings;
 import org.greenstone.gatherer.util.TreeSynchronizer;
 import org.greenstone.gatherer.util.Utility;
-import org.greenstone.gatherer.valuetree.GValueModel;
-import org.greenstone.gatherer.valuetree.GValueNode;
-/** Provides a view of controls for the editing of metadata. It makes use of several other important components such as a GTree, GTable and GValueTree. While much of the gui content is left to these components, the EnrichPane is resposible for actioning metadata edit requests, listing for mouse clicks within its scope and other data functionality (such as providing a list of the selected files).
-* @author John Thompson, Greenstone Digital Libraries, University of Waikato
-* @version 2.3b
-*/
+
+
+/** Provides a view of controls for the editing of metadata. It makes use of several other important components such as a GTree, GTable and MetadataValueTree. While much of the gui content is left to these components, the EnrichPane is resposible for actioning metadata edit requests, listing for mouse clicks within its scope and other data functionality (such as providing a list of the selected files).
+ */
 public class EnrichPane
     extends JPanel
-    implements ActionListener, ListSelectionListener, TreeSelectionListener, MSMListener {
+    implements ActionListener, TreeSelectionListener {
 
     static private Dimension BUTTON_SIZE = new Dimension(190, 25);
@@ -80,27 +77,28 @@
     static private Dimension TREE_SIZE = new Dimension(250, 500);
     static private int MINIMUM_TABLE_HEADER_SIZE = 15;
-    /** The name of the panel containing the metadata table. */
-    static final private String CARD_ONE  = "Card One";
-    /** The name of the panel containing the 'no file' placeholder for the metadata table. */
-    static final private String CARD_TWO = "Card Two";
-    /** The name of the panel containing the 'no metadata' placeholder for the metadata table. */
-    static final private String CARD_ZERO = "Card Zero";
-    /** The name of the panel containing the placeholder for the value tree. */
-    static final private String TOOLS_OFF = "Tools Off";
-    /** The name of the panel containing the value tree. */
-    static final private String TOOLS_ON  = "Tools On";
-
-    /** The GValueTree graphically shows the available metadata that has been previously assigned, and provides controls for adding, updating and removing metadata, depending on the users selections in the other important components. */
-    private GValueTree tree = null;
-    /** The layout manager used to display either the GTable (when records are selected) or a placeholder panel with the immortal words 'No Record Selected'. */
-    private CardLayout card_layout = null;
-    /** The layout manager used to display either the GValueTree (when records are selected) or a placeholder panel with the immortal words 'No Record Selected'. */
-    private CardLayout card_layout2 = null;
+
+    private MetadataValueTable metadata_value_table = null;
+    /** The layout manager used to display either the MetadataValueTable (when files are selected) or a placeholder panel */
+    private CardLayout metadata_value_table_card_layout = null;
+    /** The name of the panel containing the metadata table */
+    static final private String TABLE_CARD = "";
+    /** The name of the panel containing the "no files selected" placeholder for the metadata table */
+    static final private String TABLE_CARD_NO_FILES_SELECTED = "No files selected";
+    /** The name of the panel containing the "no metadata available" placeholder for the metadata table */
+    static final private String TABLE_CARD_NO_METADATA_AVAILABLE = "No metadata available";
+
+    /** The MetadataValueTree graphically shows the available metadata that has been previously assigned, and provides controls for adding, updating and removing metadata, depending on the user's selections in the other important components. */
+    private MetadataValueTree metadata_value_tree = null;
+    /** The layout manager used to display either the MetadataValueTree (when metadata is selected) or a placeholder panel */
+    private CardLayout metadata_value_tree_card_layout = null;
+    /** The name of the panel containing the metadata value tree */
+    static final private String TREE_CARD = "";
+    /** The name of the panel containing the "no metadata element selected" placeholder for the metadata table */
+    static final private String TREE_CARD_NO_METADATA_ELEMENT_SELECTED  = "No metadata element selected";
+
     /** Used to dynamically filter the collection tree at user request. Note that this is synchronized with the collection tree filter in the Gather view. */
     private Filter filter = null;
-    /** The data model behind the GTable, to which we hold a reference for convenient access. */
-    private GTableModel model = null;
-    /** The currently reported selection. Note that this may actually be incorrect, but if so the changed flag will be set, and the selection will be updated the next time it is needed. */
-    private FileNode records[] = null;
+    /** The currently reported selection. */
+    private FileNode[] file_nodes = null;
     /** The button, which when clicked, adds metadata to the selected records. */
     private JButton add;
@@ -120,23 +118,18 @@
     /** The splitpane dividing the collection tree and the metadata based controls. */
     private JSplitPane external_split;
-    /** A reference to the metadata table, via its superclass. */
-    private JTable table;
     /** The label shown at the top of the metadata table detailing the current selection statistics. */
     private JTextField table_label;
     /** A reference to the collection tree. */
     private DragTree collection_tree;
-    /** The currently selected metadata determined by listening to every second list selection event from the metadata table. */
-    private Metadata selected_metadata;
     /** Provide synchronization between the collection trees in this view and the collection pane view. */
     private TreeSynchronizer tree_sync = null;
+    private boolean metadata_edit_event = false;
+
 
     /** Constructor.
      * @param tree_sync The <strong>TreeSynchronizer</strong> to be used on the collection tree
-     * @see org.greenstone.gatherer.Configuration
-     * @see org.greenstone.gatherer.gui.EnrichPane.GValueTree
      */
     public EnrichPane(TreeSynchronizer tree_sync)
     {
-	this.tree = null;
 	this.tree_sync = tree_sync;
 
@@ -176,5 +169,6 @@
 	Dictionary.registerBoth(expand_for_extracted, "MetaEdit.Expand", "MetaEdit.Expand_Tooltip");
 
-	tree = new GValueTree(CONTROL_SIZE.width, CONTROL_SIZE.height);
+	metadata_value_table = new MetadataValueTable();
+	metadata_value_tree = new MetadataValueTree(CONTROL_SIZE.width, CONTROL_SIZE.height);
     }
 
@@ -182,129 +176,58 @@
     /** Called whenever an action occurs on one of our registered buttons.
      * @param event An <strong>ActionEvent</strong> containing information about the event.
-     * @see org.greenstone.gatherer.collection.CollectionManager
-     * @see org.greenstone.gatherer.gui.EnrichPane.GValueTree
-     * @see org.greenstone.gatherer.gui.table.GTableModel
-     * @see org.greenstone.gatherer.msm.ElementWrapper
-     * @see org.greenstone.gatherer.msm.MetadataSetManager
-     * @see org.greenstone.gatherer.msm.MSMEvent
      */
-    public void actionPerformed(ActionEvent event) {
+    public void actionPerformed(ActionEvent event)
+    {
 	Object esrc = event.getSource();
+
+	// Add button pressed
 	if (esrc == add) {
-	    ElementWrapper element = tree.getSelectedMetadataElement();
-	    String value = tree.getSelectedValue();
-	    (new AppendMetadataTask(element, value)).start();
-	    value = null;
-	    element = null;
-	}
+	    MetadataElement metadata_element = metadata_value_table.getSelectedMetadataElement();
+	    MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue(metadata_value_tree.getSelectedValue());
+	    MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node);
+	    metadata_value.setIsAccumulatingMetadata(true);
+	    (new AppendMetadataTask(metadata_value)).start();
+	}
+
+	// Replace button pressed
 	else if (esrc == update) {
-	    ElementWrapper element = tree.getSelectedMetadataElement();
-	    String value = tree.getSelectedValue();
-	    (new UpdateMetadataTask(element, value)).start();
-	    value = null;
-	    element = null;
-	}
+	    MetadataElement metadata_element = metadata_value_table.getSelectedMetadataElement();
+	    MetadataValueTreeNode metadata_value_tree_node = metadata_element.addMetadataValue(metadata_value_tree.getSelectedValue());
+	    MetadataValue metadata_value = new MetadataValue(metadata_element, metadata_value_tree_node);
+	    metadata_value.setIsAccumulatingMetadata(!metadata_value_table.getSelectedMetadataValueTableEntry().isInheritedMetadata());
+	    (new UpdateMetadataTask(metadata_value)).start();
+	}
+
+	// Remove button pressed
 	else if (esrc == remove) {
 	    (new RemoveMetadataTask()).start();
 	}
+
+	// Expand button pressed
 	else if (esrc == expand) {
 	    EditorDialog ed = new EditorDialog();
-	    String temp = ed.display(tree.getSelectedValue());
-	    if (temp != null) {
-		tree.setSelectedValue(temp);
-	    }
-	}
+	    String new_metadata_value = ed.display(metadata_value_tree.getSelectedValue());
+	    if (new_metadata_value != null) {
+		metadata_value_tree.setSelectedValue(new_metadata_value);
+	    }
+	}
+
+	// Expand button for extracted metadata pressed
 	else if (esrc == expand_for_extracted) {
 	    EditorDialog ed = new EditorDialog();
 	    ed.setEditable(false);
-	    String temp = ed.display(selected_metadata.getValue());
-	}
-	validateControls();
-    }
-
-    private class AppendMetadataTask
-	extends Thread {
-
-	private ElementWrapper element = null;
-	private String value = null;
-
-	private AppendMetadataTask(ElementWrapper element, String raw_value) {
-	    this.element = element;
-	    this.value = raw_value;
-	    // Transform the raw text to be GREENSTONE and DOM compatible - as that will be its next destination immediately after being added to the value model
-	    //this.value = /odec.transform(value, /odec.ENCODE_PATH);
-	    //this.value = /odec.transform(this.value, /odec.REMOVE_SQUARE_BRACKET);
-	    //this.value = /odec.transform(this.value, /odec.TEXT_TO_DOM);
-	}
-
-	public void run() {
-	    // System.err.println("Add metadata - '" + value + "'");
-	    // Check the new metadata is valid
-	    if (records != null && element != null && value != null) {
-		// Check the records, and if they are folders then display the warning.
-		Metadata added_metadata = null;
-		if (!records[0].isLeaf()) {
-		    WarningDialog dialog = new WarningDialog("warning.DirectoryLevelMetadata", true);
-		    if (dialog.display() == JOptionPane.OK_OPTION) {
-			added_metadata = Gatherer.c_man.getCollection().msm.addMetadata(System.currentTimeMillis(), records, element, value);
-		    }
-		    dialog.dispose();
-		    dialog = null;
-		}
-		else {
-		    added_metadata = Gatherer.c_man.getCollection().msm.addMetadata(System.currentTimeMillis(), records, element, value);
-		}
-		model.selectMetadataWhenBuildingComplete(added_metadata);
-	    }
-	}
-    }
-
-    private class UpdateMetadataTask
-	extends Thread {
-
-	private ElementWrapper element;
-	private String value;
-
-	private UpdateMetadataTask(ElementWrapper element, String raw_value) {
-	    this.element = element;
-	    this.value = raw_value;
-	    // Transform the raw text to be DOM compatible - as that will be its next destination immediately after being added to the value model
-	    //this.value = /odec.transform(value, /odec.REMOVE_SQUARE_BRACKET);
-	    //this.value = /odec.transform(this.value, /odec.TEXT_TO_DOM);
-	}
-
-	public void run() {
-	    // You can only update if there is a selected_metadata and
-	    // you have valid values in all fields.
-	    DebugStream.println("Replacing value:");
-	    if (selected_metadata != null && records != null && element != null && value != null) {
-		selected_metadata = Gatherer.c_man.getCollection().msm.updateMetadata(System.currentTimeMillis(), selected_metadata, records, value, MetaEditPrompt.CONFIRM, selected_metadata.isFileLevel());
-	    }
-	    model.selectMetadataWhenBuildingComplete(selected_metadata);
-	}
-    }
-
-    private class RemoveMetadataTask
-	extends Thread {
-
-	private RemoveMetadataTask() {}
-
-	public void run() {
-	    DebugStream.println("Removing value:");
-	    if (selected_metadata != null && records != null) {
-		Gatherer.c_man.getCollection().msm.removeMetadata(System.currentTimeMillis(), selected_metadata, records);
-	    }
-
-	    // Select the closest piece of metadata with the same element name
-	    model.selectClosestMetadataWhenBuildingComplete(selected_metadata);
-	}
-    }
+	    ed.display(metadata_value_table.getSelectedMetadataValueTableEntry().getFullValue());
+	}
+    }
+
 
     /** Some actions can only occur after this panel has been displayed on-screen, so this method is provided to do exactly that. Such actions include the proportioning of the split panes and the setting of table column widths.
-     * @see org.greenstone.gatherer.gui.table.GTableModel
      */
-    public void afterDisplay() {
+    public void afterDisplay()
+    {
 	external_split.setDividerLocation(0.3);
     }
+
+
     /** Called whenever a significant change has occured in the state of the currently loaded collection.
      * @param ready <i>true</i> if there is a collection currently ready to be editing, <i>false</i> otherwise.
@@ -312,30 +235,19 @@
      * @see org.greenstone.gatherer.util.TreeSynchronizer
      */
-    public void collectionChanged(boolean ready) {
+    public void collectionChanged(boolean ready)
+    {
 	if (ready) {
+	    // System.err.println("In collectionChanged(true).");
 	    TreeModel collection_model = Gatherer.c_man.getRecordSet();
-	    //String[] args = new String[1];
-	    //args[0] = Gatherer.c_man.getCollection().getName();
 	    Dictionary.registerText(collection_label, "Collection.Collection");
+
 	    // Update label coloring.
 	    collection_label.setBackground(Configuration.getColor("coloring.collection_heading_background", false));
 	    collection_label.setForeground(Configuration.getColor("coloring.collection_heading_foreground", false));
 	    collection_tree.setModel(collection_model);
+
 	    // Update tree coloring.
 	    collection_tree.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
 	    collection_tree.setForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
-	    // Register our msm dependant components (or correctly their models) with msm.
-	    if (model != null) {
-		// remove the listener first - in case its already present
-		Gatherer.c_man.getCollection().msm.removeMSMListener(model);
-		Gatherer.c_man.getCollection().msm.addMSMListener(model);
-	    }
-	    // register the pane itself as an MSMListener, so if we add a new metadata set, it will immediately show up. - remove itself first just in case
-	    Gatherer.c_man.getCollection().msm.removeMSMListener(this);
-	    Gatherer.c_man.getCollection().msm.addMSMListener(this);
-
-	    // Clear the currently selected metadata element in the table
-	    // This is important so the value tree is refreshed when the collection changes
-	    tree.setSelectedMetadataElement(null);
 	}
 	else {
@@ -350,4 +262,6 @@
 	tree_sync.add(collection_tree);
     }
+
+
     /** Used to create, connect and layout the components to be shown on this control panel.
      * @see org.greenstone.gatherer.Gatherer
@@ -355,9 +269,7 @@
      * @see org.greenstone.gatherer.file.FileOpenActionListener
      * @see org.greenstone.gatherer.gui.Filter
-     * @see org.greenstone.gatherer.gui.GComboBox
-     * @see org.greenstone.gatherer.gui.table.GTableModel
      */
-    public void display() {
-	RightButtonListener right_button_listener = new RightButtonListener();
+    public void display()
+    {
 	// Creation
 	JPanel collection_pane = new JPanel(new BorderLayout());
@@ -367,5 +279,4 @@
 	external_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
 
-	///atherer.println("\tCreating collection_label");
 	collection_label = new JLabel();
 	Dictionary.registerText(collection_label, "Collection.No_Collection");
@@ -375,8 +286,8 @@
 	TreeModel collection_model = Gatherer.c_man.getRecordSet();
 	if (collection_model != null) {
-	    collection_tree = new DragTree("MetaEdit", collection_model, null, false);
+	    collection_tree = new DragTree("Enrich", collection_model, null, false);
 	}
 	else {
-	    collection_tree = new DragTree("MetaEdit", null, false);
+	    collection_tree = new DragTree("Enrich", null, false);
 	}
 	group.add(collection_tree);
@@ -384,10 +295,10 @@
 	collection_tree.putClientProperty("JTree.lineStyle", "Angled");
 	collection_tree.addMouseListener(Gatherer.g_man.foa_listener);
-	collection_tree.addMouseListener(right_button_listener);
+	collection_tree.addMouseListener(new RightButtonListener());
 	collection_tree.addTreeSelectionListener(this);
 	collection_tree.addTreeExpansionListener(Gatherer.g_man.foa_listener);
 	collection_tree.setLargeModel(true);
 	collection_tree.setRootVisible(false);
-	
+
 	KeyListenerImpl key_listener = new KeyListenerImpl();
 	collection_tree.addKeyListener(key_listener);
@@ -398,6 +309,4 @@
 	filter.setEditable(Configuration.getMode() > Configuration.LIBRARIAN_MODE);
 	Dictionary.registerTooltip(filter.getComboBox(), "Collection.Filter_Tooltip");
-
-	// Connection
 
 	// Layout
@@ -432,6 +341,4 @@
 	Dictionary.registerText(table_label, "MetaEdit.No_File");
 
-	card_layout = new CardLayout();
-
 	table_card_pane = new JPanel();
 
@@ -456,43 +363,29 @@
 	JPanel table_pane_one = new JPanel();
 
-	///atherer.println("\tCreating metadata_table");
-	table = new JTable();
-	model = new GTableModel(table);
-	table.setModel(model);
-	table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-	table.getSelectionModel().addListSelectionListener(this);
-	table.setColumnSelectionAllowed(false);
-
-	// The default JTable doesn't quite have the desired properties - when a
-	// table cell is clicked on, the table is scrolled so the cell is as
-	// visible as possible. This means that the left-most cells can become
-	// hidden. To fix this, the MouseInputHandler in BasicTableUI is removed
-	// as a MouseListener on the table, and a very slightly altered copy is
-	// added in its place (TableMouseInputHandler).
-	MouseListener[] mls = table.getMouseListeners();
-	for (int i = 0; i < mls.length; i++) {
-	    // Remove the instances of MouseInputHandler
-	    if (mls[i].toString().startsWith("javax.swing.plaf.basic.BasicTableUI$MouseInputHandler@")) {
-		table.removeMouseListener(mls[i]);
-	    }
-	}
-	// Add the slightly-altered mouse listener
-	table.addMouseListener(new TableMouseInputHandler());
-
-	// We also have to ensure that the table column header hasn't gone on a severe Jenny Craig binge and has somehow lost 7/8th of its component size (15 -> 2 pixels high).
-	JTableHeader table_header = table.getTableHeader();
-	Dimension table_header_preferred_size = table_header.getPreferredSize();
-	if (table_header_preferred_size.height < MINIMUM_TABLE_HEADER_SIZE) {
-	    table_header_preferred_size.setSize(table_header_preferred_size.width, MINIMUM_TABLE_HEADER_SIZE);
-	    table_header.setPreferredSize(table_header_preferred_size);
-	}
-
-	JScrollPane table_scroll = new JScrollPane(table);
+	JScrollPane table_scroll = new JScrollPane(metadata_value_table);
 	table_scroll.getViewport().setBackground(Configuration.getColor("coloring.collection_tree_background", false));
 	table_scroll.setOpaque(true);
 
+	// Create the cards for the metadata value table
+	metadata_value_table_card_layout = new CardLayout();
+
+	table_pane_zero.setLayout(new BorderLayout());
+	table_pane_zero.add(no_file_message, BorderLayout.CENTER);
+
+	table_pane_one.setLayout(new BorderLayout());
+	table_pane_one.add(table_scroll, BorderLayout.CENTER);
+
+	table_pane_two.setLayout(new BorderLayout());
+	table_pane_two.add(no_metadata_message, BorderLayout.CENTER);
+
+	table_card_pane.setLayout(metadata_value_table_card_layout);
+	table_card_pane.add(table_pane_zero, TABLE_CARD_NO_FILES_SELECTED);
+	table_card_pane.add(table_pane_one, TABLE_CARD);
+	table_card_pane.add(table_pane_two, TABLE_CARD_NO_METADATA_AVAILABLE);
+
+	// Create the cards for the metadata value tree
+	metadata_value_tree_card_layout = new CardLayout();
+
 	// Control pane
-	///atherer.println("\tCreating Metadata Controls");
-
 	control_pane = new JPanel();
 	control_pane.setBorder(BorderFactory.createLoweredBevelBorder());
@@ -501,6 +394,4 @@
 	control_pane.setPreferredSize(CONTROL_SIZE);
 
-	card_layout2 = new CardLayout();
-
 	JPanel tools_off_pane = new JPanel();
 
@@ -523,9 +414,9 @@
 
 	tools_on_pane.setLayout(new BorderLayout());
-	tools_on_pane.add(tree, BorderLayout.CENTER);
-
-	control_pane.setLayout(card_layout2);
-	control_pane.add(tools_off_pane, TOOLS_OFF);
-	control_pane.add(tools_on_pane, TOOLS_ON);
+	tools_on_pane.add(metadata_value_tree, BorderLayout.CENTER);
+
+	control_pane.setLayout(metadata_value_tree_card_layout);
+	control_pane.add(tools_off_pane, TREE_CARD_NO_METADATA_ELEMENT_SELECTED);
+	control_pane.add(tools_on_pane, TREE_CARD);
 
 	// Table components
@@ -534,18 +425,4 @@
 	table_title_pane.add(table_label, BorderLayout.CENTER);
 
-	table_pane_zero.setLayout(new BorderLayout());
-	table_pane_zero.add(no_file_message, BorderLayout.CENTER);
-
-	table_pane_one.setLayout(new BorderLayout());
-	table_pane_one.add(table_scroll, BorderLayout.CENTER);
-
-	table_pane_two.setLayout(new BorderLayout());
-	table_pane_two.add(no_metadata_message, BorderLayout.CENTER);
-
-	table_card_pane.setLayout(card_layout);
-	table_card_pane.add(table_pane_zero, CARD_ZERO);
-	table_card_pane.add(table_pane_one, CARD_ONE);
-	table_card_pane.add(table_pane_two, CARD_TWO);
-
 	table_pane.setLayout(new BorderLayout());
 	table_pane.add(table_title_pane, BorderLayout.NORTH);
@@ -563,516 +440,859 @@
     }
 
-    /** Method that is called whenever an element within a set is changed or modified. - needed for MSMListener
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
+
+    /** Called to inform this control panel that it has just gained focus as an effect of the user clicking on its tab.
      */
-    public void elementChanged(MSMEvent event) {}
-
-    /** Ensures a certain tree path is expanded, visible and selected within the collection tree.
-     * @param path The <strong>TreePath</strong> to make visible.
-     * @see org.greenstone.gatherer.gui.tree.DragTree
-     */
-    private void expandPath(TreePath path) {
-	collection_tree.expandPath(path);
-	collection_tree.setSelectionPath(path);
-    }
-    /** Called to inform this control panel that it has just gained focus as an effect of the user clicking on its tab.
-     * @see org.greenstone.gatherer.gui.tree.DragTree
-     */
-    public void gainFocus() {
-	// Use this opportunity to update the table model etc.
-	// Select the first file (if any)
-	if (collection_tree != null && collection_tree.getRowCount() > 0) {
-	    collection_tree.setImmediate(true);
-	    collection_tree.setSelectionRow(0);
-	    collection_tree.setImmediate(false);
-	}
-	else {
-	    // No selection. Reset other components
-	    valueChanged(new TreeSelectionEvent(this, null, false, null, null));
-	}
-
-	// Update the menubars idea of whats been selected
-	if (collection_tree != null) {
-	    if (collection_tree.isSelectionEmpty()) {
-		Gatherer.g_man.menu_bar.setMetaAuditSuffix(null);
-	    }
-	    else {
-		Gatherer.g_man.menu_bar.setMetaAuditSuffix(collection_tree.getSelectionDetails());
-	    }
-	}
-	// Update the meta-audit view to show the current selection, if any.
-	Gatherer.g_man.meta_audit.setRecords(records);
-    }
-
-    /** Retrieve the currently selected records.
-     * @return A <strong>FileNode[]</strong> containing the current, and up to date, selection.
-     */
-    public FileNode[] getSelectedNode() {
-	return records;
-    }
-
-    /** Called whenever the metadata value changes in some way, such as the addition of a new value. - needed for MSMListener
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
-     */
-    public void metadataChanged(MSMEvent event) {}
+    public void gainFocus()
+    {
+	// If there is nothing in the collection tree there is nothing to do
+	if (collection_tree == null || collection_tree.getRowCount() == 0) {
+	    System.err.println("No/empty collection tree... nothing to do.");
+	    return;
+	}
+
+	// Select the first node in the tree if nothing is already selected
+	if (collection_tree.getSelectionPaths() == null) {
+	    System.err.println("Nothing selected... selecting first tree node.");
+ 	    collection_tree.setImmediate(true);
+ 	    collection_tree.setSelectionRow(0);
+ 	    collection_tree.setImmediate(false);
+	}
+
+	// Force all of the controls to be updated
+	valueChanged(new TreeSelectionEvent(this, null, false, null, null));
+    }
+
 
     /** Called whenever the detail mode changes to ensure the filters are at an appropriate level (ie only editable by those that understand regular expression matching)
      * @param mode the mode level as an int
      */
-    public void modeChanged(int mode) {
+    public void modeChanged(int mode)
+    {
 	filter.setEditable(mode > Configuration.LIBRARIAN_MODE);
     }
 
-    /** Method that is called whenever the metadata set collection changes in some way, such as the addition of a new set or the merging of two sets. - needed for MSMListener
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
+
+    /** This method is called whenever the selection within the collection
+     * tree changes. This causes the table to be rebuilt with a new model.
      */
-    public void setChanged(MSMEvent event){
-	// call the collection tree value changed - we need to do the same stuff here
-	valueChanged((TreeSelectionEvent) null);
-    }
-
-    /** This method enables or diables the various controls based upon the state of the system. This method should be called after every change which could affect the GUI.
-     */
-    private void validateControls() {
-	validateControls(false);
-    }
-
-    private void validateControls(boolean update_card) {
-	validateMetadataTable();
-	// Validate card_layout_2
-	// We only ever change tools if the metadata table has finished building or is empty.
-	if (update_card) {
-	    if (selected_metadata == null && model.isBuildingComplete() && model.getRowCount() == 0) {
-		card_layout2.show(control_pane, TOOLS_OFF);
-	    }
-	    else {
-		card_layout2.show(control_pane, TOOLS_ON);
-	    }
-	}
-
-	// Validate the buttons in the lower pane
-	if (selected_metadata == null) {
-	    // Nothing selected
-	    return;
-	}
-
-	// Does the metadata element have no current value?
-	GValueNode value_node = selected_metadata.getValueNode();
-	if (value_node == null) {
-	    // Can only append if something has been entered
-	    add.setEnabled((tree.getSelectedValue().length() > 0));
-	    // Nothing to replace or remove
-	    update.setEnabled(false);
-	    remove.setEnabled(false);
-	}
-
+    public void valueChanged(TreeSelectionEvent event)
+    {
+	// Nothing selected in the collection tree
+	if (collection_tree.getSelectionCount() == 0) {
+	    file_nodes = null;
+
+	    // Update the label to show nothing is selected in the collection tree
+	    Dictionary.registerText(table_label, "MetaEdit.No_File");
+
+	    // Display the "no file selected" card
+	    metadata_value_table_card_layout.show(table_card_pane, TABLE_CARD_NO_FILES_SELECTED);
+	}
+
+	// Some files selected in the collection tree
 	else {
-	    // Check if the text in the value field is the same as the metadata value
-	    if (tree.getSelectedValue().equals(value_node.getFullPath(false))) {
-		// Can't replace
-		update.setEnabled(false);
-		// Adding, however, is dependant on whether the metadata is common or uncommon. If the later then you can append so as to make it common.
-		add.setEnabled(!model.isCommon(selected_metadata));
-	    }
-	    else {
-		// Can append or replace, if something has been entered
-		add.setEnabled((tree.getSelectedValue().length() > 0));
-		update.setEnabled((tree.getSelectedValue().length() > 0));
-	    }
-
-	    // Can only remove if the metadata is file level
-	    if (selected_metadata != null) {  // Shouldn't be necessary, but is
-		remove.setEnabled(selected_metadata.isFileLevel());
-	    }
-	}
-    }
-
-    /** Validate the metadata table area, and if no metadata is available display the no metadata panel. */
-    public void validateMetadataTable() {
-	// Validate card_layout
-	if (records == null) {
-	    card_layout.show(table_card_pane, CARD_ZERO);
-	} else if (model.getRowCount() == 0) {
-	    card_layout.show(table_card_pane, CARD_TWO);
-	} else {
-	    card_layout.show(table_card_pane, CARD_ONE);
-	}
-    }
-
-    /** Another in a long list of listeners, this one is called whenever the
-     * selection within the JTable changes. When it does we load the new data
-     * and set the selected_metadata if applicable (ie the metadata is non-
-     * empty).
-     * @param event The <strong>ListSelectionEvent</strong> which contains all the information about the event that has been fired.
-     * @see org.greenstone.gatherer.gui.table.GTableModel
-     * @see org.greenstone.gatherer.gui.EnrichPane.GValueTree
-     */
-    public void valueChanged(ListSelectionEvent event) {
-	// We only want to handle one event per selection, so wait for the value to stabilise
-	ListSelectionModel lsm = table.getSelectionModel();
-	if (lsm.getValueIsAdjusting() == false) {
-	    // We have a SINGLE_SELECTION model set so there is at most one
-	    // selection. Get the offending row.
-	    int selected = table.getSelectedRow();
-	    selected_metadata = model.getMetadataAtRow(selected);
-	    if (selected_metadata != null) { // Check something is selected.
-		tree.setSelectedMetadataElement(selected_metadata.getElement());
-		GValueNode value_node = selected_metadata.getValueNode();
-		if (value_node != null) {
-		    tree.setSelectedValue(value_node.getFullPath(true));
-		}
-		else {
-		    tree.setSelectedValue("");
-		}
-	    }
-	    validateControls(true);
-	}
-    }
-
-    /** Called whenever the value tree of an metadata element changes in some way, such as the addition of a new value. - needed for MSMListener
-     * @param event A <strong>MSMEvent</strong> containing details of the event that caused this message to be fired.
-     */
-    public void valueChanged(MSMEvent event) {}
-
-    /** This method is called whenever the selection within the collection
-     * tree changes. This causes the table to be rebuilt with a new model
-     * @param event A <strong>TreeSelectionEvent</strong> containing information about the event.
-     * @see org.greenstone.gatherer.Gatherer
-     * @see org.greenstone.gatherer.file.FileNode
-     * @see org.greenstone.gatherer.gui.GUIManager
-     * @see org.greenstone.gatherer.gui.MenuBar
-     * @see org.greenstone.gatherer.gui.table.GTableModel
-     * @see org.greenstone.gatherer.msm.MetadataSetManager
-     * @see org.greenstone.gatherer.gui.tree.DragTree
-     * @see org.greenstone.gatherer.util.ArrayTools
-     */
-    public void valueChanged(TreeSelectionEvent event) {
-	///ystem.err.println("\n(MEP) valueChanged(TreeSelectionEvent)...");
-
-	// Don't bother if this isn't the selected view
-	// if (Gatherer.g_man.getSelectedView() != this) {
-	//     return;
-	// }
-
-	if (collection_tree.getSelectionCount() > 0) {
-	    records = null;
 	    TreePath paths[] = collection_tree.getSelectionPaths();
-	    records = new FileNode[paths.length];
+	    file_nodes = new FileNode[paths.length];
 	    for (int i = 0; i < paths.length; i++) {
-		FileNode record = (FileNode) paths[i].getLastPathComponent();
-		records[i] = record;
-	    }
-
-	    // Remember the previous selection so we can select it again later
-	    Metadata previous_selection = selected_metadata;
-
+		file_nodes[i] = (FileNode) paths[i].getLastPathComponent();
+	    }
+
+	    // Update the label to show what is selected in the collection tree
 	    table_label.setText(collection_tree.getSelectionDetails());
-
-	    // Remove old model from msm
-	    Gatherer.c_man.getCollection().msm.removeMSMListener(model);
-	    // Create new model
-	    model = new GTableModel(table, records);
-	    table.setModel(model);
-
-	    // Select the closest piece of metadata in the new file
-	    model.selectClosestMetadataWhenBuildingComplete(previous_selection);
-	}
-	else {
-	    records = null;
-	    Dictionary.registerText(table_label, "MetaEdit.No_File");
-
-	    // Remove old model from msm
-	    if (Gatherer.c_man.ready()) {
-		Gatherer.c_man.getCollection().msm.removeMSMListener(model);
-	    }
-	    // Create new model
-	    model = new GTableModel(table);
-	    table.setModel(model);
-	}
-
-	if (table != null) {
-	    table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
-	    Dimension table_size = table.getPreferredSize();
-	    TableColumnModel column_model = table.getColumnModel();
+	}
+
+	// Update the metadata value table (and consequently, the metadata value tree)
+	metadata_value_table.rebuild();
+
+// 	// Update the meta-audit view to show the current selection, if any.
+// 	Gatherer.g_man.meta_audit.setRecords(file_nodes);
+    }
+
+
+    private class AppendMetadataTask
+	extends Thread
+    {
+	private MetadataValue metadata_value = null;
+
+	private AppendMetadataTask(MetadataValue metadata_value)
+	{
+	    this.metadata_value = metadata_value;
+	}
+
+	public void run()
+	{
+	    if (file_nodes == null || metadata_value == null) {
+		return;
+	    }
+
+	    // If we're adding metadata to folders display the warning
+	    if (!file_nodes[0].isLeaf()) {
+		WarningDialog dialog = new WarningDialog("warning.DirectoryLevelMetadata", true);
+		int dialog_result = dialog.display();
+		dialog.dispose();
+
+		if (dialog_result != JOptionPane.OK_OPTION) {
+		    return;
+		}
+	    }
+
+	    // Edit metadata.xml files to add the metadata
+	    MetadataXMLFileManager.addMetadata(file_nodes, metadata_value);
+
+	    // Update the metadata value table and tree
+	    metadata_edit_event = true;
+	    metadata_value_table.rebuild();
+	    metadata_edit_event = false;
+	}
+    }
+
+
+    private class UpdateMetadataTask
+	extends Thread
+    {
+	private MetadataValue metadata_value = null;
+
+	private UpdateMetadataTask(MetadataValue metadata_value)
+	{
+	    this.metadata_value = metadata_value;
+	}
+
+	public void run()
+	{
+	    MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table.getSelectedMetadataValueTableEntry();
+	    if (selected_metadata_value_table_entry == null || file_nodes == null || metadata_value == null) {
+		return;
+	    }
+
+	    // Edit metadata.xml files to replace the metadata
+	    MetadataXMLFileManager.removeMetadata(file_nodes, selected_metadata_value_table_entry);
+	    MetadataXMLFileManager.addMetadata(file_nodes, metadata_value);
+
+	    // Update the metadata value table and tree
+	    metadata_edit_event = true;
+	    metadata_value_table.rebuild();
+	    metadata_edit_event = false;
+	}
+    }
+
+
+    private class RemoveMetadataTask
+	extends Thread
+    {
+	public void run()
+	{
+	    MetadataValueTableEntry selected_metadata_value_table_entry = metadata_value_table.getSelectedMetadataValueTableEntry();
+	    if (selected_metadata_value_table_entry == null || file_nodes == null) {
+		return;
+	    }
+
+	    // Edit metadata.xml files to remove the metadata
+	    MetadataXMLFileManager.removeMetadata(file_nodes, selected_metadata_value_table_entry);
+
+	    // Update the metadata value table and tree
+	    metadata_edit_event = true;
+	    metadata_value_table.rebuild();
+	    metadata_edit_event = false;
+	}
+    }
+
+
+    private class MetadataValueTable
+	extends JTable
+    {
+	private MetadataValueTableModel metadata_value_table_model = null;
+	/** The currently selected metadata value table entry */
+	private MetadataValueTableEntry selected_metadata_value_table_entry = null;
+
+
+	public MetadataValueTable()
+	{
+	    metadata_value_table_model = new MetadataValueTableModel();
+	    setModel(metadata_value_table_model);
+
+	    // We allow only one row to be selected at a time
+	    setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+	    getSelectionModel().addListSelectionListener(new MetadataValueTableListSelectionListener());
+
+	    // The default JTable doesn't quite have the desired properties - when a
+	    // table cell is clicked on, the table is scrolled so the cell is as
+	    // visible as possible. This means that the left-most cells can become
+	    // hidden. To fix this, the MouseInputHandler in BasicTableUI is removed
+	    // as a MouseListener on the table, and a very slightly altered copy is
+	    // added in its place (TableMouseInputHandler).
+	    MouseListener[] mls = getMouseListeners();
+	    for (int i = 0; i < mls.length; i++) {
+		// Remove the instances of MouseInputHandler
+		if (mls[i].toString().startsWith("javax.swing.plaf.basic.BasicTableUI$MouseInputHandler@")) {
+		    removeMouseListener(mls[i]);
+		}
+	    }
+	    // Add the slightly-altered mouse listener
+	    addMouseListener(new TableMouseInputHandler());
+
+	    // We also have to ensure that the table column header hasn't gone on a severe Jenny Craig binge and has somehow lost 7/8th of its component size
+	    JTableHeader table_header = getTableHeader();
+	    Dimension table_header_preferred_size = table_header.getPreferredSize();
+	    if (table_header_preferred_size.height < MINIMUM_TABLE_HEADER_SIZE) {
+		table_header_preferred_size.setSize(table_header_preferred_size.width, MINIMUM_TABLE_HEADER_SIZE);
+		table_header.setPreferredSize(table_header_preferred_size);
+	    }
+
+	    // Set the table columns as we want them
+	    setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+	    Dimension table_size = getPreferredSize();
+	    TableColumnModel column_model = getColumnModel();
 
 	    TableColumn inherited_column = column_model.getColumn(0);
 	    inherited_column.setPreferredWidth(20);
-	    inherited_column.setCellRenderer(new TableCellRenderer(model));
+	    inherited_column.setCellRenderer(new MetadataValueTableCellRenderer(metadata_value_table_model));
 
 	    TableColumn element_column = column_model.getColumn(1);
 	    element_column.setPreferredWidth((TABLE_SIZE.width / 4) - 15);
-	    element_column.setCellRenderer(new TableCellRenderer(model));
+	    element_column.setCellRenderer(new MetadataValueTableCellRenderer(metadata_value_table_model));
 
 	    TableColumn value_column = column_model.getColumn(2);
 	    value_column.setPreferredWidth(((3 * TABLE_SIZE.width) / 4) - 30);
-	    value_column.setCellRenderer(new TableCellRenderer(model));
-	}
-	table.doLayout();
-	validateControls();
-    }
-
-
-    /** A direct copy of javax.swing.plaf.basic.BasicTableUI$MouseInputHandler, except for one change in adjustFocusAndSelection(). The purpose of this change is to always keep the left-most cells of the table row selected visible. */
-    private class TableMouseInputHandler implements MouseInputListener
+	    value_column.setCellRenderer(new MetadataValueTableCellRenderer(metadata_value_table_model));
+	}
+
+
+ 	public MetadataElement getSelectedMetadataElement()
+ 	{
+ 	    return selected_metadata_value_table_entry.getMetadataElement();
+ 	}
+
+
+	public MetadataValueTableEntry getSelectedMetadataValueTableEntry()
+	{
+	    return selected_metadata_value_table_entry;
+	}
+
+
+	public boolean isSelectedMetadataValueTableEntryCommon()
+	{
+	    return metadata_value_table_model.isCommon(selected_metadata_value_table_entry);
+	}
+
+
+	public void rebuild()
+	{
+	    // Remember the current metadata element selection so we can select it again later
+	    MetadataValueTableEntry previously_selected_metadata_value_table_entry = selected_metadata_value_table_entry;
+
+	    // We don't want a lot of ListSelectionEvents while the table is rebuilding
+	    clearSelection();
+
+	    // Rebuild the metadata value table model
+	    metadata_value_table_model.rebuild(file_nodes);
+
+	    // If the metadata value table is empty there isn't much to do
+	    if (metadata_value_table_model.getRowCount() == 0) {
+		// ...except display the "no metadata available" card, unless no files are selected
+		if (file_nodes != null) {
+		    metadata_value_table_card_layout.show(table_card_pane, TABLE_CARD_NO_METADATA_AVAILABLE);
+		}
+		return;
+	    }
+
+	    // Display the card with the metadata value table
+	    metadata_value_table_card_layout.show(table_card_pane, TABLE_CARD);
+
+	    // If there was no previous selection then we're done
+	    if (previously_selected_metadata_value_table_entry == null) {
+		return;
+	    }
+
+ 	    // Look for an exact match
+ 	    for (int i = 0; i < metadata_value_table_model.getRowCount(); i++) {
+ 		MetadataValueTableEntry metadata_value_table_entry = metadata_value_table_model.getMetadataValueTableEntry(i);
+ 		int c = metadata_value_table_entry.compareTo(previously_selected_metadata_value_table_entry);
+
+ 		if (c == 0) {
+		    // Select this row and we're done
+		    addRowSelectionInterval(i, i);
+ 		    return;
+ 		}
+
+ 		if (c < 0) {
+ 		    // Not in the list
+ 		    break;
+ 		}
+ 	    }
+
+ 	    // Select the first entry with the same metadata element
+ 	    MetadataElement previously_selected_metadata_element = previously_selected_metadata_value_table_entry.getMetadataElement();
+ 	    for (int i = 0; i < metadata_value_table_model.getRowCount(); i++) {
+ 		MetadataElement metadata_element = metadata_value_table_model.getMetadataValueTableEntry(i).getMetadataElement();
+ 		if (metadata_element.equals(previously_selected_metadata_element)) {
+		    // Select this row and we're done
+		    addRowSelectionInterval(i, i);
+ 		    return;
+ 		}
+ 	    }
+
+ 	    // All else has failed, so just select the first row in the table
+	    addRowSelectionInterval(0, 0);
+	}
+
+
+	private class MetadataValueTableListSelectionListener
+	    implements ListSelectionListener
+	{
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		// We only want to handle one event per selection, so wait for the value to stabilise
+		if (getSelectionModel().getValueIsAdjusting() == true) {
+		    return;
+		}
+
+		// System.err.println("In MetadataValueTableListSelectionListener.valueChanged()...");
+
+ 		selected_metadata_value_table_entry = null;
+ 		MetadataElement selected_metadata_element = null;
+ 		String selected_metadata_value = "";
+
+ 		// We have a SINGLE_SELECTION model set so there is at most one selection
+ 		int selected_row = getSelectedRow();
+ 		if (selected_row >= 0) {
+ 		    selected_metadata_value_table_entry = metadata_value_table_model.getMetadataValueTableEntry(selected_row);
+ 		    selected_metadata_element = selected_metadata_value_table_entry.getMetadataElement();
+ 		    MetadataValueTreeNode metadata_value_tree_node = selected_metadata_value_table_entry.getMetadataValueTreeNode();
+ 		    if (metadata_value_tree_node != null) {
+ 			selected_metadata_value = metadata_value_tree_node.getFullValue();
+ 		    }
+ 		}
+
+		// Update the metadata value tree
+		metadata_value_tree.rebuild(selected_metadata_element, selected_metadata_value);
+	    }
+	}
+
+
+	/** A direct copy of javax.swing.plaf.basic.BasicTableUI$MouseInputHandler, except for one change in adjustFocusAndSelection(). The purpose of this change is to always keep the left-most cells of the table row selected visible. */
+	private class TableMouseInputHandler implements MouseInputListener
+	{
+	    // Component receiving mouse events during editing.
+	    // May not be editorComponent.
+	    private Component dispatchComponent;
+	    private boolean selectedOnPress;
+
+	    //  The Table's mouse listener methods.
+
+	    public void mouseClicked(MouseEvent e) {}
+
+	    private void setDispatchComponent(MouseEvent e) {
+		Component editorComponent = getEditorComponent();
+		Point p = e.getPoint();
+		Point p2 = SwingUtilities.convertPoint(metadata_value_table, p, editorComponent);
+		dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent,
+									 p2.x, p2.y);
+	    }
+
+	    private boolean repostEvent(MouseEvent e) {
+		// Check for isEditing() in case another event has
+		// caused the editor to be removed. See bug #4306499.
+		if (dispatchComponent == null || !isEditing()) {
+		    return false;
+		}
+		MouseEvent e2 = SwingUtilities.convertMouseEvent(metadata_value_table, e, dispatchComponent);
+		dispatchComponent.dispatchEvent(e2);
+		return true;
+	    }
+
+	    private void setValueIsAdjusting(boolean flag) {
+		getSelectionModel().setValueIsAdjusting(flag);
+		getColumnModel().getSelectionModel().setValueIsAdjusting(flag);
+	    }
+
+	    private boolean shouldIgnore(MouseEvent e) {
+		return e.isConsumed() || (!(SwingUtilities.isLeftMouseButton(e) && isEnabled()));
+	    }
+
+	    public void mousePressed(MouseEvent e) {
+		if (e.isConsumed()) {
+		    selectedOnPress = false;
+		    return;
+		}
+		selectedOnPress = true;
+		adjustFocusAndSelection(e);
+	    }
+
+	    void adjustFocusAndSelection(MouseEvent e) {
+		if (shouldIgnore(e)) {
+		    return;
+		}
+
+		Point p = e.getPoint();
+		int row = rowAtPoint(p);
+		int column = columnAtPoint(p);
+		// The autoscroller can generate drag events outside the Table's range.
+		if ((column == -1) || (row == -1)) {
+		    return;
+		}
+
+		if (editCellAt(row, column, e)) {
+		    setDispatchComponent(e);
+		    repostEvent(e);
+		}
+		else if (isRequestFocusEnabled()) {
+		    requestFocus();
+		}
+
+		CellEditor editor = getCellEditor();
+		if (editor == null || editor.shouldSelectCell(e)) {
+		    boolean adjusting = (e.getID() == MouseEvent.MOUSE_PRESSED) ? true : false;
+		    setValueIsAdjusting(adjusting);
+
+		    // Special code for clicking the first column (folder-level metadata)
+		    if (column == 0) {
+			selected_metadata_value_table_entry = metadata_value_table_model.getMetadataValueTableEntry(row);
+
+			// If this metadata is inherited, switch to the folder it came from
+			if (selected_metadata_value_table_entry.isInheritedMetadata()) {
+			    File folder_metadata_inherited_from = selected_metadata_value_table_entry.getFolderMetadataInheritedFrom();
+			    if (folder_metadata_inherited_from != null) {
+				collection_tree.setSelection(folder_metadata_inherited_from);
+			    }
+			}
+
+			changeSelection(row, 0, e.isControlDown(), e.isShiftDown());
+		    }
+		    else {
+			changeSelection(row, 1, e.isControlDown(), e.isShiftDown());
+		    }
+		}
+	    }
+
+	    public void mouseReleased(MouseEvent e) {
+		if (selectedOnPress) {
+		    if (shouldIgnore(e)) {
+			return;
+		    }
+
+		    repostEvent(e);
+		    dispatchComponent = null;
+		    setValueIsAdjusting(false);
+		} else {
+		    adjustFocusAndSelection(e);
+		}
+	    }
+
+
+	    public void mouseEntered(MouseEvent e) {}
+
+	    public void mouseExited(MouseEvent e) {}
+
+	    //  The Table's mouse motion listener methods.
+
+	    public void mouseMoved(MouseEvent e) {}
+
+	    public void mouseDragged(MouseEvent e) {
+		if (shouldIgnore(e)) {
+		    return;
+		}
+
+		repostEvent(e);
+
+		CellEditor editor = getCellEditor();
+		if (editor == null || editor.shouldSelectCell(e)) {
+		    Point p = e.getPoint();
+		    int row = rowAtPoint(p);
+		    int column = columnAtPoint(p);
+		    // The autoscroller can generate drag events outside the Table's range.
+		    if ((column == -1) || (row == -1)) {
+			return;
+		    }
+		    changeSelection(row, column, false, true);
+		}
+	    }
+	}
+    }
+
+
+    /**
+     * This class is a little bit complex, a little bit subtle, and a little bit odd.
+     * The strange interaction model is due to the fact that it is very tightly
+     * coupled to the EnrichPane.
+     *
+     * The interaction is complex because there are three separate controls that the
+     * user may interact with, each of which can affect the other two. The three
+     * controls are:
+     *   - The "assigned metadata" table, at the top right of the meta edit pane.
+     *   - The "metadata value" text field, where users can type in new values.
+     *   - The "metadata value tree", which shows other values that have been
+     *     assigned to the selected metadata element.
+     *
+     * The interactions are:
+     *   - The "assigned metadata" table
+     *     Users may select one (and only one) row in this table. Selecting a row
+     *     chooses one metadata element. The text field will be set to the current
+     *     value of the metadata element. This value will also be selected in the
+     *     metadata value tree.
+     *
+     *   - The "metadata value" text field
+     *     If the value the user has typed in this is a prefix of an entry in the
+     *     value tree, this value will be selected in the value tree. In this case,
+     *     pressing "Tab" will complete the value (ie. make the value in the text
+     *     field the same as the value in the tree). This is to allow users to
+     *     quickly and easily assign existing metadata values to new documents.
+     *
+     *   - The "metadata value tree"
+     *     Selecting a value in the tree will set the text field to this value.
+     */
+    private class MetadataValueTree
+	extends JPanel
+	implements TreeSelectionListener
     {
-        // Component receiving mouse events during editing.
-        // May not be editorComponent.
-        private Component dispatchComponent;
-	private boolean selectedOnPress;
-
-	//  The Table's mouse listener methods.
-
-        public void mouseClicked(MouseEvent e) {}
-
-        private void setDispatchComponent(MouseEvent e) {
-            Component editorComponent = table.getEditorComponent();
-            Point p = e.getPoint();
-            Point p2 = SwingUtilities.convertPoint(table, p, editorComponent);
-            dispatchComponent = SwingUtilities.getDeepestComponentAt(editorComponent,
-								     p2.x, p2.y);
-        }
-
-        private boolean repostEvent(MouseEvent e) {
-	    // Check for isEditing() in case another event has
-	    // caused the editor to be removed. See bug #4306499.
-            if (dispatchComponent == null || !table.isEditing()) {
-                return false;
-            }
-            MouseEvent e2 = SwingUtilities.convertMouseEvent(table, e, dispatchComponent);
-            dispatchComponent.dispatchEvent(e2);
-            return true;
-        }
-
-        private void setValueIsAdjusting(boolean flag) {
-            table.getSelectionModel().setValueIsAdjusting(flag);
-            table.getColumnModel().getSelectionModel().setValueIsAdjusting(flag);
-        }
-
-	private boolean shouldIgnore(MouseEvent e) {
-	    return e.isConsumed() || (!(SwingUtilities.isLeftMouseButton(e) && table.isEnabled()));
-	}
-
-        public void mousePressed(MouseEvent e) {
-	    if (e.isConsumed()) {
-		selectedOnPress = false;
-		return;
-	    }
-	    selectedOnPress = true;
-	    adjustFocusAndSelection(e);
-	}
-
-	void adjustFocusAndSelection(MouseEvent e) {
-	    if (shouldIgnore(e)) {
-	        return;
-	    }
-
-            Point p = e.getPoint();
-            int row = table.rowAtPoint(p);
-            int column = table.columnAtPoint(p);
-	    // The autoscroller can generate drag events outside the Table's range.
-            if ((column == -1) || (row == -1)) {
-                return;
-            }
-
-            if (table.editCellAt(row, column, e)) {
-                setDispatchComponent(e);
-                repostEvent(e);
-            }
-	    else if (table.isRequestFocusEnabled()) {
-                table.requestFocus();
-	    }
-
-            CellEditor editor = table.getCellEditor();
-            if (editor == null || editor.shouldSelectCell(e)) {
-		boolean adjusting = (e.getID() == MouseEvent.MOUSE_PRESSED) ? true : false;
-                setValueIsAdjusting(adjusting);
-
-		// Special code for clicking the first column (folder-level metadata)
-		if (column == 0) {
-		    selected_metadata = model.getMetadataAtRow(row);
-
-		    // If this metadata is inherited, switch to the folder it came from
-		    if (!selected_metadata.isFileLevel()) {
-			File folder_inherited_from = selected_metadata.getFile();
-			if (folder_inherited_from != null) {
-			    collection_tree.setSelection(folder_inherited_from);
+	private boolean ignore_tree_selection_event = false;
+	private boolean manual_text_edit_event = false;
+	private CardLayout card_layout;
+	private String card_showing = null;
+	/** The metadata element that is currently selected. */
+	private MetadataElement selected_metadata_element = null;
+	private JTextArea extracted_message;
+	private JTextField value;
+	private JTree tree;
+
+	static final private String NONE = "None";
+	static final private String TREE = "Tree";
+
+
+	public MetadataValueTree(int width, int height)
+	{
+	    super();
+
+	    setFont(Configuration.getFont("general.font", false));
+	    setPreferredSize(new Dimension(width, height));
+
+	    JPanel metadata_pane = new JPanel();
+
+	    JPanel value_pane = new JPanel();
+	    JLabel value_label = new JLabel();
+	    Dictionary.registerText(value_label, "MetaEdit.Value");
+
+	    JPanel value_field_pane = new JPanel();
+	    value = new JTextField();
+	    value.setBackground(Configuration.getColor("coloring.editable_background", false));
+	    value.setForeground(Configuration.getColor("coloring.editable_foreground", false));
+	    value.setPreferredSize(new Dimension(413, 24));
+	    value.getDocument().addDocumentListener(new DocumentListenerImpl());
+	    value.addKeyListener(new MetadataFieldListener());
+	    value.setFocusTraversalKeysEnabled(false);
+	    Dictionary.setTooltip(value, "MetaEdit.Value_Field_Tooltip");
+
+	    JPanel button_pane = new JPanel();
+
+	    JPanel tree_pane = new JPanel();
+	    JLabel tree_label = new JLabel();
+	    Dictionary.registerText(tree_label, "MetaEdit.Tree");
+
+	    tree = new JTree();
+	    tree.addTreeSelectionListener(this);
+	    tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+	    tree.setRootVisible(false);
+	    tree.putClientProperty("JTree.lineStyle", "Angled");
+
+	    JPanel extracted_pane = new JPanel();
+	    JPanel extracted_header_pane = new JPanel();
+	    extracted_message = new JTextArea("");
+	    extracted_message.setEditable(false);
+	    extracted_message.setLineWrap(true);
+	    extracted_message.setOpaque(false);
+	    extracted_message.setWrapStyleWord(true);
+
+	    card_layout = new CardLayout();
+
+	    // Layout
+	    value_field_pane.setBorder(BorderFactory.createEmptyBorder(0,5,0,5));
+	    value_field_pane.setLayout(new BorderLayout(0, 0));
+	    value_field_pane.add(value, BorderLayout.CENTER);
+
+	    button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
+	    button_pane.setLayout(new GridLayout());
+	    button_pane.add(add);
+	    button_pane.add(update);
+	    button_pane.add(remove);
+
+	    value_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
+	    value_pane.setLayout(new BorderLayout());
+	    value_pane.add(value_label, BorderLayout.WEST);
+	    value_pane.add(value_field_pane, BorderLayout.CENTER);
+	    value_pane.add(expand, BorderLayout.EAST);
+	    value_pane.add(button_pane, BorderLayout.SOUTH);
+
+	    tree_pane.setLayout(new BorderLayout());
+	    tree_pane.add(tree_label, BorderLayout.NORTH);
+	    tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
+
+	    metadata_pane.setLayout(new BorderLayout());
+	    metadata_pane.add(value_pane, BorderLayout.NORTH);
+	    metadata_pane.add(tree_pane, BorderLayout.CENTER);
+
+	    extracted_header_pane.setLayout(new BorderLayout());
+	    extracted_header_pane.add(expand_for_extracted, BorderLayout.EAST);
+
+	    extracted_pane.setBorder(BorderFactory.createEmptyBorder(0,10,25,0));
+	    extracted_pane.setLayout(new BorderLayout());
+	    extracted_pane.add(extracted_header_pane, BorderLayout.NORTH);
+	    extracted_pane.add(extracted_message, BorderLayout.CENTER);
+
+	    this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+	    this.setLayout(card_layout);
+	    this.add(metadata_pane, TREE);
+	    this.add(extracted_pane, NONE);
+	    card_showing = TREE;
+	}
+
+
+	/** Returns a TreePath for the node most closely matching the metadata value. */
+	private TreePath getClosestPath(String val)
+	{
+	    // Start at the root of the tree
+	    MetadataValueTreeNode tree_node = (MetadataValueTreeNode) tree.getModel().getRoot();
+
+	    // Separate hierarchical values
+	    PatternTokenizer tokenizer = new PatternTokenizer(val, MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN);
+	    while (tokenizer.hasMoreTokens()) {
+		String token = tokenizer.nextToken();
+
+		// All components except the last must match exactly
+		if (tokenizer.hasMoreTokens()) {
+		    for (int i = 0; i < tree_node.getChildCount(); i++) {
+			MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
+			if (child_node.getValue().equals(token)) {
+			    // The matching node has been found, so move onto the next token
+			    tree_node = child_node;
+			    break;
 			}
 		    }
-
-		    table.changeSelection(row, 0, e.isControlDown(), e.isShiftDown());
-		}
+		}
+
+		// The last component may match partially
 		else {
-		    table.changeSelection(row, 1, e.isControlDown(), e.isShiftDown());
-		}
-	    }
-        }
-
-        public void mouseReleased(MouseEvent e) {
-	    if (selectedOnPress) {
-		if (shouldIgnore(e)) {
+		    for (int i = 0; i < tree_node.getChildCount(); i++) {
+			MetadataValueTreeNode child_node = (MetadataValueTreeNode) tree_node.getChildAt(i);
+			if (child_node.getValue().startsWith(token)) {
+			    // The closest node has been found, so return its path
+			    return new TreePath(child_node.getPath());
+			}
+		    }
+
+		    // Not even a partial match
+		    return null;
+		}
+	    }
+
+	    // If nothing else, return the path of the root node
+	    return new TreePath(tree_node.getPath());
+	}
+
+
+	public String getSelectedValue()
+	{
+	    return value.getText().replaceAll("\\\\", MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN);
+	}
+
+
+	public void rebuild(MetadataElement metadata_element, String metadata_value)
+	{
+	    // System.err.println("In MetadataValueTree.rebuild()...");
+
+	    // Clear selection
+	    if (metadata_element == null) {
+		if (metadata_edit_event == false) {
+		    System.err.println("Clearing selection...");
+		    selected_metadata_element = null;
+		    validateDisplay();
+		}
+		return;
+	    }
+
+	    // Reload the value tree model if the selected metadata element has changed
+	    if (selected_metadata_element != metadata_element) {
+		selected_metadata_element = metadata_element;
+		tree.setModel(selected_metadata_element.getMetadataValueTreeModel());
+	    }
+
+	    validateDisplay();
+
+	    setSelectedValue(metadata_value);
+	}
+
+
+	/** This function is copied from JTree::setPathToVisible(), and modified so tree rows
+	    are always shown flushed left. Note: doesn't do accessibleContext stuff. */
+	private void scrollTreePathToVisible(TreePath path)
+	{
+	    if (path != null) {
+		tree.makeVisible(path);
+
+		Rectangle bounds = tree.getPathBounds(path);
+		if (bounds != null) {
+		    bounds.width += bounds.x;
+		    bounds.x = 0;
+		    tree.scrollRectToVisible(bounds);
+		}
+	    }
+	}
+
+
+	/** Sets the value in the text field. */
+	private void setSelectedValue(String metadata_value)
+	{
+	    // Setting the text of the field causes the DocumentListener to be notified, and
+	    //   updating the tree is handled there (DocumentListenerImpl::validate())
+	    if (!card_showing.equals(NONE)) {
+		manual_text_edit_event = metadata_value.equals("");  // Set to false unless val == ""
+		value.setText(metadata_value);
+		manual_text_edit_event = true;
+	    }
+	}
+
+
+	private void validateDisplay()
+	{
+	    // If no metadata is selected in the metadata value table, display "no metadata element selected" card
+	    if (file_nodes == null || selected_metadata_element == null) {
+		metadata_value_tree_card_layout.show(control_pane, TREE_CARD_NO_METADATA_ELEMENT_SELECTED);
+	    }
+
+	    // Otherwise, display the card with the metadata value tree
+	    else {
+		metadata_value_tree_card_layout.show(control_pane, TREE_CARD);
+
+		// Special case the extracted metadata set
+		if (selected_metadata_element.getNamespace().equals(Utility.EXTRACTED_METADATA_NAMESPACE)) {
+		    // Display the panel showing the "you cannot edit this metadata" message
+		    String[] args = new String[1];
+		    args[0] = selected_metadata_element.getFullName();
+		    Dictionary.registerText(extracted_message, "MetaEdit.AutoMessage", args);
+		    card_layout.show(this, NONE);
+		    card_showing = NONE;
+		}
+		else {
+		    // Display the panel for viewing and assigning metadata
+		    card_layout.show(this, TREE);
+		    card_showing = TREE;
+		}
+
+		// Validate the buttons above the value tree
+		MetadataValueTableEntry metadata_value_table_entry = metadata_value_table.getSelectedMetadataValueTableEntry();
+		if (metadata_value_table_entry.getValue().equals("")) {
+		    // Can only append if something has been entered
+		    add.setEnabled((getSelectedValue().length() > 0));
+
+		    // Nothing to replace or remove
+		    update.setEnabled(false);
+		    remove.setEnabled(false);
 		    return;
 		}
 
-		repostEvent(e);
-		dispatchComponent = null;
-		setValueIsAdjusting(false);
-	    } else {
-		adjustFocusAndSelection(e);
-	    }
-        }
-
-
-        public void mouseEntered(MouseEvent e) {}
-
-        public void mouseExited(MouseEvent e) {}
-
-	//  The Table's mouse motion listener methods.
-
-        public void mouseMoved(MouseEvent e) {}
-
-        public void mouseDragged(MouseEvent e) {
-	    if (shouldIgnore(e)) {
-	        return;
-	    }
-
-            repostEvent(e);
-
-            CellEditor editor = table.getCellEditor();
-            if (editor == null || editor.shouldSelectCell(e)) {
-                Point p = e.getPoint();
-                int row = table.rowAtPoint(p);
-                int column = table.columnAtPoint(p);
-	        // The autoscroller can generate drag events outside the Table's range.
-                if ((column == -1) || (row == -1)) {
-                    return;
-                }
-	        table.changeSelection(row, column, false, true);
-            }
-        }
-    }
-
-
-    /** A listener for right mouse button clicks over the collection tree. */
-    private class RightButtonListener
-	extends MouseAdapter {
-	/** Called whenever a mouse click occurs (right or left) over a target component.
-	 * @param event A <strong>MouseEvent</strong> containing further information about the mouse click action.
-	 * @see org.greenstone.gatherer.gui.EnrichPane.RightButtonMenu
-	 */
-	public void mouseClicked(MouseEvent event) {
-	    if (SwingUtilities.isRightMouseButton(event)) {
-		new RightButtonMenu(event);
-	    }
-	}
-    }
-
-
-    /** When a user right-clicks within the collection tree they are presented with a small popup menu of context based options. This class provides such functionality.
-     */
-    private class RightButtonMenu
-	extends JPopupMenu
-	implements ActionListener {
-
-	/** The tree over which the right click action occurred. */
-	private DragTree tree = null;
-	/** The tree nodes selected when the right click action occurred. */
-	private TreePath[] selection_paths = null;
-	/** The file record over which the right click action occurred. */
-	private FileNode node = null;
-
-	private JMenuItem collapse_folder = null;
-	private JMenuItem expand_folder = null;
-	private JMenuItem metaaudit = null;
-	private JMenuItem open_externally = null;
-
-
-	private RightButtonMenu(MouseEvent event)
-	{
-	    super();
-	    this.tree = collection_tree;
-
-	    // Get the paths currently selected in the tree
-	    selection_paths = tree.getSelectionPaths();
-
-	    // Create an appropriate context menu, based on what is selected
-	    buildContextMenu(selection_paths);
-
-	    // Show the popup menu on screen
-	    show(tree, event.getX(), event.getY());
-	}
-
-
-	private void buildContextMenu(TreePath[] selection_paths)
-	{
-	    // If nothing is selected, no options are available
-	    if (selection_paths == null) {
-		return;
-	    }
-
-	    DebugStream.println("Number of files/folders selected: " + selection_paths.length);
-
-	    // Always have meta-audit option
-	    String[] args = new String[1];
-	    args[0] = collection_tree.getSelectionDetails();
-	    metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", args), KeyEvent.VK_A);
-	    metaaudit.addActionListener(this);
-	    add(metaaudit);
-
-	    // Only meta-audit is available if multiple items are selected...
-	    if (selection_paths.length > 1) {
-		return;
-	    }
-
-	    TreePath path = selection_paths[0];
-	    node = (FileNode) path.getLastPathComponent();
-
-	    // ---- Options for file nodes ----
-	    if (node.isLeaf()) {
-		// Open the file in an external program
-		open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O);
-		open_externally.addActionListener(this);
-		add(open_externally);
-
-		return;
-	    }
-
-	    // ---- Options for folder nodes ----
-	    // Collapse or expand, depending on current status
-	    if (tree.isExpanded(path)) {
-		collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C);
-		collapse_folder.addActionListener(this);
-		add(collapse_folder);
-	    }
-	    else {
-		expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O);
-		expand_folder.addActionListener(this);
-		add(expand_folder);
-	    }
-	}
-
-
-	/** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */
-	public void actionPerformed(ActionEvent event)
-	{
-	    Object source = event.getSource();
-
-	    // Collapse folder
-	    if (source == collapse_folder) {
-		tree.collapsePath(selection_paths[0]);
-	    }
-
-	    // Expand folder
-	    else if (source == expand_folder) {
-		tree.expandPath(selection_paths[0]);
-	    }
-
-	    // Meta-audit
-	    else if (source == metaaudit) {
- 		Gatherer.g_man.showMetaAuditBox();
- 	    }
-
-	    // Open in external program
-	    else if (source == open_externally) {
-		Gatherer.self.spawnApplication(node.getFile());
+		// Check if the text in the value field is the same as the metadata value
+		if (getSelectedValue().equals(metadata_value_table_entry.getFullValue())) {
+		    // Can't replace
+		    update.setEnabled(false);
+
+		    // Adding, however, is dependant on whether the selected metadata is common or uncommon. If the later then you can append so as to make it common.
+		    add.setEnabled(!metadata_value_table.isSelectedMetadataValueTableEntryCommon());
+		}
+		else {
+		    // Can append or replace, if something has been entered
+		    add.setEnabled((getSelectedValue().length() > 0));
+		    update.setEnabled((getSelectedValue().length() > 0));
+		}
+
+		// Can only remove if the metadata is file level
+		if (metadata_value_table_entry != null) {  // Shouldn't be necessary, but is
+		    remove.setEnabled((metadata_value_table_entry.isInheritedMetadata() == false));
+		}
+	    }
+	}
+
+
+	/** Handles TreeSelectionEvents. */
+	public void valueChanged(TreeSelectionEvent event)
+	{
+	    if (tree.getSelectionCount() != 0 && !ignore_tree_selection_event) {
+		TreePath path = tree.getSelectionPath();
+		MetadataValueTreeNode node = (MetadataValueTreeNode) path.getLastPathComponent();
+		setSelectedValue(node.getFullValue());
+	    }
+	}
+
+
+	private class MetadataFieldListener
+	    implements KeyListener {
+
+	    /** Gives notification of key events on the text field */
+	    public void keyPressed(KeyEvent e) {
+		if (e.getKeyCode() == KeyEvent.VK_TAB) {
+		    // Tab: Auto-complete
+		    if (tree.getSelectionCount() != 0 && !getSelectedValue().equals("")) {
+			TreePath path = tree.getSelectionPath();
+			MetadataValueTreeNode node = (MetadataValueTreeNode) path.getLastPathComponent();
+			setSelectedValue(node.getFullValue());
+		    }
+		}
+		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+		    // Enter: Append the metadata value, if we're allowed to
+		    if (add.isEnabled()) {
+			add.doClick();
+		    }
+		}
+	    }
+
+	    public void keyReleased(KeyEvent e) { }
+
+	    public void keyTyped(KeyEvent e) { }
+	}
+
+
+	private class DocumentListenerImpl
+	    implements DocumentListener
+	{
+	    /** Gives notification that an attribute or set of attributes changed */
+	    public void changedUpdate(DocumentEvent e) {
+		validate();
+	    }
+
+	    /** Gives notification that there was an insert into the document */
+	    public void insertUpdate(DocumentEvent e) {
+		validate();
+	    }
+
+	    /** Gives notification that a portion of the document has been removed */
+	    public void removeUpdate(DocumentEvent e) {
+		validate();
+	    }
+
+
+	    /** Ensures that the value text field and value tree are synchronized */
+	    private void validate()
+	    {
+		String value_text = getSelectedValue();
+
+		// Ignore the validate() with empty text that occurs when value.setText() is used
+		if (!value_text.equals("") || manual_text_edit_event == true) {
+		    TreePath closest_path = getClosestPath(value_text);
+
+		    // Select the new path in the tree
+		    // The tree selection event this causes must be ignored, since it alters value
+		    ignore_tree_selection_event = true;
+		    tree.setSelectionPath(closest_path);
+		    ignore_tree_selection_event = false;
+
+		    // If a folder has been specified, make sure it is expanded
+		    if (value_text.endsWith(MetadataValueTreeNode.METADATA_VALUE_TREE_NODE_HIERARCHY_TOKEN) && !tree.isExpanded(closest_path)) {
+			tree.expandPath(closest_path);
+		    }
+
+		    // Make sure the path is visible on the screen
+		    scrollTreePathToVisible(closest_path);
+		    // One call should be enough, but it isn't in some cases (for some reason)
+		    scrollTreePathToVisible(closest_path);
+
+		    // Update the status of the buttons
+		    validateDisplay();
+		}
 	    }
 	}
@@ -1146,377 +1366,123 @@
 
 
-    /**
-     * This class is a little bit complex, a little bit subtle, and a little bit odd.
-     * The strange interaction model is due to the fact that it is very tightly
-     * coupled to the EnrichPane.
-     *
-     * The interaction is complex because there are three separate controls that the
-     * user may interact with, each of which can affect the other two. The three
-     * controls are:
-     *   - The "assigned metadata" table, at the top right of the meta edit pane.
-     *   - The "metadata value" text field, where users can type in new values.
-     *   - The "metadata value tree", which shows other values that have been
-     *     assigned to the selected metadata element.
-     *
-     * The interactions are:
-     *   - The "assigned metadata" table
-     *     Users may select one (and only one) row in this table. Selecting a row
-     *     chooses one metadata element. The text field will be set to the current
-     *     value of the metadata element. This value will also be selected in the
-     *     metadata value tree.
-     *
-     *   - The "metadata value" text field
-     *     If the value the user has typed in this is a prefix of an entry in the
-     *     value tree, this value will be selected in the value tree. In this case,
-     *     pressing "Enter" will complete the value (ie. make the value in the text
-     *     field the same as the value in the tree). This is to allow users to
-     *     quickly and easily assign existing metadata values to new documents.
-     *
-     *   - The "metadata value tree"
-     *     Selecting a value in the tree will set the text field to this value.
+    /** A listener for right mouse button clicks over the collection tree. */
+    private class RightButtonListener
+	extends MouseAdapter {
+	/** Called whenever a mouse click occurs (right or left) over a target component.
+	 * @param event A <strong>MouseEvent</strong> containing further information about the mouse click action.
+	 * @see org.greenstone.gatherer.gui.EnrichPane.RightButtonMenu
+	 */
+	public void mouseClicked(MouseEvent event) {
+	    if (SwingUtilities.isRightMouseButton(event)) {
+		new RightButtonMenu(event);
+	    }
+	}
+    }
+
+
+    /** When a user right-clicks within the collection tree they are presented with a small popup menu of context based options. This class provides such functionality.
      */
-    private class GValueTree
-	extends JPanel
-	implements TreeSelectionListener {
-	private boolean ignore_tree_selection_event = false;
-	private boolean manual_text_edit_event;
-	private CardLayout card_layout;
-	private String card_showing = null;
-	/** The metadata element that is currently selected. */
-	private ElementWrapper selected_metadata_element = null;
-	private GValueModel vm;
-	private JTextArea extracted_message;
-	private JTextField value;
-	private JTree tree;
-
-	static final private String NONE = "None";
-	static final private String TREE = "Tree";
-
-
-	public GValueTree(int width, int height)
+    private class RightButtonMenu
+	extends JPopupMenu
+	implements ActionListener {
+
+	/** The tree over which the right click action occurred. */
+	private DragTree tree = null;
+	/** The tree nodes selected when the right click action occurred. */
+	private TreePath[] selection_paths = null;
+	/** The file record over which the right click action occurred. */
+	private FileNode node = null;
+
+	private JMenuItem collapse_folder = null;
+	private JMenuItem expand_folder = null;
+	private JMenuItem metaaudit = null;
+	private JMenuItem open_externally = null;
+
+
+	private RightButtonMenu(MouseEvent event)
 	{
 	    super();
-
-	    setFont(Configuration.getFont("general.font", false));
-	    setPreferredSize(new Dimension(width, height));
-
-	    JPanel metadata_pane = new JPanel();
-
-	    JPanel value_pane = new JPanel();
-	    JLabel value_label = new JLabel();
-	    Dictionary.registerText(value_label, "MetaEdit.Value");
-
-	    JPanel value_field_pane = new JPanel();
-	    value = new JTextField();
-	    value.setBackground(Configuration.getColor("coloring.editable_background", false));
-	    value.setForeground(Configuration.getColor("coloring.editable_foreground", false));
-	    value.setPreferredSize(new Dimension(413, 24));
-	    value.getDocument().addDocumentListener(new DocumentListenerImpl());
-	    value.addKeyListener(new MetadataFieldListener());
-	    value.setFocusTraversalKeysEnabled(false);
-	    Dictionary.setTooltip(value, "MetaEdit.Value_Field_Tooltip");
-
-	    JPanel button_pane = new JPanel();
-
-	    JPanel tree_pane = new JPanel();
-	    JLabel tree_label = new JLabel();
-	    Dictionary.registerText(tree_label, "MetaEdit.Tree");
-
-	    tree = new JTree(new GValueModel());
-	    tree.addTreeSelectionListener(this);
-	    tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
-	    tree.setRootVisible(false);
-	    tree.putClientProperty("JTree.lineStyle", "Angled");
-
-	    JPanel extracted_pane = new JPanel();
-	    JPanel extracted_header_pane = new JPanel();
-	    extracted_message = new JTextArea("");
-	    extracted_message.setEditable(false);
-	    extracted_message.setLineWrap(true);
-	    extracted_message.setOpaque(false);
-	    extracted_message.setWrapStyleWord(true);
-
-	    card_layout = new CardLayout();
-
-	    // Layout
-	    value_field_pane.setBorder(BorderFactory.createEmptyBorder(0,5,0,5));
-	    value_field_pane.setLayout(new BorderLayout(0, 0));
-	    value_field_pane.add(value, BorderLayout.CENTER);
-
-	    button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
-	    button_pane.setLayout(new GridLayout());
-	    button_pane.add(add);
-	    button_pane.add(update);
-	    button_pane.add(remove);
-
-	    value_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
-	    value_pane.setLayout(new BorderLayout());
-	    value_pane.add(value_label, BorderLayout.WEST);
-	    value_pane.add(value_field_pane, BorderLayout.CENTER);
-	    value_pane.add(expand, BorderLayout.EAST);
-	    value_pane.add(button_pane, BorderLayout.SOUTH);
-
-	    tree_pane.setLayout(new BorderLayout());
-	    tree_pane.add(tree_label, BorderLayout.NORTH);
-	    tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
-
-	    metadata_pane.setLayout(new BorderLayout());
-	    metadata_pane.add(value_pane, BorderLayout.NORTH);
-	    metadata_pane.add(tree_pane, BorderLayout.CENTER);
-
-	    extracted_header_pane.setLayout(new BorderLayout());
-	    extracted_header_pane.add(expand_for_extracted, BorderLayout.EAST);
-
-	    extracted_pane.setBorder(BorderFactory.createEmptyBorder(0,10,25,0));
-	    extracted_pane.setLayout(new BorderLayout());
-	    extracted_pane.add(extracted_header_pane, BorderLayout.NORTH);
-	    extracted_pane.add(extracted_message, BorderLayout.CENTER);
-
-	    this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
-	    this.setLayout(card_layout);
-	    this.add(metadata_pane, TREE);
-	    this.add(extracted_pane, NONE);
-	    card_showing = TREE;
-	}
-
-
-	public GValueModel getModel() {
-	    return (GValueModel) tree.getModel();
-	}
-
-
-	public ElementWrapper getSelectedMetadataElement() {
-	    return selected_metadata_element;
-	}
-
-
-	public String getSelectedValue() {
-	    String raw_value = value.getText();
-	    raw_value = Codec.transformUnicode(raw_value);
-	    raw_value = Codec.transform(raw_value, Codec.ENCODE_PATH);
-	    raw_value = Codec.transform(raw_value, Codec.ENCODE_SQUARE_BRACKETS);
-	    return raw_value;
-	}
-
-
-	public void setSelectedMetadataElement(ElementWrapper element)
-	{
-	    ///ystem.err.println("Setting selected metadata element to: " + element);
-	    if (element == null) {
-		selected_metadata_element = null;
+	    this.tree = collection_tree;
+
+	    // Get the paths currently selected in the tree
+	    selection_paths = tree.getSelectionPaths();
+
+	    // Create an appropriate context menu, based on what is selected
+	    buildContextMenu(selection_paths);
+
+	    // Show the popup menu on screen
+	    show(tree, event.getX(), event.getY());
+	}
+
+
+	private void buildContextMenu(TreePath[] selection_paths)
+	{
+	    // If nothing is selected, no options are available
+	    if (selection_paths == null) {
 		return;
 	    }
 
-	    // Don't bother if the element selected is the same as the current one
-	    if (selected_metadata_element != null && element.equals(selected_metadata_element)) {
+	    DebugStream.println("Number of files/folders selected: " + selection_paths.length);
+
+	    // Always have meta-audit option
+	    metaaudit = new JMenuItem(Dictionary.get("Menu.Metadata_View", collection_tree.getSelectionDetails()), KeyEvent.VK_A);
+	    metaaudit.addActionListener(this);
+	    add(metaaudit);
+
+	    // Only meta-audit is available if multiple items are selected...
+	    if (selection_paths.length > 1) {
 		return;
 	    }
 
-	    if (vm != null) {
-		// Close any expanded paths in the tree
-		GValueNode root_node = (GValueNode) vm.getRoot();
-		for (int i = 0; i < root_node.getChildCount(); i++) {
-		    GValueNode child_node = (GValueNode) root_node.getChildAt(i);
-		    TreePath child_path = new TreePath(child_node.getPath());
-		    if (tree.isExpanded(child_path)) {
-			tree.collapsePath(child_path);
-		    }
-		}
-	    }
-
-	    // Load the model for the newly selected metadata element
-	    selected_metadata_element = element;
-	    if (Gatherer.c_man != null && Gatherer.c_man.getCollection() != null && Gatherer.c_man.getCollection().msm != null && tree != null) {
-		vm = Gatherer.c_man.getCollection().msm.getValueTree(element);
-		tree.setModel(vm);
-	    }
-
-	    // Special case the extracted metadata set
-	    if (selected_metadata_element.getNamespace().equals(Utility.EXTRACTED_METADATA_NAMESPACE)) {
-		// Display the panel showing the "you cannot edit this metadata" message
-		String[] args = new String[1];
-		args[0] = selected_metadata_element.toString();
-		Dictionary.registerText(extracted_message, "MetaEdit.AutoMessage", args);
-		card_layout.show(this, NONE);
-		card_showing = NONE;
+	    TreePath path = selection_paths[0];
+	    node = (FileNode) path.getLastPathComponent();
+
+	    // ---- Options for file nodes ----
+	    if (node.isLeaf()) {
+		// Open the file in an external program
+		open_externally = new JMenuItem(Dictionary.get("Menu.Open_Externally"), KeyEvent.VK_O);
+		open_externally.addActionListener(this);
+		add(open_externally);
+		return;
+	    }
+
+	    // ---- Options for folder nodes ----
+	    // Collapse or expand, depending on current status
+	    if (tree.isExpanded(path)) {
+		collapse_folder = new JMenuItem(Dictionary.get("Menu.Collapse"), KeyEvent.VK_C);
+		collapse_folder.addActionListener(this);
+		add(collapse_folder);
 	    }
 	    else {
-		// Display the panel for viewing and assigning metadata
-		card_layout.show(this, TREE);
-		card_showing = TREE;
-	    }
-	}
-
-
-	/** Handles TreeSelectionEvents. */
-	public void valueChanged(TreeSelectionEvent event)
-	{
-	    if (tree.getSelectionCount() != 0 && !ignore_tree_selection_event) {
-		TreePath path = tree.getSelectionPath();
-		GValueNode node = (GValueNode) path.getLastPathComponent();
-		setSelectedValue(node.getFullPath(true));
-	    }
-	}
-
-
-	/** Sets the value in the text field. */
-	public void setSelectedValue(String val)
-	{
-	    // Setting the text of the field causes the DocumentListener to be notified, and
-	    //   updating the tree is handled there (DocumentListenerImpl::validate())
-	    if (!card_showing.equals(NONE)) {
-		// Decode val
-		///ystem.err.println("Before transforms: " + val);
-		//val = Codec.transform(val, Codec.DECODE_SQUARE_BRACKETS);
-		//val = Codec.transform(val, Codec.DECODE_PATH);
-		///ystem.err.println("Setting selected value to: " + val);
-		manual_text_edit_event = val.equals("");  // Set to false unless val == ""
-		value.setText(val); ///odec.transform(val, /odec.GREENSTONE_TO_TEXT));
-		value.setCaretPosition(0);
-		manual_text_edit_event = true;
-	    }
-	}
-
-
-	/** Returns a TreePath for the node most closely matching the metadata value. */
-	private TreePath getClosestPath(String val)
-	{
-	    ///ystem.err.println("Select closest path to: " + val);
-	    // Start at the root of the tree
-	    GValueNode tree_node = (GValueNode) tree.getModel().getRoot();
-
-	    // Hierarchical values are separated using '|'
-	    PatternTokenizer tokenizer = new PatternTokenizer(val, StaticStrings.PIPE_STR);
-	    while (tokenizer.hasMoreTokens()) {
-		String token = tokenizer.nextToken();
-
-		// All components except the last must match exactly
-		if (tokenizer.hasMoreTokens()) {
-		    for (int i = 0; i < tree_node.getChildCount(); i++) {
-			GValueNode child_node = (GValueNode) tree_node.getChildAt(i);
-			if (child_node.toString(GValueNode.DOM).equals(token)) {
-			    // The matching node has been found, so move onto the next token
-			    tree_node = child_node;
-			    break;
-			}
-		    }
-		}
-
-		// The last component may match partially
-		else {
-		    for (int i = 0; i < tree_node.getChildCount(); i++) {
-			GValueNode child_node = (GValueNode) tree_node.getChildAt(i);
-			if (child_node.toString(GValueNode.DOM).startsWith(token)) {
-			    // The closest node has been found, so return its path
-			    return new TreePath(child_node.getPath());
-			}
-		    }
-
-		    // Not even a partial match
-		    return null;
-		}
-	    }
-
-	    // If nothing else, return the path of the root node
-	    return new TreePath(tree_node.getPath());
-	}
-
-
-	/** This function is copied from JTree::setPathToVisible(), and modified so tree rows
-	    are always shown flushed left. Note: doesn't do accessibleContext stuff. */
-	private void scrollTreePathToVisible(TreePath path)
-	{
-	    if (path != null) {
-		tree.makeVisible(path);
-
-		Rectangle bounds = tree.getPathBounds(path);
-		if (bounds != null) {
-		    bounds.width += bounds.x;
-		    bounds.x = 0;
-		    tree.scrollRectToVisible(bounds);
-		}
-	    }
-	}
-
-
-	private class MetadataFieldListener
-	    implements KeyListener {
-
-	    /** Gives notification of key events on the text field */
-	    public void keyPressed(KeyEvent e) {
-		if (e.getKeyCode() == KeyEvent.VK_TAB) {
-		    // Tab: Auto-complete
-		    if (tree.getSelectionCount() != 0 && !getSelectedValue().equals("")) {
-			TreePath path = tree.getSelectionPath();
-			GValueNode node = (GValueNode) path.getLastPathComponent();
-			String val = node.getFullPath(true);
-			///ystem.err.println("Setting value to: " + val);
-			value.setText(val);
-			val = null;
-		    }
-		}
-		if (e.getKeyCode() == KeyEvent.VK_ENTER) {
-		    // Enter: Append the metadata value, if we're allowed to
-		    if (add.isEnabled()) {
-			add.doClick();
-		    }
-		}
-	    }
-
-	    public void keyReleased(KeyEvent e) { }
-
-	    public void keyTyped(KeyEvent e) { }
-	}
-
-
-	private class DocumentListenerImpl
-	    implements DocumentListener {
-	    /** Gives notification that an attribute or set of attributes changed */
-	    public void changedUpdate(DocumentEvent e) {
-		validate();
-	    }
-
-	    /** Gives notification that there was an insert into the document */
-	    public void insertUpdate(DocumentEvent e) {
-		validate();
-	    }
-
-	    /** Gives notification that a portion of the document has been removed */
-	    public void removeUpdate(DocumentEvent e) {
-		validate();
-	    }
-
-
-	    /** Ensures that the value text field and value tree are synchronized */
-	    private void validate()
-	    {
-		String value_text = getSelectedValue(); ///odec.transform(getSelectedValue(), /odec.TEXT_TO_DOM);
-		///ystem.err.println("\n(Validate) Value text: " + value_text);
-
-		// Ignore the validate() with empty text that occurs when value.setText() is used
-		if (!value_text.equals("") || manual_text_edit_event == true) {
-		    TreePath closest_path = getClosestPath(value_text);
-
-		    ///ystem.err.println("The closest path is: " + closest_path);
-
-		    // Select the new path in the tree
-		    // The tree selection event this causes must be ignored, since it alters value
-		    ignore_tree_selection_event = true;
-		    tree.setSelectionPath(closest_path);
-		    ignore_tree_selection_event = false;
-
-		    // If a folder has been specified, make sure it is expanded
-		    if (value_text.endsWith("\\") && !tree.isExpanded(closest_path)) {
-			tree.expandPath(closest_path);
-		    }
-
-		    // Make sure the path is visible on the screen
-		    scrollTreePathToVisible(closest_path);
-		    // One call should be enough, but it isn't in some cases (for some reason)
-		    scrollTreePathToVisible(closest_path);
-
-		    // Update the status of the buttons
-		    validateControls(); // Don't update the tools view itself
-		}
+		expand_folder = new JMenuItem(Dictionary.get("Menu.Expand"), KeyEvent.VK_O);
+		expand_folder.addActionListener(this);
+		add(expand_folder);
+	    }
+	}
+
+
+	/** Called whenever one of the menu items is clicked, this method then causes the appropriate effect. */
+	public void actionPerformed(ActionEvent event)
+	{
+	    Object source = event.getSource();
+
+	    // Collapse folder
+	    if (source == collapse_folder) {
+		tree.collapsePath(selection_paths[0]);
+	    }
+
+	    // Expand folder
+	    else if (source == expand_folder) {
+		tree.expandPath(selection_paths[0]);
+	    }
+
+	    // Meta-audit
+	    else if (source == metaaudit) {
+		Gatherer.g_man.showMetaAuditBox();
+	    }
+
+	    // Open in external program
+	    else if (source == open_externally) {
+		Gatherer.self.spawnApplication(node.getFile());
 	    }
 	}
Index: /trunk/gli/src/org/greenstone/gatherer/gui/GUIManager.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/GUIManager.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/GUIManager.java	(revision 8313)
@@ -63,5 +63,6 @@
 import org.greenstone.gatherer.gui.tree.WorkspaceTree;
 import org.greenstone.gatherer.help.HelpFrame;
-import org.greenstone.gatherer.mem.MetadataEditorManager;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
 import org.greenstone.gatherer.shell.GShell;
 import org.greenstone.gatherer.util.StaticStrings;
@@ -166,4 +167,5 @@
 	else if(esrc == menu_bar.file_close) {
 	    boolean cont = showSaveCollectionBox(true, false);
+	    // System.err.println("Here 1.");
 	    if(cont) {
 		tab_pane.setSelectedComponent(gather_pane);
@@ -252,22 +254,7 @@
 	// Metadata Options.
 	// *****************
-	else if (esrc == menu_bar.metadata_import) {
-	    JFileChooser chooser = new JFileChooser(new File(Utility.METADATA_DIR));
-	    MDSFileFilter filter = new MDSFileFilter();
-	    chooser.setFileFilter(filter);
-	    int returnVal = chooser.showDialog(Gatherer.g_man, Dictionary.get("MSMPrompt.File_Import"));
-	    if (returnVal == JFileChooser.APPROVE_OPTION) {
-		Gatherer.c_man.getCollection().msm.importMDS(chooser.getSelectedFile(), true);
-	    }
-	}
-	else if(esrc == menu_bar.metadata_edit) {
-	    showEditMetadataBox();
-	}
-	else if(esrc == menu_bar.metadata_export) {
-	    Gatherer.c_man.getCollection().msm.exportMDS();
-	}
-	else if(esrc == menu_bar.metadata_view) {
-	    showMetaAuditBox();
-	}
+// 	else if (esrc == menu_bar.metadata_view) {
+// 	    showMetaAuditBox();
+// 	}
 
 	// *************
@@ -658,11 +645,4 @@
     }
 
-    /** When the edit metadata option is choosen from the menu, this method is called to ensure we only edit the metadata if there is metadata loaded.
-     */
-    private void showEditMetadataBox() {
-	if(Gatherer.c_man.getCollection() != null) {
-	    Gatherer.c_man.getCollection().msm.editMDS(null, MetadataEditorManager.NORMAL);
-	}
-    }
     /** When the load collection option is choosen this method is called to produce the modal file load prompt.
      */
@@ -814,5 +794,7 @@
 	//case SaveCollectionBox.SAVE_YES:
 	Gatherer.c_man.setClosingThread(true);
+	// System.err.println("Here 2.");
 	Gatherer.c_man.saveCollection(close_after, exit_after);
+	// System.err.println("Here 3.");
 	// Wait until it is closed.
 	try {
@@ -823,7 +805,6 @@
 	    }
 	}
-	catch(Exception error) {
-	    DebugStream.println("Exception: " + error);
-	    DebugStream.printStackTrace(error);
+	catch (Exception exception) {
+	    DebugStream.printStackTrace(exception);
 	}
 	
@@ -859,5 +840,5 @@
 	}
 	// "View assigned metadata" menu item is disabled by default
-	menu_bar.metadata_view.setCanEnable(false);
+	// menu_bar.metadata_view.setCanEnable(false);
 	menu_bar.setMetaAuditSuffix(null);
 
@@ -867,10 +848,10 @@
 	    gather_pane.gainFocus();
 	    // "View assigned metadata" menu item is enabled for the "Gather" pane
-	    menu_bar.metadata_view.setCanEnable(true);
+	    // menu_bar.metadata_view.setCanEnable(true);
 	}
 	else if(selected_index == tab_pane.indexOfComponent(enrich_pane)) {
 	    enrich_pane.gainFocus();
 	    // "View assigned metadata" menu item is enabled for the "Enrich" pane
-	    menu_bar.metadata_view.setCanEnable(true);
+	    // menu_bar.metadata_view.setCanEnable(true);
 	}
 	else if(selected_index == tab_pane.indexOfComponent(design_pane)) {
@@ -953,30 +934,4 @@
 
 
-    private class MDSFileFilter
-	extends FileFilter
-    {
-	/** Override this method to return <i>true</i> only if the file extension is .mds.
-	 * @param f A possible mds <strong>File</strong>.
-	 * @return <i>true</i> if we should show this file, <i>false</i> otherwise.
-	 */
-	public boolean accept(File f)
-	{
-	    String file_name = f.getName().toLowerCase();
-	    if (file_name.endsWith(".mds") || file_name.indexOf(".") == -1) {
-		return true;
-	    }
-	    return false;
-	}
-
-	/** Retrieve the description for this filter.
-	 * @return The description as a <strong>String</strong>.
-	 */
-	public String getDescription()
-	{
-	    return Dictionary.get("MSMPrompt.File_Filter_Description");
-	}
-    }
-
-
     /** Listens to actions upon the menu bar, and if it detects a click over the help menu brings the help window to the front if it has become hidden.
      */
Index: /trunk/gli/src/org/greenstone/gatherer/gui/MenuBar.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/MenuBar.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/MenuBar.java	(revision 8313)
@@ -57,5 +57,4 @@
     private JMenu file               = null;
     private JMenu edit               = null;
-    private JMenu metadata           = null;
     public JMenu help                = null;
     public JMenuItem file_associations;
@@ -71,7 +70,4 @@
     public JMenuItem edit_cut;
     public JMenuItem edit_paste;
-    public JMenuItem metadata_import = null;
-    public JMenuItem metadata_edit   = null;
-    public JMenuItem metadata_export = null;
     public JMenuItem help_about;
     public JMenuItem help_browse;
@@ -84,5 +80,4 @@
     public JMenuItem help_mirror ;
     public JMenuItem help_preview;
-    public MagicMenuItem metadata_view   = null;
 
     public MenuBar(MenuListener menu_listener)
@@ -178,34 +173,4 @@
 	edit.add(edit_paste);
 
-	// Metadata menu
-	metadata = new JMenu();
-	metadata.setEnabled(false);
-	metadata.setMnemonic(KeyEvent.VK_M);
-	Dictionary.registerText(metadata, "Menu.Metadata");
-
-	metadata_import = new JMenuItem();
-	metadata_import.addActionListener(Gatherer.g_man);
-	metadata_import.setMnemonic(KeyEvent.VK_I);
-	Dictionary.registerText(metadata_import, "Menu.Metadata_Import");
-
-	metadata_edit = new JMenuItem();
-	metadata_edit.addActionListener(Gatherer.g_man);
-	metadata_edit.setMnemonic(KeyEvent.VK_E);
-	Dictionary.registerText(metadata_edit, "Menu.Metadata_Edit");
-
-	metadata_export = new JMenuItem();
-	metadata_export.addActionListener(Gatherer.g_man);
-	metadata_export.setMnemonic(KeyEvent.VK_X);
-	Dictionary.registerText(metadata_export, "Menu.Metadata_Export");
-
-	metadata_view = new MagicMenuItem(Dictionary.get("Menu.Metadata_View") + " " + Dictionary.get("FileActions.No_Selection"), KeyEvent.VK_A);
-	metadata_view.addActionListener(Gatherer.g_man);	
-
-	// Layout (metadata sets menu)
-	metadata.add(metadata_import);
-	metadata.add(metadata_edit);
-	metadata.add(metadata_export);
-	metadata.add(metadata_view);
-
 	// Help menu
 	help = new JMenu();
@@ -287,6 +252,4 @@
 	this.add(Box.createHorizontalStrut(15));
 	this.add(edit);
-	this.add(Box.createHorizontalStrut(15));
-	this.add(metadata);
 	this.add(Box.createHorizontalGlue());
 	this.add(help);
@@ -296,5 +259,4 @@
 	file_close.setEnabled(ready);
 	file_save.setEnabled(ready);
-	metadata.setEnabled(ready);
     }
 
@@ -303,19 +265,18 @@
 	file.setEnabled(false);
 	edit.setEnabled(false);
-	metadata.setEnabled(false);
 	help.setEnabled(false);
     }
 
     public void setMetaAuditSuffix(String metaaudit_suffix) {
-	///ystem.err.println("**** Set suffix: " + metaaudit_suffix);
-	if(metaaudit_suffix == null) {
-	    metadata_view.setText(Dictionary.get("Menu.Metadata_View") + " " + Dictionary.get("FileActions.No_Selection"));
-	    metadata_view.setEnabled(false);
-	}
-	else {
-	    ///ystem.err.println("Set metadata view suffix: " + metaaudit_suffix);
-	    metadata_view.setText(Dictionary.get("Menu.Metadata_View") + " " + metaaudit_suffix);
-	    metadata_view.setEnabled(true);
-	}
+// 	///ystem.err.println("**** Set suffix: " + metaaudit_suffix);
+// 	if(metaaudit_suffix == null) {
+// 	    metadata_view.setText(Dictionary.get("Menu.Metadata_View") + " " + Dictionary.get("FileActions.No_Selection"));
+// 	    metadata_view.setEnabled(false);
+// 	}
+// 	else {
+// 	    ///ystem.err.println("Set metadata view suffix: " + metaaudit_suffix);
+// 	    metadata_view.setText(Dictionary.get("Menu.Metadata_View") + " " + metaaudit_suffix);
+// 	    metadata_view.setEnabled(true);
+// 	}
     }
 
@@ -344,33 +305,33 @@
 
 
-    public class MagicMenuItem
-	extends JMenuItem {
-
-	private boolean can_enable;
-	private boolean should_enable;
-
-	public MagicMenuItem(String title, int key_event) {
-	    super(title, key_event);
-	    super.setEnabled(false);
-	    can_enable = false;
-	    should_enable = false;
-	}
-
-	public void setCanEnable(boolean can_enable) {
-	    this.can_enable = can_enable;
-	    if (can_enable) {
-		super.setEnabled(should_enable);
-	    }
-	    else {
-		super.setEnabled(false);
-	    }
-	}
-
-	public void setEnabled(boolean should_enable) {
-	    this.should_enable = should_enable;
-	    if (can_enable) {
-		super.setEnabled(should_enable);
-	    }
-	}
-    }
+//     public class MagicMenuItem
+// 	extends JMenuItem {
+
+// 	private boolean can_enable;
+// 	private boolean should_enable;
+
+// 	public MagicMenuItem(String title, int key_event) {
+// 	    super(title, key_event);
+// 	    super.setEnabled(false);
+// 	    can_enable = false;
+// 	    should_enable = false;
+// 	}
+
+// 	public void setCanEnable(boolean can_enable) {
+// 	    this.can_enable = can_enable;
+// 	    if (can_enable) {
+// 		super.setEnabled(should_enable);
+// 	    }
+// 	    else {
+// 		super.setEnabled(false);
+// 	    }
+// 	}
+
+// 	public void setEnabled(boolean should_enable) {
+// 	    this.should_enable = should_enable;
+// 	    if (can_enable) {
+// 		super.setEnabled(should_enable);
+// 	    }
+// 	}
+//     }
 }
Index: /trunk/gli/src/org/greenstone/gatherer/gui/NewCollectionMetadataPrompt.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/NewCollectionMetadataPrompt.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/NewCollectionMetadataPrompt.java	(revision 8313)
@@ -32,15 +32,15 @@
 import java.util.*;
 import javax.swing.*;
+import javax.swing.border.*;
 import javax.swing.event.*;
 import org.greenstone.gatherer.Configuration;
 import org.greenstone.gatherer.Dictionary;
 import org.greenstone.gatherer.Gatherer;
-import org.greenstone.gatherer.checklist.CheckList;
-import org.greenstone.gatherer.checklist.Entry;
-import org.greenstone.gatherer.cdm.ElementWrapper;
-import org.greenstone.gatherer.msm.MetadataSet;
-import org.greenstone.gatherer.util.StaticStrings;
+import org.greenstone.gatherer.metadata.MetadataElement;
+import org.greenstone.gatherer.metadata.MetadataSet;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
+import org.greenstone.gatherer.metadata.MetadataTools;
 import org.greenstone.gatherer.util.Utility;
-import org.w3c.dom.*;
+
 
 public class NewCollectionMetadataPrompt
@@ -48,7 +48,7 @@
 
     private boolean cancelled = true;
-    private CheckList sets_list;
     private JDialog self;
     private JList elements_list;
+    private MetadataSetList sets_list;
     static private Dimension size = new Dimension(700, 380);
 
@@ -68,16 +68,17 @@
 	setModal(true);
 	setSize(size);
-	
-
-	// And the remaining metadata sets.
-	ArrayList sets = new ArrayList();
-	// Determine what collections are available.
-	File metadata_directory = new File(Utility.METADATA_DIR);
-	File[] possible_mdses = metadata_directory.listFiles();
-	for(int i = 0; i < possible_mdses.length; i++) {
-	    String name = possible_mdses[i].getName();
-	    if(name.endsWith(StaticStrings.METADATA_SET_EXTENSION) && !name.equals(Utility.EXTRACTED_METADATA_NAMESPACE + StaticStrings.METADATA_SET_EXTENSION)) {
-		sets.add(new MetadataSet(possible_mdses[i]));
-	    }
+
+	// Show the metadata sets (except extracted!) available in the GLI "metadata" folder 
+	ArrayList sets = MetadataSetManager.listMetadataSets(new File(Utility.METADATA_DIR));
+	ArrayList metadata_set_list_entries = new ArrayList();
+	for (int i = 0; i < sets.size(); i++) {
+	    MetadataSet metadata_set = (MetadataSet) sets.get(i);
+
+	    // Don't show the extracted metadata set
+	    if (metadata_set.getNamespace().equals(MetadataSetManager.EXTRACTED_METADATA_NAMESPACE)) {
+		continue;
+	    }
+
+	    metadata_set_list_entries.add(new MetadataSetListEntry(metadata_set));
 	}
 
@@ -97,5 +98,7 @@
 	sets_list_label.setOpaque(false);
 	Dictionary.setText(sets_list_label, "NewCollectionPrompt.Select_MDS");
-	sets_list = new CheckList(sets, true);
+	sets_list = new MetadataSetList();
+	sets_list.setListData(new Vector(metadata_set_list_entries));
+	sets_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 
 	JPanel elements_list_pane = new JPanel();
@@ -103,8 +106,12 @@
 	Dictionary.setText(elements_list_label, "NewCollectionPrompt.Metadata_Elements");
 	elements_list = new JList();
+	elements_list.setCellRenderer(new MetadataElementListCellRenderer());
 	elements_list.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
 	elements_list.setForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
 	elements_list.setSelectionBackground(Configuration.getColor("coloring.collection_tree_background", false));
 	elements_list.setSelectionForeground(Configuration.getColor("coloring.collection_tree_foreground", false));
+
+	// Select the Dublin Core metadata set by default, at Ian's request
+	sets_list.selectDublinCoreMetadataSet();
 
 	JPanel button_pane = new JPanel();
@@ -119,5 +126,4 @@
 	ok_button.addActionListener(new OKButtonListener());
 	cancel_button.addActionListener(new CancelButtonListener());
-	sets_list.addListSelectionListener(new MetadataListSelectionListener());
 
 	// Display
@@ -157,5 +163,5 @@
 
     public ArrayList getSets() {
-	return sets_list.getSelected();
+	return sets_list.getSelectedMetadataSets();
     }
 
@@ -163,4 +169,5 @@
 	return cancelled;
     }
+
 
     private class CancelButtonListener
@@ -172,35 +179,132 @@
     }
 
-    public class MetadataListSelectionListener
-	implements ListSelectionListener {
-	public void valueChanged(ListSelectionEvent event) {
-	    if(!sets_list.isSelectionEmpty()) {
-		// Retrieve the selected set.
-		Entry entry = (Entry) sets_list.getSelectedValue();
-		MetadataSet set = (MetadataSet) entry.getObject();
-		entry = null;
-		// Build a model from its elements.
-		NodeList elements = set.getElements();
-		set = null;
-		Vector elements_model = new Vector();
-		for(int i = 0; i < elements.getLength(); i++) {
-		    elements_model.add(new ElementWrapper(elements.item(i)));
-		}
-		elements = null;
-		Collections.sort(elements_model);
-		elements_list.setListData(elements_model);
-		elements_model = null;
-	    }
-	    else {
-		elements_list.setListData(new String[0]);
-	    }
-	}
-    }
-
-    public class OKButtonListener
+
+    private class MetadataSetList
+	extends JList
+    {
+	public MetadataSetList()
+	{
+	    super();
+	    addListSelectionListener(new MetadataSetListSelectionListener());
+	    addMouseListener(new MetadataSetListSelectionListener());
+	    setCellRenderer(new MetadataSetListCellRenderer());
+	}
+
+
+	public ArrayList getSelectedMetadataSets()
+	{
+	    ArrayList selected_metadata_sets = new ArrayList();
+
+	    ListModel model = (ListModel) getModel();
+	    for (int i = 0; i < model.getSize(); i++) {
+		MetadataSetListEntry metadata_set_list_entry = (MetadataSetListEntry) model.getElementAt(i);
+		if (metadata_set_list_entry.isSelected()) {
+		    selected_metadata_sets.add(metadata_set_list_entry.getMetadataSet());
+		}
+	    }
+
+	    return selected_metadata_sets;
+	}
+
+
+	/** Hack special-case code, used to select the Dublin Core metadata set by default */
+	public void selectDublinCoreMetadataSet()
+	{
+	    ListModel model = (ListModel) getModel();
+	    for (int i = 0; i < model.getSize(); i++) {
+		MetadataSetListEntry metadata_set_list_entry = (MetadataSetListEntry) model.getElementAt(i);
+		if (metadata_set_list_entry.getMetadataSet().getNamespace().equals("dc")) {
+		    metadata_set_list_entry.setSelected(true);
+		    metadata_set_list_entry.grabFocus();
+		    setSelectedIndex(i);
+		}
+	    }
+	}
+
+
+  	private class MetadataSetListCellRenderer
+  	    extends JLabel
+  	    implements ListCellRenderer {
+
+	    public Component getListCellRendererComponent(JList list, Object value, int index, boolean is_selected, boolean cell_has_focus)
+	    {
+		JCheckBox checkbox = (JCheckBox) value;
+		checkbox.setBackground(is_selected ? list.getSelectionBackground() : list.getBackground());
+		checkbox.setForeground(is_selected ? list.getSelectionForeground() : list.getForeground());
+		checkbox.setBorderPainted(true);
+		checkbox.setEnabled(list.isEnabled());
+		checkbox.setFont(list.getFont());
+		checkbox.setFocusPainted(false);
+		checkbox.setBorder((is_selected) ? UIManager.getBorder("List.focusCellHighlightBorder") : new EmptyBorder(1, 1, 1, 1));
+		return checkbox;
+	    }
+  	}
+
+
+	private class MetadataSetListSelectionListener
+	    extends MouseAdapter
+	    implements ListSelectionListener {
+
+	    public void mousePressed(MouseEvent e)
+	    {
+		JList list = (JList) e.getSource();
+		int index = list.locationToIndex(e.getPoint());
+		MetadataSetListEntry metadata_set_list_entry = (MetadataSetListEntry) list.getModel().getElementAt(index);
+		metadata_set_list_entry.setSelected(!metadata_set_list_entry.isSelected());
+		metadata_set_list_entry.grabFocus();
+
+		// Fire a selection changed event
+		fireSelectionValueChanged(index, index, false);
+	    }
+
+	    public void valueChanged(ListSelectionEvent event)
+	    {
+		if (!sets_list.isSelectionEmpty()) {
+		    // Retrieve the selected set
+		    MetadataSetListEntry metadata_set_list_entry = (MetadataSetListEntry) sets_list.getSelectedValue();
+		    MetadataSet set = (MetadataSet) metadata_set_list_entry.getMetadataSet();
+		    elements_list.setListData(new Vector(set.getMetadataSetElements()));
+		}
+		else {
+		    elements_list.setListData(new String[0]);
+		}
+	    }
+	}
+    }
+
+
+    private class MetadataSetListEntry
+	extends JCheckBox
+    {
+	private MetadataSet metadata_set = null;
+
+	public MetadataSetListEntry(MetadataSet metadata_set)
+	{
+	    this.metadata_set = metadata_set;
+	}
+
+	public MetadataSet getMetadataSet()
+	{
+	    return metadata_set;
+	}
+
+	public String getText()
+	{
+	    if (metadata_set == null) {
+		return null;
+	    }
+
+	    String interface_language_code = Configuration.getLanguage();
+	    String metadata_set_name = MetadataTools.getMetadataSetAttribute(metadata_set, "Name", interface_language_code, "en");
+	    return metadata_set_name + " (" + metadata_set.getNamespace() + ")";
+	}
+    }
+
+
+    private class OKButtonListener
 	implements ActionListener {
 	public void actionPerformed(ActionEvent event) {
 	    // See if the user has selected no metadata sets, and if so confirm thats what they really want.
-	    ArrayList selected_sets = sets_list.getSelected();
+	    ArrayList selected_sets = sets_list.getSelectedMetadataSets();
 	    cancelled = false;
 	    if(selected_sets.size() == 0) {
Index: /trunk/gli/src/org/greenstone/gatherer/gui/OptionsPane.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/OptionsPane.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/OptionsPane.java	(revision 8313)
@@ -52,4 +52,5 @@
 import org.greenstone.gatherer.collection.Collection;
 import org.greenstone.gatherer.collection.CollectionManager;
+import org.greenstone.gatherer.metadata.MetadataSetManager;
 import org.greenstone.gatherer.util.AppendLineOnlyFileDocument;
 import org.greenstone.gatherer.util.AppendLineOnlyFileDocumentOwner;
@@ -424,7 +425,7 @@
 		}
 		if (argument.getType() == Argument.METADATUM) {
-		    Vector meta_list = Gatherer.c_man.getCollection().msm.getAssignedElements();
-		    for (int i = 0; i < meta_list.size(); i++) {
-			combobox.addItem(meta_list.get(i));
+		    ArrayList every_metadata_set_element = MetadataSetManager.getEveryMetadataSetElement();
+		    for (int i = 0; i < every_metadata_set_element.size(); i++) {
+			combobox.addItem(every_metadata_set_element.get(i));
 		    }
 		}
Index: /trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderListener.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderListener.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/HeaderListener.java	(revision 8313)
@@ -37,17 +37,10 @@
 package org.greenstone.gatherer.gui.metaaudit;
 
-/**************************************************************************************
- * Title:        Gatherer
- * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
- * Company:      The University of Waikato
- * Written:      03/09/02
- * Revised:      
- * @author John Thompson, 9826509
- * @version 2.3
- **************************************************************************************/
+
 import de.qfs.lib.gui.TableModelSorter;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
+import org.greenstone.gatherer.metadata.MetadataAuditTableModel;
 
 public class HeaderListener
@@ -67,5 +60,5 @@
 	Filter filter_model = table.getFilter();
 	Autofilter filter = filter_model.getFilter(clicked_column);
-	MetaAuditModel model = table.getOriginalModel();
+	MetadataAuditTableModel model = table.getOriginalModel();
 	ArrayList default_values = model.getColumnValues(clicked_column);
 	String column_name = model.getColumnName(clicked_column);
Index: unk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditModel.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditModel.java	(revision 8312)
+++ 	(revision )
@@ -1,180 +1,0 @@
-/**
- *#########################################################################
- *
- * A component of the Gatherer application, part of the Greenstone digital
- * library suite from the New Zealand Digital Library Project at the
- * University of Waikato, New Zealand.
- *
- * <BR><BR>
- *
- * Author: John Thompson, Greenstone Digital Library, University of Waikato
- *
- * <BR><BR>
- *
- * Copyright (C) 1999 New Zealand Digital Library Project
- *
- * <BR><BR>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * <BR><BR>
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * <BR><BR>
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *########################################################################
- */
-package org.greenstone.gatherer.gui.metaaudit;
-
-import java.awt.*;
-import java.util.*;
-import java.io.*;
-import javax.swing.table.*;
-import org.greenstone.gatherer.Dictionary;
-import org.greenstone.gatherer.Gatherer;
-import org.greenstone.gatherer.file.FileNode;
-import org.greenstone.gatherer.msm.Metadata;
-import org.greenstone.gatherer.msm.MSMUtils;
-
-/**
- * @author John Thompson, Greenstone Digital Library, University of Waikato
- * @version 2.1 
- */
-public class MetaAuditModel
-    extends AbstractTableModel {
-
-    private ArrayList elements;
-    private MetadataTableCache data;
-
-    public MetaAuditModel(FileNode records[]) {
-	this.elements = new ArrayList(Gatherer.c_man.getCollection().msm.getElements());
-	Collections.sort(this.elements, MSMUtils.METADATA_COMPARATOR);
-	this.data = new MetadataTableCache(elements.size() + 1);
-	// Work our way through the record array provided, adding files, skipping blanks and recursively searching directories.
-	for(int i = 0; records != null && i < records.length; i++) {
-	    if(records[i] != null) {
-		addRecord(records[i]);
-	    }
-	}
-    }
-    public Class getColumnClass(int column) {
-	return ArrayList.class;
-    }
-    public int getColumnCount() {
-	return elements.size() + 1;
-    }
-    public String getColumnName(int column) {
-	String result;
-	if(column == 0) {
-	    result = Dictionary.get("AuditTable.File");
-	}
-	else {
-	    result = elements.get(column - 1).toString();
-	}
-	return result;
-    }
-    public ArrayList getColumnValues(int column) {
-	ArrayList column_values = new ArrayList();
-	if(0 <= column && column < getColumnCount()) {
-	    for(int i = 0; i < data.size(); i++) {
-		ArrayList values = (ArrayList) data.get(i, column);
-		for(int j = 0; j < values.size(); j++) {
-		    column_values.add(values.get(j).toString());
-		}
-	    }
-	}
-	return column_values;
-    }
-    public int getRowCount() {
-	return data.size();
-    }
-    public Object getValueAt(int row, int column) {
-	Object result = "";
-	if(0 <= row && row < data.size() && 0 <= column && column < elements.size() + 1) {
-	    result = data.get(row, column);
-	}
-	return result;
-    }
-
-    public void reset() {
-    }
-
-    private void addRecord(FileNode record) {
-	if(record.isLeaf()) {
-	    File file = record.getFile();
-	    data.newRow();
-	    data.put(0, file.getName());
-	    ArrayList metadatum = Gatherer.c_man.getCollection().gdm.getAllMetadata(file);
-	    for(int i = 0; i < metadatum.size(); i++) {
-		Metadata metadata = (Metadata) metadatum.get(i);
-		int index = elements.indexOf(metadata.getElement())+1;
-		if (index!=0) {
-		    // some elements are hidden and dont appear in teh table
-		    data.put(index, metadata.getValueNode());
-		}
-	    }
-	}
-	else {
-	    for(int i = 0; i < record.getChildCount(); i++) {
-		addRecord((FileNode)record.getChildAt(i));
-	    }
-	}
-    }
-
-    private class MetadataTableCache {
-	private ArrayList data;
-	private ArrayList current_row[];
-	private int columns;
-	private RowComparator row_comparator = new RowComparator();
-	public MetadataTableCache(int columns) {
-	    this.columns = columns;
-	    this.data = new ArrayList();
-	}
-
-	public ArrayList get(int row, int column) {
-	    ArrayList array_list[] = (ArrayList[]) data.get(row);
-	    return array_list[column];
-	}
-
-	public void newRow() {
-	    if(current_row != null) {
-		for(int i = 0; i < columns; i++) {
-		    Collections.sort(current_row[i], row_comparator);
-		}
-	    }
-	    current_row = new ArrayList[columns];
-	    for(int i = 0; i < columns; i++) {
-		current_row[i] = new ArrayList();
-	    }
-	    data.add(current_row);
-	}
-
-	public void put(int column, Object value) {
-	    current_row[column].add(value);
-	}
-
-	public int size() {
-	    return data.size();
-	}
-    }
-
-    private class RowComparator
-	implements Comparator {
-	public int compare(Object o1, Object o2) {
-	    return o1.toString().compareTo(o2.toString());
-	}
-	public boolean equals(Object obj) {
-	    return toString().equals(obj.toString());
-	}
-    }
-}
Index: /trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditTable.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditTable.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/gui/metaaudit/MetaAuditTable.java	(revision 8313)
@@ -44,4 +44,6 @@
 import javax.swing.table.*;
 import org.greenstone.gatherer.file.FileNode;
+import org.greenstone.gatherer.metadata.MetadataAuditTableModel;
+
 
 /**
@@ -63,5 +65,5 @@
     private MetaAuditFrame parent_frame;
 
-    private MetaAuditModel model;
+    private MetadataAuditTableModel metadata_audit_table_model;
 
     private SortedTableHelper helper;
@@ -83,7 +85,10 @@
     }
 
-    public MetaAuditModel getOriginalModel() {
-	return model;
-    }
+
+   public MetadataAuditTableModel getOriginalModel()
+   {
+      return metadata_audit_table_model;
+   }
+
 
     public TableModelSorter getSorter() {
@@ -105,8 +110,9 @@
 	wait(true);
 	initial_state = true;
-	///ystem.err.println("Build new Model - should only be called once per click!");
-	model = new MetaAuditModel(records);
-	setModel(model);
-	filter = new Filter(model.getColumnCount());
+	// System.err.println("Build new Model - should only be called once per click!");
+	metadata_audit_table_model = new MetadataAuditTableModel();
+	metadata_audit_table_model.rebuild(records);
+	setModel(metadata_audit_table_model);
+	filter = new Filter(metadata_audit_table_model.getColumnCount());
 	helper = new SortedTableHelper (this, filter, new DefaultTableModelSorter(), header_renderer, null);
 	helper.prepareTable();
Index: /trunk/gli/src/org/greenstone/gatherer/shell/GShell.java
===================================================================
--- /trunk/gli/src/org/greenstone/gatherer/shell/GShell.java	(revision 8312)
+++ /trunk/gli/src/org/greenstone/gatherer/shell/GShell.java	(revision 8313)
@@ -53,5 +53,5 @@
 import org.greenstone.gatherer.cdm.CollectionMetaManager;
 import org.greenstone.gatherer.cdm.CollectionMeta;
-import org.greenstone.gatherer.msm.GreenstoneArchiveParser;
+import org.greenstone.gatherer.metadata.DocXMLFileManager;
 import org.greenstone.gatherer.util.StaticStrings; 
 import org.greenstone.gatherer.util.Utility;
@@ -542,29 +542,30 @@
 		}
 
-		// extract any new metadata from the archive directory.
+		// Refresh the DocXMLFileManager
 		fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Parsing_Metadata_Start"), status, null);
-		new GreenstoneArchiveParser(progress, this);
+		DocXMLFileManager.clearDocXMLFiles();
+		DocXMLFileManager.loadDocXMLFiles(new File(Gatherer.c_man.getCollectionArchive()));
 		fireMessage(type, typeAsString(type) + "> " + Dictionary.get("GShell.Parsing_Metadata_Complete"), status, null);
 	    }
 
-	    else if(type == BUILD) {
+// 	    else if(type == BUILD) {
 		
-		// download the building directory (if gsdl server is remote)			
-		if (Gatherer.isGsdlRemote) {
-		    if (progress!=null) {
-			progress.messageOnProgressBar("Downloading index data from server");
-		    }
-
-		    Utility.delete(Gatherer.c_man.getCollectionBuild()); // remove current build dir
-		    GathererApplet.download_url_zip(col_name,"building");
-		    Utility.unzip(col_name);
-
-		    if (progress!=null) {
-			progress.messageOnProgressBar("");
-		    }
-
-		}
-
-	    }
+// 		// download the building directory (if gsdl server is remote)			
+// 		if (Gatherer.isGsdlRemote) {
+// 		    if (progress!=null) {
+// 			progress.messageOnProgressBar("Downloading index data from server");
+// 		    }
+
+// 		    Utility.delete(Gatherer.c_man.getCollectionBuild()); // remove current build dir
+// 		    GathererApplet.download_url_zip(col_name,"building");
+// 		    Utility.unzip(col_name);
+
+// 		    if (progress!=null) {
+// 			progress.messageOnProgressBar("");
+// 		    }
+
+// 		}
+
+// 	    }
 	}
 
