Index: src/business/business-gnome/dialog-invoice.c
===================================================================
--- src/business/business-gnome/dialog-invoice.c	(revision 18306)
+++ src/business/business-gnome/dialog-invoice.c	(working copy)
@@ -1110,8 +1110,8 @@
     case NEW_INVOICE:
     case MOD_INVOICE:
       iw->job_choice =
-	gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."),
-				gnc_invoice_select_job_cb, iw);
+	gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."), TRUE,
+				gnc_invoice_select_job_cb, iw, iw->book);
 
       gnc_general_search_set_selected (GNC_GENERAL_SEARCH (iw->job_choice),
 				       gncOwnerGetJob (&iw->job));
@@ -1181,8 +1181,8 @@
       iw->proj_job_choice = NULL;
     } else {
       iw->proj_job_choice =
-	gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."),
-				gnc_invoice_select_proj_job_cb, iw);
+	gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."), TRUE,
+				gnc_invoice_select_proj_job_cb, iw, iw->book);
 
       gnc_general_search_set_selected (GNC_GENERAL_SEARCH(iw->proj_job_choice),
 				       gncOwnerGetJob (&iw->proj_job));
Index: src/business/business-gnome/business-gnome-utils.c
===================================================================
--- src/business/business-gnome/business-gnome-utils.c	(revision 18306)
+++ src/business/business-gnome/business-gnome-utils.c	(working copy)
@@ -64,13 +64,16 @@
   GNCSearchCB search_cb = NULL;
   const char *type_name = NULL;
   const char *text = NULL;
+  gboolean text_editable = FALSE;
 
   switch (type) {
   case GNCSEARCH_TYPE_SELECT:
     text = _("Select...");
+    text_editable = TRUE;
     break;
   case GNCSEARCH_TYPE_EDIT:
     text = _("Edit...");
+    text_editable = FALSE;
   };
 
   switch (owner->type) {
@@ -115,7 +118,7 @@
     return NULL;
   }
 
-  edit = gnc_general_search_new (type_name, text, search_cb, book);
+  edit = gnc_general_search_new (type_name, text, text_editable, search_cb, book, book);
   if (!edit)
     return NULL;
 
@@ -251,7 +254,7 @@
   isi->label = label;
 
   edit = gnc_general_search_new (GNC_INVOICE_MODULE_NAME, _("Select..."),
-				 gnc_invoice_select_search_cb, isi);
+				 TRUE, gnc_invoice_select_search_cb, isi, isi->book);
   if (!edit) {
     g_free(isi);
     return NULL;

Index: src/gnome-search/gnc-general-search.c
===================================================================
--- src/gnome-search/gnc-general-search.c	(revision 18306)
+++ src/gnome-search/gnc-general-search.c	(working copy)
@@ -51,6 +51,12 @@
 	LAST_SIGNAL
 };
 
+/* Columns used in GtkEntryCompletion's model */
+enum {
+  GSL_COLUMN_TEXT,
+  GSL_COLUMN_QOFOBJECT,
+  GSL_N_COLUMNS
+};
 
 static void gnc_general_search_init         (GNCGeneralSearch      *gsl);
 static void gnc_general_search_class_init   (GNCGeneralSearchClass *class);
@@ -256,14 +262,175 @@
 
 }
 
+/**  The completion attached to search edit widget has selected a
+ *   match.  This function extracts the completed string from the
+ *   completion code's temporary model, and uses that to set the iterator
+ *   and object data of the selection for use when the user leaves the widget.
+ *   This should always point to a valid iterator since the user
+ *   made the selection from a list of available object names.
+ *
+ *   @param completion Unused.
+ *
+ *   @param comp_model A temporary model used by completion code that
+ *   contains only the current matches.
+ *
+ *   @param comp_iter The iter in the completion's temporary model
+ *   that represents the user selected match.
+ *
+ *   @param cbe A pointer to a currency entry widget. */
+static gboolean
+gnc_gsl_match_selected_cb (GtkEntryCompletion *completion,
+			   GtkTreeModel       *comp_model,
+			   GtkTreeIter        *comp_iter,
+			   GNCGeneralSearch   *gsl)
+{
+	QofObject * qofobject;
+
+	gtk_tree_model_get(comp_model, comp_iter, GSL_COLUMN_QOFOBJECT, &qofobject, -1);
+	gnc_general_search_set_selected (gsl, qofobject);
+	return FALSE;
+}
+
+/**  The focus left the general search edit widget, so reset the widget to
+ *   its last known good value.  If the widget value contained a valid
+ *   value then this is a noop.  Otherwise the widget will be reset
+ *   to the last user selected value.  This latter state will occur
+ *   if the user has typed characters directly into the widget but not
+ *   selected a completion.
+ *
+ *   @param entry The entry widget in which the user is typing.
+ *
+ *   @param event Unused.
+ *
+ *   @param gsl A pointer to a general search widget. */
+static gboolean
+gnc_gsl_focus_out_cb (GtkEntry *entry,
+		      GdkEventFocus *event,
+		      GNCGeneralSearch *gsl)
+{
+	const gchar	*text;
+	GtkEntryCompletion *completion;
+	GtkTreeModel *model;
+	GtkTreeIter iter;
+	gchar *lc_text, *tree_string, *lc_tree_string;
+	gboolean match, valid_iter;
+	QofObject *qofobject;
+	gpointer selected_item=NULL;
+
+	/* Attempt to match the current text to a qofobject. */
+	completion = gtk_entry_get_completion(entry);
+	model = gtk_entry_completion_get_model(completion);
+
+	/* Return if completion tree is empty */
+	valid_iter = gtk_tree_model_get_iter_first(model, &iter);
+	if (!valid_iter)
+		return FALSE;
+
+	text = gtk_entry_get_text(entry);
+	lc_text = g_utf8_strdown(text, -1);
+
+	/* The last, valid selected entry can match the entered text
+	 * No need to search further in that case */
+	if (gsl->selected_item)
+	{
+		GNCGeneralSearchPrivate *	priv;
+
+		priv=_PRIVATE(gsl);
+		tree_string = g_strdup(qof_object_printable(priv->type, gsl->selected_item));
+		lc_tree_string = g_utf8_strdown(tree_string, -1);
+		match = g_utf8_collate(lc_text, lc_tree_string) == 0;
+		g_free(tree_string);
+		g_free(lc_tree_string);
+		if (match)
+			selected_item = gsl->selected_item;
+	}
+
+	/* Otherwise, find a match in the completion list */
+	while (valid_iter && !selected_item)
+	{
+		gtk_tree_model_get(model, &iter, GSL_COLUMN_TEXT, &tree_string, -1);
+		lc_tree_string = g_utf8_strdown(tree_string, -1);
+		match = g_utf8_collate(lc_text, lc_tree_string) == 0;
+		g_free(tree_string);
+		g_free(lc_tree_string);
+		if (match)
+		{
+			gtk_tree_model_get(model, &iter, GSL_COLUMN_QOFOBJECT, &qofobject, -1);
+			selected_item = qofobject;
+		}
+		else
+			valid_iter = gtk_tree_model_iter_next(model, &iter);
+	}
+
+	g_free(lc_text);
+	gnc_general_search_set_selected (gsl, selected_item);
+	return FALSE;
+}
+
 static void
-create_children (GNCGeneralSearch *gsl, const char *label)
+create_children (GNCGeneralSearch *gsl, const char *label, gboolean text_editable,
+			GNCIdTypeConst type, QofBook *book)
 {
+	GtkListStore *	list_store;
+	QueryNew *	q;
+	GtkTreeIter iter;
+	GList * list, * it;
+	GtkEntryCompletion *completion;
+
+	/* Add a text entry box */
 	gsl->entry = gtk_entry_new ();
-	gtk_editable_set_editable (GTK_EDITABLE (gsl->entry), FALSE);
+	if (!text_editable)
+		gtk_editable_set_editable (GTK_EDITABLE (gsl->entry), FALSE);
 	gtk_box_pack_start (GTK_BOX (gsl), gsl->entry, TRUE, TRUE, 0);
+
+
+	/* Setup a GtkEntryCompletion auxiliary widget for our Entry box
+	 * This requires an internal table ("model") with the possible
+	 * auto-completion text entries */
+
+	/* Query for the requested object type */
+	q = gncQueryCreateFor (type);
+ 	gncQuerySetBook (q, book);
+	list = gncQueryRun(q);
+
+	/* Setup the internal model */
+	list_store = gtk_list_store_new (GSL_N_COLUMNS, G_TYPE_STRING, G_TYPE_OBJECT);
+	for (it = list; it != NULL ; it = it->next)
+    {
+		char * name;
+
+		name = g_strdup(qof_object_printable(type, it->data));
+		/* Add a new row to the model */
+		if (name)
+		{
+		gtk_list_store_append (list_store, &iter);
+		gtk_list_store_set (list_store, &iter,
+                          GSL_COLUMN_TEXT, name,
+                          GSL_COLUMN_QOFOBJECT, G_OBJECT(it->data),
+                          -1);
+			g_free(name);
+		}
+
+    }
+
+	gncQueryDestroy(q);
+
+	/* Add the GtkEntryCompletion widget */
+	completion = gtk_entry_completion_new();
+	gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(list_store));
+	gtk_entry_completion_set_text_column(completion, 0);
+	gtk_entry_completion_set_inline_completion(completion, TRUE);
+	gtk_entry_set_completion(GTK_ENTRY(gsl->entry), completion);
+
+	g_signal_connect (G_OBJECT (completion), "match_selected",
+			  G_CALLBACK (gnc_gsl_match_selected_cb), gsl);
+	g_signal_connect (G_OBJECT (gsl->entry), "focus-out-event",
+			  G_CALLBACK (gnc_gsl_focus_out_cb), gsl);
+
+	g_object_unref(completion);
 	gtk_widget_show (gsl->entry);
 
+	/* Add the search button */
 	gsl->button = gtk_button_new_with_label (label);
 	gtk_box_pack_start (GTK_BOX (gsl), gsl->button, FALSE, FALSE, 0);
 	g_signal_connect (G_OBJECT (gsl->button), "clicked",
@@ -275,13 +442,26 @@
  * gnc_general_search_new:
  *
  * Creates a new GNCGeneralSearch widget which can be used to provide
- * an easy way to choose selections
+ * an easy way to choose selections.
  *
- * Returns a GNCGeneralSearch widget.
+ * @param type The type of object that this widget will be used for.
+ * This parameter is a GNCIdTypeConst.
+ * @param label The label for the GtkButton child widget.
+ * @param text_editable switch to enable or disable direct text entry
+ * @param search_cb The callback function to use when an object has been
+ * selected in the search dialog. This dialog is created when clicking on
+ * the GtkButton child widget.
+ * @param user_data Generic pointer to context relevant data that can be
+ * used by callback functions later on. At present, depending on the context
+ * this can be a QofBook, a GncISI structure or a InvoiceWindow structure.
+ * @param book Pointer to the QofBook for this search widget. This is used for
+ * the autocompletion in the text entry widget.
+ *
+ * @return a GNCGeneralSearch widget.
  */
 GtkWidget *
-gnc_general_search_new (GNCIdTypeConst type, const char *label,
-			GNCSearchCB search_cb, gpointer user_data)
+gnc_general_search_new (GNCIdTypeConst type, const char *label, gboolean text_editable,
+			GNCSearchCB search_cb, gpointer user_data, QofBook *book)
 {
 	GNCGeneralSearch *gsl;
 	GNCGeneralSearchPrivate *priv;
@@ -294,7 +474,7 @@
 
 	gsl = g_object_new (GNC_TYPE_GENERAL_SEARCH, NULL);
 
-	create_children (gsl, label);
+	create_children (gsl, label, text_editable, type, book);
 
 	priv = _PRIVATE(gsl);
 	priv->type = type;
@@ -328,10 +508,10 @@
 	priv = _PRIVATE(gsl);
 	if (selection != gsl->selected_item) {
 		gsl->selected_item = selection;
-		reset_selection_text (gsl);
 		g_signal_emit(gsl,
 			      general_search_signals[SELECTION_CHANGED], 0);
 	}
+	reset_selection_text (gsl);
 
 	gnc_gui_component_clear_watches (priv->component_id);
 
Index: src/gnome-search/gnc-general-search.h
===================================================================
--- src/gnome-search/gnc-general-search.h	(revision 18306)
+++ src/gnome-search/gnc-general-search.h	(working copy)
@@ -74,8 +74,10 @@
 
 GtkWidget *gnc_general_search_new            (GNCIdTypeConst type,
 					      const char *label,
+					      gboolean text_editable,
 					      GNCSearchCB search_cb,
-					      gpointer user_data);
+					      gpointer user_data,
+					      QofBook *book);
 
 void	   gnc_general_search_allow_clear    (GNCGeneralSearch *gsl,
 					      gboolean allow_clear);
