Index: gli/trunk/src/org/greenstone/gatherer/cdm/Argument.java
===================================================================
--- gli/trunk/src/org/greenstone/gatherer/cdm/Argument.java	(revision 18910)
+++ gli/trunk/src/org/greenstone/gatherer/cdm/Argument.java	(revision 18911)
@@ -72,8 +72,9 @@
 	/** An element of the argument type enumeration specifying a metadata set combobox control. */
 	static final public byte METADATA_SET_NAMESPACE = 9;
-
-	///////////kk added the number was 9, I changed it to 10//////////////
 	/** An element of the argument type enumeration specifying a text field. */
 	static final public byte URL = 10;
+  /** An editable combo box */
+  static final public byte ENUM_STRING = 11;
+
 	/////////////////////////////////////////////////////////////////
 
@@ -94,5 +95,5 @@
 	/** The DOM element this argument is built around, if any. */
 	private Element element;
-	/** If the argument is of type ENUM then this map holds all the various options. Each entry is an &lt;option value&gt; -&gt; &lt;description&gt; mapping. */
+	/** If the argument is of type ENUM or ENUM_STRING then this map holds all the various options. Each entry is an &lt;option value&gt; -&gt; &lt;description&gt; mapping. */
 	private ArrayList option_list = null;
 	/** A default value for parameter-type arguments. May be a Perl pattern. */
@@ -123,5 +124,5 @@
 	 */
 	public void addOption(String name, String desc) {
-		if(type == ENUM && name != null) {
+	  if((type == ENUM || type == ENUM_STRING) && name != null) {
 			if(desc == null) {
 				desc = "";
@@ -412,4 +413,8 @@
 		if(new_type.equalsIgnoreCase(StaticStrings.ENUM_STR)) {
 			this.type = ENUM;
+			option_list = new ArrayList();
+		}
+		else if(new_type.equalsIgnoreCase(StaticStrings.ENUM_STRING_STR)) {
+			this.type = ENUM_STRING;
 			option_list = new ArrayList();
 		}
Index: gli/trunk/src/org/greenstone/gatherer/cdm/ArgumentControl.java
===================================================================
--- gli/trunk/src/org/greenstone/gatherer/cdm/ArgumentControl.java	(revision 18910)
+++ gli/trunk/src/org/greenstone/gatherer/cdm/ArgumentControl.java	(revision 18911)
@@ -92,10 +92,21 @@
 
     switch(argument.getType()) {
+    case Argument.ENUM_STRING:
     case Argument.ENUM:
       ArrayList option_list = argument.getOptions();
-      value_control = new GComboBox(option_list.toArray(), false, false);
+      boolean editable = false;
+      if (argument.getType() == Argument.ENUM_STRING) {
+	editable = true;
+      }
+      value_control = new GComboBox(option_list.toArray(), editable, false);
       value_control.setComponentOrientation(Dictionary.getOrientation());
 			
-      selectValue((JComboBox)value_control, initial_value); // also sets the tooltip
+      boolean found = selectValue((JComboBox)value_control, initial_value); // also sets the tooltip
+      if (!found && argument.getType() == Argument.ENUM_STRING) {
+	// Its a custom item
+	((JComboBox) value_control).addItem(initial_value);
+	((JComboBox) value_control).setSelectedItem(initial_value);
+      }
+
       ((JComboBox)value_control).addActionListener(new ToolTipUpdater());
       break;
@@ -158,5 +169,5 @@
       }
       if (existing_value != null && existing_value.length() > 0) {
-	boolean found = selectValue((JComboBox) value_control, existing_value);
+	found = selectValue((JComboBox) value_control, existing_value);
 	// It's possible that this is a custom value and so doesn't exist in the combobox
 	if (!found) {
@@ -244,5 +255,5 @@
     // Listener
     if(value_control != null) {
-      if (argument.getType() != Argument.ENUM) {
+      if (argument.getType() != Argument.ENUM && argument.getType() != Argument.ENUM_STRING) {
 	// enums have already set tooltips based on option value
 	value_control.setToolTipText(tip);
@@ -325,77 +336,16 @@
       case Argument.ENUM:
 	Argument.ArgumentOption option = (Argument.ArgumentOption)((JComboBox)value_control).getSelectedItem();
-	if(option != null && option.name.length() > 0) {
-	  argument.setValue(option.name);
-	}
-	else {
-	  String args[] = new String[1];
-	  args[0] = argument.getName();
-	  if(argument.isRequired()) {
-	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
-	  }
-	  // They've left the field blank
-	  else {
-	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
-	    argument.setValue(null);
-	  }
-	  args = null;
-	  return false;
-	}
+	// its impossible not to choose an entry
+	argument.setValue(option.name);
 	argument.setAssigned(true);
 	return true;
-      case Argument.FLAG:
-	// Should have already been handled above.
-	argument.setAssigned(true);
-	return true;
-      case Argument.INTEGER:
-	result = ((JSpinner)value_control).getValue().toString();
-	if(result.length() > 0) {
-	  // Test if the value entered is a valid int.
-	  try {
-	    int x = Integer.parseInt(result);
-	  }
-	  catch(NumberFormatException nfe) {
-	    String args[] = new String[2];
-	    args[0] = argument.getName();
-	    args[1] = result;
-	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.Bad_Integer", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
-	    args = null;
-	    return false;
-	  }
-	  argument.setValue(result);
-	}
-	else {
-	  String args[] = new String[1];
-	  args[0] = argument.getName();
-	  if(argument.isRequired()) {
-	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
-	  }
-	  // They've left the field blank
-	  else {
-	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
-	    argument.setValue(null);
-	  }
-	  args = null;
-	  return false;
-	}
-	argument.setAssigned(true);
-	return true;
-      case Argument.LANGUAGE:
-	String language = (((JComboBox)value_control).getSelectedItem()).toString();
-	argument.setValue(language);
-	// 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.METADATUM:
-      case Argument.METADATA:
-	Object new_value_raw = ((JComboBox) value_control).getSelectedItem();
-	if (new_value_raw instanceof MetadataElement) {
-	  argument.setValue(((MetadataElement) new_value_raw).getFullName());
-	}
-	else {
-	  // But we have to be careful as an arbitary string object could be zero length
+      case Argument.ENUM_STRING:
+	Object new_value_raw = ((JComboBox)value_control).getSelectedItem();
+	if (new_value_raw instanceof Argument.ArgumentOption) {
+	  argument.setValue(((Argument.ArgumentOption)new_value_raw).name);
+	} else {
+	  // have entered a new string
 	  String new_value = new_value_raw.toString();
-	  ///ystem.err.println("The current value is: " + new_value);
-	  if(new_value.length() > 0) {
+	  if (new_value.length() > 0) {
 	    argument.setValue(new_value);
 	  }
@@ -417,4 +367,77 @@
 	argument.setAssigned(true);
 	return true;
+      case Argument.FLAG:
+	// Should have already been handled above.
+	argument.setAssigned(true);
+	return true;
+      case Argument.INTEGER:
+	result = ((JSpinner)value_control).getValue().toString();
+	if(result.length() > 0) {
+	  // Test if the value entered is a valid int.
+	  try {
+	    int x = Integer.parseInt(result);
+	  }
+	  catch(NumberFormatException nfe) {
+	    String args[] = new String[2];
+	    args[0] = argument.getName();
+	    args[1] = result;
+	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.Bad_Integer", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+	    args = null;
+	    return false;
+	  }
+	  argument.setValue(result);
+	}
+	else {
+	  String args[] = new String[1];
+	  args[0] = argument.getName();
+	  if(argument.isRequired()) {
+	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+	  }
+	  // They've left the field blank
+	  else {
+	    JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+	    argument.setValue(null);
+	  }
+	  args = null;
+	  return false;
+	}
+	argument.setAssigned(true);
+	return true;
+      case Argument.LANGUAGE:
+	String language = (((JComboBox)value_control).getSelectedItem()).toString();
+	argument.setValue(language);
+	// 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.METADATUM:
+      case Argument.METADATA:
+	new_value_raw = ((JComboBox) value_control).getSelectedItem();
+	if (new_value_raw instanceof MetadataElement) {
+	  argument.setValue(((MetadataElement) new_value_raw).getFullName());
+	}
+	else {
+	  // But we have to be careful as an arbitary string object could be zero length
+	  String new_value = new_value_raw.toString();
+	  ///ystem.err.println("The current value is: " + new_value);
+	  if(new_value.length() > 0) {
+	    argument.setValue(new_value);
+	  }
+	  else {
+	    String args[] = new String[1];
+	    args[0] = argument.getName();
+	    if(argument.isRequired()) {
+	      JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.Required_Argument", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+	    }
+	    // They've left the field blank
+	    else {
+	      JOptionPane.showMessageDialog(this, Dictionary.get("CDM.ArgumentConfiguration.No_Value", args), Dictionary.get("CDM.ArgumentConfiguration.Error_Title"), JOptionPane.ERROR_MESSAGE);
+	      argument.setValue(null);
+	    }
+	    args = null;
+	    return false;
+	  }
+	}
+	argument.setAssigned(true);
+	return true;
       case Argument.REGEXP:
       case Argument.STRING:
Index: gli/trunk/src/org/greenstone/gatherer/util/StaticStrings.java
===================================================================
--- gli/trunk/src/org/greenstone/gatherer/util/StaticStrings.java	(revision 18910)
+++ gli/trunk/src/org/greenstone/gatherer/util/StaticStrings.java	(revision 18911)
@@ -99,4 +99,5 @@
     static final public String ENTRY_ELEMENT = "Entry";
     static final public String ENUM_STR = "enum";
+    static final public String ENUM_STRING_STR = "enumstring";
     static final public String EQUALS_CHARACTER = "=";
     static final public String EXCLAMATION_CHARACTER = "!";
