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


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18349 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Phil Longstaff 2009-09-26 00:07:49 +00:00
parent 5ee9dcade2
commit d5a4c757ff
4 changed files with 209 additions and 16 deletions

View File

@ -64,13 +64,16 @@ static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
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 @@ static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
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 @@ GtkWidget * gnc_invoice_select_create (GtkWidget *hbox, QofBook *book,
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;

View File

@ -1110,8 +1110,8 @@ gnc_invoice_update_job_choice (InvoiceWindow *iw)
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 @@ gnc_invoice_update_proj_job (InvoiceWindow *iw)
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));

View File

@ -51,6 +51,12 @@ enum
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 @@ search_cb(GtkButton * button, gpointer user_data)
}
static void
create_children (GNCGeneralSearch *gsl, const char *label)
/** 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,
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 @@ create_children (GNCGeneralSearch *gsl, const char *label)
* 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 @@ gnc_general_search_new (GNCIdTypeConst type, const char *label,
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 @@ gnc_general_search_set_selected (GNCGeneralSearch *gsl, gpointer selection)
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);

View File

@ -74,8 +74,10 @@ typedef struct {
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);