r18349 - gnucash/trunk/src - Fix enhancement bug 101456 - 'Find' dialog cumbersome for Business functions
Phil Longstaff
plongstaff at code.gnucash.org
Fri Sep 25 20:07:49 EDT 2009
Author: plongstaff
Date: 2009-09-25 20:07:49 -0400 (Fri, 25 Sep 2009)
New Revision: 18349
Trac: http://svn.gnucash.org/trac/changeset/18349
Modified:
gnucash/trunk/src/business/business-gnome/business-gnome-utils.c
gnucash/trunk/src/business/business-gnome/dialog-invoice.c
gnucash/trunk/src/gnome-search/gnc-general-search.c
gnucash/trunk/src/gnome-search/gnc-general-search.h
Log:
Fix enhancement bug 101456 - 'Find' dialog cumbersome for Business functions
When opening an invoice search dialog from a specific company, list is populated by all invoices.
Patch by Geert Janssens
Modified: gnucash/trunk/src/business/business-gnome/business-gnome-utils.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/business-gnome-utils.c 2009-09-25 23:36:56 UTC (rev 18348)
+++ gnucash/trunk/src/business/business-gnome/business-gnome-utils.c 2009-09-26 00:07:49 UTC (rev 18349)
@@ -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;
Modified: gnucash/trunk/src/business/business-gnome/dialog-invoice.c
===================================================================
--- gnucash/trunk/src/business/business-gnome/dialog-invoice.c 2009-09-25 23:36:56 UTC (rev 18348)
+++ gnucash/trunk/src/business/business-gnome/dialog-invoice.c 2009-09-26 00:07:49 UTC (rev 18349)
@@ -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));
Modified: gnucash/trunk/src/gnome-search/gnc-general-search.c
===================================================================
--- gnucash/trunk/src/gnome-search/gnc-general-search.c 2009-09-25 23:36:56 UTC (rev 18348)
+++ gnucash/trunk/src/gnome-search/gnc-general-search.c 2009-09-26 00:07:49 UTC (rev 18349)
@@ -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,179 @@
}
+/** 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 = qof_query_create_for (type);
+ qof_query_add_boolean_match(q, g_slist_prepend
+ (NULL, QOF_PARAM_ACTIVE), TRUE, QOF_QUERY_AND);
+ qof_query_set_book (q, book);
+ list = qof_query_run(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 +446,30 @@
* 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 +482,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 +516,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);
Modified: gnucash/trunk/src/gnome-search/gnc-general-search.h
===================================================================
--- gnucash/trunk/src/gnome-search/gnc-general-search.h 2009-09-25 23:36:56 UTC (rev 18348)
+++ gnucash/trunk/src/gnome-search/gnc-general-search.h 2009-09-26 00:07:49 UTC (rev 18349)
@@ -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);
More information about the gnucash-changes
mailing list