mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
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:
parent
5ee9dcade2
commit
d5a4c757ff
@ -64,13 +64,16 @@ static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
|
|||||||
GNCSearchCB search_cb = NULL;
|
GNCSearchCB search_cb = NULL;
|
||||||
const char *type_name = NULL;
|
const char *type_name = NULL;
|
||||||
const char *text = NULL;
|
const char *text = NULL;
|
||||||
|
gboolean text_editable = FALSE;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case GNCSEARCH_TYPE_SELECT:
|
case GNCSEARCH_TYPE_SELECT:
|
||||||
text = _("Select...");
|
text = _("Select...");
|
||||||
|
text_editable = TRUE;
|
||||||
break;
|
break;
|
||||||
case GNCSEARCH_TYPE_EDIT:
|
case GNCSEARCH_TYPE_EDIT:
|
||||||
text = _("Edit...");
|
text = _("Edit...");
|
||||||
|
text_editable = FALSE;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (owner->type) {
|
switch (owner->type) {
|
||||||
@ -115,7 +118,7 @@ static GtkWidget * gnc_owner_new (GtkWidget *label, GtkWidget *hbox,
|
|||||||
return NULL;
|
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)
|
if (!edit)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@ -251,7 +254,7 @@ GtkWidget * gnc_invoice_select_create (GtkWidget *hbox, QofBook *book,
|
|||||||
isi->label = label;
|
isi->label = label;
|
||||||
|
|
||||||
edit = gnc_general_search_new (GNC_INVOICE_MODULE_NAME, _("Select..."),
|
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) {
|
if (!edit) {
|
||||||
g_free(isi);
|
g_free(isi);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1110,8 +1110,8 @@ gnc_invoice_update_job_choice (InvoiceWindow *iw)
|
|||||||
case NEW_INVOICE:
|
case NEW_INVOICE:
|
||||||
case MOD_INVOICE:
|
case MOD_INVOICE:
|
||||||
iw->job_choice =
|
iw->job_choice =
|
||||||
gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."),
|
gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."), TRUE,
|
||||||
gnc_invoice_select_job_cb, iw);
|
gnc_invoice_select_job_cb, iw, iw->book);
|
||||||
|
|
||||||
gnc_general_search_set_selected (GNC_GENERAL_SEARCH (iw->job_choice),
|
gnc_general_search_set_selected (GNC_GENERAL_SEARCH (iw->job_choice),
|
||||||
gncOwnerGetJob (&iw->job));
|
gncOwnerGetJob (&iw->job));
|
||||||
@ -1181,8 +1181,8 @@ gnc_invoice_update_proj_job (InvoiceWindow *iw)
|
|||||||
iw->proj_job_choice = NULL;
|
iw->proj_job_choice = NULL;
|
||||||
} else {
|
} else {
|
||||||
iw->proj_job_choice =
|
iw->proj_job_choice =
|
||||||
gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."),
|
gnc_general_search_new (GNC_JOB_MODULE_NAME, _("Select..."), TRUE,
|
||||||
gnc_invoice_select_proj_job_cb, iw);
|
gnc_invoice_select_proj_job_cb, iw, iw->book);
|
||||||
|
|
||||||
gnc_general_search_set_selected (GNC_GENERAL_SEARCH(iw->proj_job_choice),
|
gnc_general_search_set_selected (GNC_GENERAL_SEARCH(iw->proj_job_choice),
|
||||||
gncOwnerGetJob (&iw->proj_job));
|
gncOwnerGetJob (&iw->proj_job));
|
||||||
|
@ -51,6 +51,12 @@ enum
|
|||||||
LAST_SIGNAL
|
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_init (GNCGeneralSearch *gsl);
|
||||||
static void gnc_general_search_class_init (GNCGeneralSearchClass *class);
|
static void gnc_general_search_class_init (GNCGeneralSearchClass *class);
|
||||||
@ -256,14 +262,179 @@ search_cb(GtkButton * button, gpointer user_data)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
/** The completion attached to search edit widget has selected a
|
||||||
create_children (GNCGeneralSearch *gsl, const char *label)
|
* 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 ();
|
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);
|
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);
|
gtk_widget_show (gsl->entry);
|
||||||
|
|
||||||
|
/* Add the search button */
|
||||||
gsl->button = gtk_button_new_with_label (label);
|
gsl->button = gtk_button_new_with_label (label);
|
||||||
gtk_box_pack_start (GTK_BOX (gsl), gsl->button, FALSE, FALSE, 0);
|
gtk_box_pack_start (GTK_BOX (gsl), gsl->button, FALSE, FALSE, 0);
|
||||||
g_signal_connect (G_OBJECT (gsl->button), "clicked",
|
g_signal_connect (G_OBJECT (gsl->button), "clicked",
|
||||||
@ -275,13 +446,30 @@ create_children (GNCGeneralSearch *gsl, const char *label)
|
|||||||
* gnc_general_search_new:
|
* gnc_general_search_new:
|
||||||
*
|
*
|
||||||
* Creates a new GNCGeneralSearch widget which can be used to provide
|
* 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 *
|
GtkWidget *
|
||||||
gnc_general_search_new (GNCIdTypeConst type, const char *label,
|
gnc_general_search_new (GNCIdTypeConst type,
|
||||||
GNCSearchCB search_cb, gpointer user_data)
|
const char *label,
|
||||||
|
gboolean text_editable,
|
||||||
|
GNCSearchCB search_cb,
|
||||||
|
gpointer user_data,
|
||||||
|
QofBook *book)
|
||||||
{
|
{
|
||||||
GNCGeneralSearch *gsl;
|
GNCGeneralSearch *gsl;
|
||||||
GNCGeneralSearchPrivate *priv;
|
GNCGeneralSearchPrivate *priv;
|
||||||
@ -294,7 +482,7 @@ gnc_general_search_new (GNCIdTypeConst type, const char *label,
|
|||||||
|
|
||||||
gsl = g_object_new (GNC_TYPE_GENERAL_SEARCH, NULL);
|
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 = _PRIVATE(gsl);
|
||||||
priv->type = type;
|
priv->type = type;
|
||||||
@ -328,10 +516,10 @@ gnc_general_search_set_selected (GNCGeneralSearch *gsl, gpointer selection)
|
|||||||
priv = _PRIVATE(gsl);
|
priv = _PRIVATE(gsl);
|
||||||
if (selection != gsl->selected_item) {
|
if (selection != gsl->selected_item) {
|
||||||
gsl->selected_item = selection;
|
gsl->selected_item = selection;
|
||||||
reset_selection_text (gsl);
|
|
||||||
g_signal_emit(gsl,
|
g_signal_emit(gsl,
|
||||||
general_search_signals[SELECTION_CHANGED], 0);
|
general_search_signals[SELECTION_CHANGED], 0);
|
||||||
}
|
}
|
||||||
|
reset_selection_text (gsl);
|
||||||
|
|
||||||
gnc_gui_component_clear_watches (priv->component_id);
|
gnc_gui_component_clear_watches (priv->component_id);
|
||||||
|
|
||||||
|
@ -74,8 +74,10 @@ typedef struct {
|
|||||||
|
|
||||||
GtkWidget *gnc_general_search_new (GNCIdTypeConst type,
|
GtkWidget *gnc_general_search_new (GNCIdTypeConst type,
|
||||||
const char *label,
|
const char *label,
|
||||||
|
gboolean text_editable,
|
||||||
GNCSearchCB search_cb,
|
GNCSearchCB search_cb,
|
||||||
gpointer user_data);
|
gpointer user_data,
|
||||||
|
QofBook *book);
|
||||||
|
|
||||||
void gnc_general_search_allow_clear (GNCGeneralSearch *gsl,
|
void gnc_general_search_allow_clear (GNCGeneralSearch *gsl,
|
||||||
gboolean allow_clear);
|
gboolean allow_clear);
|
||||||
|
Loading…
Reference in New Issue
Block a user