GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dialog-search.c
1 /*
2  * dialog-search.c -- Search Dialog
3  * Copyright (C) 2002 Derek Atkins
4  * Author: Derek Atkins <[email protected]>
5  *
6  * Copyright (c) 2006 David Hampton <[email protected]>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, contact:
20  *
21  * Free Software Foundation Voice: +1-617-542-5942
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
23  * Boston, MA 02110-1301, USA [email protected]
24  */
25 
26 #include "config.h"
27 
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 
31 #include "dialog-utils.h"
32 #include "gnc-component-manager.h"
33 #include "gnc-ui-util.h"
34 #include "gnc-ui.h"
35 #include "gnc-gui-query.h"
36 #include "gnc-query-view.h"
37 #include "gnc-prefs.h"
38 #include "gnc-session.h"
39 #include "qof.h"
40 #include "engine-helpers.h"
41 #include "qofbookslots.h"
42 
43 #include "Transaction.h" /* for the SPLIT_* and TRANS_* */
44 
45 #include "dialog-search.h"
46 #include "search-core-type.h"
47 #include "search-param.h"
48 
49 /* This static indicates the debugging module that this .o belongs to. */
50 static QofLogModule log_module = G_LOG_DOMAIN;
51 
52 #define DIALOG_SEARCH_CM_CLASS "dialog-search"
53 #define GNC_PREFS_GROUP_SEARCH_GENERAL "dialogs.search"
54 #define GNC_PREF_NEW_SEARCH_LIMIT "new-search-limit"
55 #define GNC_PREF_ACTIVE_ONLY "search-for-active-only"
56 
57 typedef enum
58 {
59  GNC_SEARCH_MATCH_ALL = 0,
60  GNC_SEARCH_MATCH_ANY = 1
61 } GNCSearchType;
62 
63 enum search_cols
64 {
65  SEARCH_COL_NAME = 0,
66  SEARCH_COL_POINTER,
67  NUM_SEARCH_COLS
68 };
69 
71 {
72  GtkWidget *dialog;
73  GtkWidget *grouping_combo;
74  GtkWidget *match_all_label;
75  GtkWidget *criteria_table;
76  GtkWidget *result_hbox;
77 
78  /* The "results" sub-window widgets */
79  GtkWidget *result_view;
80  gpointer selected_item;
81  GList *selected_item_list;
82 
83  /* The search_type radio-buttons */
84  GtkWidget *new_rb;
85  GtkWidget *narrow_rb;
86  GtkWidget *add_rb;
87  GtkWidget *del_rb;
88  GtkWidget *active_only_check;
89 
90  /* The Select button */
91  GtkWidget *select_button;
92  GList *button_list;
93 
94  /* The close/cancel buttons */
95  GtkWidget *close_button;
96  GtkWidget *cancel_button;
97 
98  /* Callbacks */
99  GNCSearchResultCB result_cb;
100  GNCSearchNewItemCB new_item_cb;
101  GNCSearchCallbackButton *buttons;
102  GNCSearchFree free_cb;
103  gpointer user_data;
104 
105  GNCSearchSelectedCB selected_cb;
106  gpointer select_arg;
107  gboolean allow_clear;
108 
109  /* What we're searching for, and how */
110  const gchar *type_label;
111  QofIdTypeConst search_for;
112  GNCSearchType grouping; /* Match Any, Match All */
113  const QofParam *get_guid; /* Function to GetGUID from the object */
114  int search_type; /* New, Narrow, Add, Delete */
115 
116  /* Our query status */
117  QofQuery *q;
118  QofQuery *start_q; /* The query to start from, if any */
119 
120  /* The list of criteria */
121  GNCSearchParam *last_param;
122  GList *params_list; /* List of GNCSearchParams */
123  GList *display_list; /* List of GNCSearchParams for Display */
124  gint num_cols; /* Number of Display Columns */
125  GList *crit_list; /* List of crit_data */
126 
127  gint component_id;
128  const gchar *prefs_group;
129 };
130 
132 {
133  GNCSearchParam *param;
134  GNCSearchCoreType *element;
135  GtkWidget *elemwidget;
136  GtkWidget *container;
137  GtkWidget *button;
138  GtkDialog *dialog;
139 };
140 
141 static void search_clear_criteria (GNCSearchWindow *sw);
142 static void gnc_search_dialog_display_results (GNCSearchWindow *sw);
143 
144 static void
145 gnc_search_callback_button_execute (GNCSearchCallbackButton *cb,
146  GNCSearchWindow *sw)
147 {
148  GNCQueryView *qview = GNC_QUERY_VIEW(sw->result_view);
149  GtkTreeSelection *selection;
150  GtkTreeModel *model;
151  GtkTreeIter iter;
152 
153  // Sanity check
154  g_assert(qview);
155  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(qview));
156  g_assert(gtk_tree_selection_get_mode(selection) == GTK_SELECTION_MULTIPLE);
157  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(qview));
158 
159  /* Do we have a callback for multi-selections ? */
160  if (cb->cb_multiselect_fn && (!cb->cb_fcn ))
161  {
162  /* We have allready populated the selected_item_list from the select row callback */
163  // We use g_list_prepend (for performance reasons), so we have to reverse once here
164  sw->selected_item_list = g_list_reverse(sw->selected_item_list);
165 
166  // Call the callback
167  (cb->cb_multiselect_fn)(sw->selected_item_list, sw->user_data);
168  }
169  else
170  {
171  // No, stick to the single-item callback
172  if (cb->cb_fcn)
173  (cb->cb_fcn)(&(sw->selected_item), sw->user_data);
174  }
175 }
176 
177 
178 static void
179 gnc_search_dialog_result_clicked (GtkButton *button, GNCSearchWindow *sw)
180 {
182 
183  cb = g_object_get_data (G_OBJECT (button), "data");
184  gnc_search_callback_button_execute (cb, sw);
185 }
186 
187 
188 static void
189 gnc_search_dialog_select_buttons_enable (GNCSearchWindow *sw, gint selected)
190 {
191  gint i;
192  gboolean enable, read_only;
193  GList *blist;
194 
195  read_only = qof_book_is_readonly (gnc_get_current_book ());
196 
197  for (blist = sw->button_list; blist; blist = blist->next)
198  {
199  GNCSearchCallbackButton *button_spec = g_object_get_data (G_OBJECT(blist->data) , "data");
200 
201  if(selected == 0)
202  {
203  gtk_widget_set_sensitive (GTK_WIDGET(blist->data), FALSE);
204  continue;
205  }
206 
207  if(read_only == TRUE)
208  {
209  if((selected > 1) && (!(button_spec->cb_multiselect_fn == NULL)) && (button_spec->sensitive_if_readonly == TRUE))
210  enable = TRUE;
211  else
212  enable = FALSE;
213 
214  if((selected == 1) && (button_spec->sensitive_if_readonly == TRUE))
215  enable = TRUE;
216  }
217  else
218  {
219  if((selected > 1) && (!(button_spec->cb_multiselect_fn == NULL)))
220  enable = TRUE;
221  else
222  enable = FALSE;
223 
224  if(selected == 1)
225  enable = TRUE;
226  }
227  gtk_widget_set_sensitive (GTK_WIDGET(blist->data), enable);
228  }
229 }
230 
231 
232 static void
233 gnc_search_dialog_select_cb (GtkButton *button, GNCSearchWindow *sw)
234 {
235  g_return_if_fail (sw->selected_cb);
236 
237  if (sw->selected_item == NULL && sw->allow_clear == FALSE)
238  {
239  char *msg = _("You must select an item from the list");
240  gnc_error_dialog (sw->dialog, "%s", msg);
241  return;
242  }
243 
244  (sw->selected_cb)(sw->selected_item, sw->select_arg);
245  gnc_search_dialog_destroy (sw);
246 }
247 
248 
249 static void
250 gnc_search_dialog_select_row_cb (GNCQueryView *qview,
251  gpointer item,
252  gpointer user_data)
253 {
254  GNCSearchWindow *sw = user_data;
255  gint number_of_rows;
256 
257  sw->selected_item_list = NULL;
258  sw->selected_item = NULL;
259 
260  number_of_rows = GPOINTER_TO_INT(item);
261 
262  gnc_search_dialog_select_buttons_enable(sw, number_of_rows);
263 
264  if(number_of_rows == 1)
265  {
266  sw->selected_item = qview->selected_entry;
267  sw->selected_item_list = qview->selected_entry_list;
268  }
269  else
270  sw->selected_item_list = qview->selected_entry_list;
271 }
272 
273 
274 static void
275 gnc_search_dialog_double_click_cb (GNCQueryView *qview,
276  gpointer item,
277  gpointer user_data)
278 {
279  GNCSearchWindow *sw = user_data;
280 
281  sw->selected_item = item;
282  if (sw->selected_cb)
283  /* Select the item */
284  gnc_search_dialog_select_cb (NULL, sw);
285  else if (sw->buttons)
286  /* Call the first button (usually view/edit) */
287  gnc_search_callback_button_execute (sw->buttons, sw);
288 
289  /* If we get here, then nothing to do for a double-click */
290 }
291 
292 
293 static void
294 gnc_search_dialog_init_result_view (GNCSearchWindow *sw)
295 {
296  GtkTreeSelection *selection;
297 
298  sw->result_view = gnc_query_view_new(sw->display_list, sw->q);
299 
300  // We want the multi-selection mode of the tree view.
301  selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(sw->result_view));
302  gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
303 
304  /* Set the sort order of the tree view */
305  gnc_query_sort_order(GNC_QUERY_VIEW(sw->result_view), 1, GTK_SORT_ASCENDING);
306 
307  /* Setup the list callbacks */
308  g_signal_connect (GNC_QUERY_VIEW(sw->result_view), "row_selected",
309  G_CALLBACK (gnc_search_dialog_select_row_cb), sw);
310 
311  g_signal_connect (GNC_QUERY_VIEW(sw->result_view), "double_click_entry",
312  G_CALLBACK(gnc_search_dialog_double_click_cb), sw);
313 }
314 
315 
316 static void
317 gnc_search_dialog_display_results (GNCSearchWindow *sw)
318 {
319  gdouble max_count;
320 
321  /* Check if this is the first time this is called for this window.
322  * If so, then build the results sub-window, the scrolled treeview,
323  * and the active buttons.
324  */
325  if (sw->result_view == NULL)
326  {
327  GtkWidget *scroller, *frame, *button_box, *button;
328 
329  /* Create the view */
330  gnc_search_dialog_init_result_view (sw);
331 
332  frame = gtk_frame_new(NULL);
333 
334  /* Create the scroller and add the view to the scroller */
335  scroller = gtk_scrolled_window_new (NULL, NULL);
336  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller),
337  GTK_POLICY_AUTOMATIC,
338  GTK_POLICY_AUTOMATIC);
339  gtk_widget_set_size_request(GTK_WIDGET(scroller), 300, 100);
340  gtk_container_add (GTK_CONTAINER (scroller), sw->result_view);
341  gtk_container_add(GTK_CONTAINER(frame), scroller);
342 
343  /* Create the button_box */
344  button_box = gtk_vbox_new (FALSE, 3);
345 
346  /* ... and add all the buttons */
347  if (sw->buttons)
348  {
349  int i;
350 
351  button = gtk_button_new_with_label (_("Select"));
352  g_signal_connect (G_OBJECT (button), "clicked",
353  G_CALLBACK (gnc_search_dialog_select_cb), sw);
354  gtk_box_pack_start (GTK_BOX (button_box), button, FALSE, FALSE, 3);
355  sw->select_button = button;
356 
357  for (i = 0; sw->buttons[i].label; i++)
358  {
359  GNCSearchCallbackButton* button_spec = sw->buttons + i;
360  button = gtk_button_new_with_label (_(button_spec->label));
361  g_object_set_data (G_OBJECT (button), "data", button_spec);
362 
363  if (qof_book_is_readonly (gnc_get_current_book ()))
364  gtk_widget_set_sensitive (GTK_WIDGET(button), button_spec->sensitive_if_readonly);
365 
366  /* Save the button pointer */
367  sw->button_list = g_list_append(sw->button_list, button);
368 
369  g_signal_connect (G_OBJECT (button), "clicked",
370  G_CALLBACK (gnc_search_dialog_result_clicked), sw);
371  gtk_box_pack_start (GTK_BOX (button_box), button, FALSE, FALSE, 3);
372  }
373  }
374 
375  /* Add the scrolled-view and button-box to the results_box */
376  gtk_box_pack_end (GTK_BOX (sw->result_hbox), button_box, FALSE, FALSE, 3);
377  gtk_box_pack_end (GTK_BOX (sw->result_hbox), frame, TRUE, TRUE, 3);
378 
379  /* And show the results */
380  gtk_widget_show_all (sw->result_hbox);
381 
382  /* But may be hide the select button */
383  if (!sw->selected_cb)
384  gtk_widget_hide (sw->select_button);
385  }
386  else
387  /* Update the query in the view */
388  gnc_query_view_reset_query (GNC_QUERY_VIEW(sw->result_view), sw->q);
389 
390  /* Deselect all the select buttons and any items */
391  gnc_search_dialog_select_buttons_enable (sw, 0);
392  gnc_query_view_unselect_all (GNC_QUERY_VIEW(sw->result_view));
393 
394  /* set 'new search' if fewer than max_count items is returned. */
395  max_count = gnc_prefs_get_float(GNC_PREFS_GROUP_SEARCH_GENERAL, GNC_PREF_NEW_SEARCH_LIMIT);
396  if (gnc_query_view_get_num_entries(GNC_QUERY_VIEW(sw->result_view)) < max_count)
397  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (sw->new_rb), TRUE);
398 }
399 
400 
401 static void
402 match_combo_changed (GtkComboBoxText *combo_box, GNCSearchWindow *sw)
403 {
404  sw->grouping = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
405 }
406 
407 
408 static void
409 search_type_cb (GtkToggleButton *button, GNCSearchWindow *sw)
410 {
411  GSList * buttongroup = gtk_radio_button_get_group (GTK_RADIO_BUTTON(button));
412 
413  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
414  {
415  sw->search_type =
416  g_slist_length (buttongroup) - g_slist_index (buttongroup, button) - 1;
417  }
418 }
419 
420 
421 static void
422 search_active_only_cb (GtkToggleButton *button, GNCSearchWindow *sw)
423 {
424 
425  gnc_prefs_set_bool(sw->prefs_group, GNC_PREF_ACTIVE_ONLY,
426  gtk_toggle_button_get_active (button));
427 }
428 
429 
430 static void
431 search_update_query (GNCSearchWindow *sw)
432 {
433  static GSList *active_params = NULL;
434  QofQuery *q, *q2, *new_q;
435  GList *node;
436  QofQueryOp op;
437  QofQueryPredData* pdata;
438 
439  if (sw->grouping == GNC_SEARCH_MATCH_ANY)
440  op = QOF_QUERY_OR;
441  else
442  op = QOF_QUERY_AND;
443 
444  if (active_params == NULL)
445  active_params = g_slist_prepend (NULL, QOF_PARAM_ACTIVE);
446 
447  /* Make sure we supply a book! */
448  if (sw->start_q == NULL)
449  {
450  sw->start_q = qof_query_create_for (sw->search_for);
451  qof_query_set_book (sw->start_q, gnc_get_current_book ());
452  }
453  else
454  {
455  /* We've got a query -- purge it of any "active" parameters */
456  qof_query_purge_terms (sw->start_q, active_params);
457  }
458 
459  /* Now create a new query to work from */
460  q = qof_query_create_for (sw->search_for);
461 
462  /* Walk the list of criteria */
463  for (node = sw->crit_list; node; node = node->next)
464  {
465  struct _crit_data *data = node->data;
466 
467  pdata = gnc_search_core_type_get_predicate (data->element);
468  if (pdata)
469  qof_query_add_term (q, gnc_search_param_get_param_path (data->param),
470  pdata, op);
471  }
472 
473  /* Now combine this query with the existing query, depending on
474  * what we want to do... We can assume that cases 1, 2, and 3
475  * already have sw->q being valid!
476  */
477 
478  switch (sw->search_type)
479  {
480  case 0: /* New */
481  new_q = qof_query_merge (sw->start_q, q, QOF_QUERY_AND);
482  qof_query_destroy (q);
483  break;
484  case 1: /* Refine */
485  new_q = qof_query_merge (sw->q, q, QOF_QUERY_AND);
486  qof_query_destroy (q);
487  break;
488  case 2: /* Add */
489  new_q = qof_query_merge (sw->q, q, QOF_QUERY_OR);
490  qof_query_destroy (q);
491  break;
492  case 3: /* Delete */
493  q2 = qof_query_invert (q);
494  new_q = qof_query_merge (sw->q, q2, QOF_QUERY_AND);
495  qof_query_destroy (q2);
496  qof_query_destroy (q);
497  break;
498  default:
499  g_warning ("bad search type: %d", sw->search_type);
500  new_q = q;
501  break;
502  }
503 
504  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (sw->active_only_check)))
505  {
506  qof_query_add_boolean_match (new_q, active_params, TRUE, QOF_QUERY_AND);
507  active_params = NULL;
508  }
509 
510  /* Destroy the old query */
511  if (sw->q)
512  qof_query_destroy (sw->q);
513 
514  /* And save the new one */
515  sw->q = new_q;
516 }
517 
518 
519 static void
520 gnc_search_dialog_show_close_cancel (GNCSearchWindow *sw)
521 {
522  if (sw->selected_cb)
523  {
524  gtk_widget_show (sw->cancel_button);
525  gtk_widget_hide (sw->close_button);
526  }
527  else
528  {
529  gtk_widget_hide (sw->cancel_button);
530  gtk_widget_show (sw->close_button);
531  }
532 }
533 
534 
535 static void
536 gnc_search_dialog_reset_widgets (GNCSearchWindow *sw)
537 {
538  gboolean sens = (sw->q != NULL);
539 
540  gtk_widget_set_sensitive(GTK_WIDGET(sw->narrow_rb), sens);
541  gtk_widget_set_sensitive(GTK_WIDGET(sw->add_rb), sens);
542  gtk_widget_set_sensitive(GTK_WIDGET(sw->del_rb), sens);
543 
544  if (sw->q)
545  {
546  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (sw->new_rb), FALSE);
547  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON (sw->narrow_rb), TRUE);
548  }
549 
550  if (sw->crit_list)
551  {
552  gtk_widget_set_sensitive(sw->grouping_combo, TRUE);
553  gtk_widget_hide(sw->match_all_label);
554  }
555  else
556  {
557  gtk_widget_set_sensitive(sw->grouping_combo, FALSE);
558  gtk_widget_show(sw->match_all_label);
559  }
560 }
561 
562 
563 static gboolean
564 gnc_search_dialog_crit_ok (GNCSearchWindow *sw)
565 {
566  struct _crit_data *data;
567  GList *l;
568  gboolean ret;
569 
570  if (!sw->crit_list)
571  return TRUE;
572 
573  l = g_list_last (sw->crit_list);
574  data = l->data;
575  ret = gnc_search_core_type_validate (data->element);
576 
577  if (ret)
578  sw->last_param = data->param;
579 
580  return ret;
581 }
582 
583 
584 static void
585 search_find_cb (GtkButton *button, GNCSearchWindow *sw)
586 {
587  if (!gnc_search_dialog_crit_ok (sw))
588  return;
589 
590  search_update_query (sw);
591  search_clear_criteria (sw);
592  gnc_search_dialog_reset_widgets (sw);
593 
594  if (sw->result_cb)
595  (sw->result_cb)(sw->q, sw->user_data, &(sw->selected_item));
596  else
597  gnc_search_dialog_display_results (sw);
598 }
599 
600 
601 static void
602 search_new_item_cb (GtkButton *button, GNCSearchWindow *sw)
603 {
604  gpointer res;
605 
606  g_return_if_fail (sw->new_item_cb);
607 
608  res = (sw->new_item_cb)(sw->user_data);
609 
610  if (res)
611  {
612  const GncGUID *guid = (const GncGUID *) ((sw->get_guid->param_getfcn)(res, sw->get_guid));
613  QofQueryOp op = QOF_QUERY_OR;
614 
615  if (!sw->q)
616  {
617  if (!sw->start_q)
618  {
619  sw->start_q = qof_query_create_for (sw->search_for);
620  qof_query_set_book (sw->start_q, gnc_get_current_book ());
621  }
622  sw->q = qof_query_copy (sw->start_q);
623  op = QOF_QUERY_AND;
624  }
625 
626  qof_query_add_guid_match (sw->q, g_slist_prepend (NULL, QOF_PARAM_GUID),
627  guid, op);
628 
629  /* Watch this entity so we'll refresh once it's actually changed */
630  gnc_gui_component_watch_entity (sw->component_id, guid, QOF_EVENT_MODIFY);
631  }
632 }
633 
634 
635 static void
636 search_cancel_cb (GtkButton *button, GNCSearchWindow *sw)
637 {
638  /* Don't select anything */
639  sw->selected_item = NULL;
640  gnc_search_dialog_destroy (sw);
641 }
642 
643 
644 static void
645 search_help_cb (GtkButton *button, GNCSearchWindow *sw)
646 {
647  gnc_gnome_help (HF_HELP, HL_FIND_TRANSACTIONS);
648 }
649 
650 
651 static void
652 remove_element (GtkWidget *button, GNCSearchWindow *sw)
653 {
654  GtkWidget *element;
655  struct _elem_data *data;
656 
657  if (!sw->crit_list)
658  return;
659 
660  element = g_object_get_data (G_OBJECT (button), "element");
661  data = g_object_get_data (G_OBJECT (element), "data");
662 
663  /* remove the element from the list */
664  sw->crit_list = g_list_remove (sw->crit_list, data);
665 
666  /* and from the display */
667  gtk_container_remove (GTK_CONTAINER (sw->criteria_table), element);
668  gtk_container_remove (GTK_CONTAINER (sw->criteria_table), button);
669 
670  /* disable match-type menu when there is no criterion */
671  if (!sw->crit_list)
672  {
673  gtk_widget_set_sensitive(sw->grouping_combo, FALSE);
674  gtk_widget_show(sw->match_all_label);
675  }
676 }
677 
678 
679 static void
680 attach_element (GtkWidget *element, GNCSearchWindow *sw, int row)
681 {
682  GtkWidget *remove;
683  struct _crit_data *data;
684 
685  data = g_object_get_data (G_OBJECT (element), "data");
686 
687  gtk_table_attach (GTK_TABLE (sw->criteria_table), element, 0, 1, row, row + 1,
688  GTK_EXPAND | GTK_FILL, 0, 0, 0);
689 
690 
691  remove = gtk_button_new_from_stock (GTK_STOCK_REMOVE);
692  g_object_set_data (G_OBJECT (remove), "element", element);
693  g_signal_connect (G_OBJECT (remove), "clicked", G_CALLBACK (remove_element), sw);
694  gtk_table_attach (GTK_TABLE (sw->criteria_table), remove, 1, 2, row, row + 1,
695  0, 0, 0, 0);
696  gtk_widget_show (remove);
697  data->button = remove; /* Save the button for later */
698 }
699 
700 
701 static void
702 combo_box_changed (GtkComboBox *combo_box, struct _crit_data *data)
703 {
704  GNCSearchParam *param;
705  GNCSearchCoreType *newelem;
706  GtkTreeModel *model;
707  GtkTreeIter iter;
708 
709  if (!gtk_combo_box_get_active_iter(combo_box, &iter))
710  return;
711  model = gtk_combo_box_get_model(combo_box);
712  gtk_tree_model_get(model, &iter, SEARCH_COL_POINTER, &param, -1);
713 
714  if (gnc_search_param_type_match (param, data->param))
715  {
716  /* The param type is the same, just save the new param */
717  data->param = param;
718  return;
719  }
720  data->param = param;
721 
722  /* OK, let's do a widget shuffle, throw away the old widget/element,
723  * and create another one here. No need to change the crit_list --
724  * the pointer to data stays the same.
725  */
726  if (data->elemwidget)
727  gtk_container_remove (GTK_CONTAINER (data->container), data->elemwidget);
728  g_object_unref (G_OBJECT (data->element));
729 
730  newelem = gnc_search_core_type_new_type_name
731  (gnc_search_param_get_param_type (param));
732  data->element = newelem;
733  data->elemwidget = gnc_search_core_type_get_widget (newelem);
734  if (data->elemwidget)
735  {
736  gtk_box_pack_start (GTK_BOX (data->container), data->elemwidget,
737  FALSE, FALSE, 0);
738  }
739 
740  /* Make sure it's visible */
741  gtk_widget_show_all (data->container);
742 
743  /* Make sure we widen up if necessary */
744  gtk_widget_queue_resize (GTK_WIDGET (data->dialog));
745 
746  /* And grab focus */
747  gnc_search_core_type_grab_focus (newelem);
748  gnc_search_core_type_editable_enters (newelem);
749 }
750 
751 
752 static void
753 search_clear_criteria (GNCSearchWindow *sw)
754 {
755  GList *node;
756 
757  for (node = sw->crit_list; node; )
758  {
759  GList *tmp = node->next;
760  struct _crit_data *data = node->data;
761  g_object_ref (data->button);
762  remove_element (data->button, sw);
763  node = tmp;
764  }
765 }
766 
767 
768 static GtkWidget *
769 get_comb_box_widget (GNCSearchWindow *sw, struct _crit_data *data)
770 {
771  GtkWidget *combo_box;
772  GtkListStore *store;
773  GtkTreeIter iter;
774  GtkCellRenderer *cell;
775  GList *l;
776  int index = 0, current = 0;
777 
778  store = gtk_list_store_new(NUM_SEARCH_COLS, G_TYPE_STRING, G_TYPE_POINTER);
779  combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
780  g_object_unref(store);
781 
782  cell = gtk_cell_renderer_text_new ();
783  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo_box), cell, TRUE);
784  gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
785  "text", SEARCH_COL_NAME,
786  NULL);
787 
788  for (l = sw->params_list; l; l = l->next)
789  {
790  GNCSearchParam *param = l->data;
791 
792  gtk_list_store_append(store, &iter);
793  gtk_list_store_set(store, &iter,
794  SEARCH_COL_NAME, _(param->title),
795  SEARCH_COL_POINTER, param,
796  -1);
797 
798  if (param == sw->last_param) /* is this the right parameter to start? */
799  current = index;
800 
801  index++;
802  }
803 
804  gtk_combo_box_set_active (GTK_COMBO_BOX(combo_box), current);
805  g_signal_connect (combo_box, "changed", G_CALLBACK (combo_box_changed), data);
806 
807  return combo_box;
808 }
809 
810 static GtkWidget *
811 get_element_widget (GNCSearchWindow *sw, GNCSearchCoreType *element)
812 {
813  GtkWidget *combo_box, *hbox, *p;
814  struct _crit_data *data;
815 
816  data = g_new0 (struct _crit_data, 1);
817  data->element = element;
818  data->dialog = GTK_DIALOG (sw->dialog);
819 
820  hbox = gtk_hbox_new (FALSE, 0);
821  /* only set to automaticaly clean up the memory */
822  g_object_set_data_full (G_OBJECT (hbox), "data", data, g_free);
823 
824  p = gnc_search_core_type_get_widget (element);
825  data->elemwidget = p;
826  data->container = hbox;
827  data->param = sw->last_param;
828 
829  combo_box = get_comb_box_widget (sw, data);
830  gtk_box_pack_start (GTK_BOX (hbox), combo_box, FALSE, FALSE, 0);
831  if (p)
832  gtk_box_pack_start (GTK_BOX (hbox), p, FALSE, FALSE, 0);
833  gtk_widget_show_all (hbox);
834 
835  return hbox;
836 }
837 
838 static void
839 gnc_search_dialog_book_option_changed (gpointer new_val, gpointer user_data)
840 {
841  GList *l;
842  GNCSearchWindow *sw = user_data;
843  gboolean *new_data = (gboolean*)new_val;
844  /* Save current dialog focus */
845  GtkWidget *focused_widget = gtk_window_get_focus(GTK_WINDOW(sw->dialog));
846 
847  g_return_if_fail (sw);
848  if (strcmp (sw->search_for, GNC_ID_SPLIT) != 0)
849  return;
850 
851  /* Adjust labels for future added search criteria */
852  for (l = sw->params_list; l; l = l->next)
853  {
854  GNCSearchParam *param = l->data;
855 
856  if (*new_data)
857  {
858  if (strcmp (param->title, N_("Action")) == 0)
859  gnc_search_param_set_title (param, N_("Number/Action"));
860  if (strcmp (param->title, N_("Number")) == 0)
861  gnc_search_param_set_title (param, N_("Transaction Number"));
862  }
863  else
864  {
865  if (strcmp (param->title, N_("Number/Action")) == 0)
866  gnc_search_param_set_title (param, N_("Action"));
867  if (strcmp (param->title, N_("Transaction Number")) == 0)
868  gnc_search_param_set_title (param, N_("Number"));
869  }
870  }
871  /* Adjust labels for existing search criteria; walk the list of criteria */
872  for (l = sw->crit_list; l; l = l->next)
873  {
874  struct _crit_data *data = l->data;
875  GList *children;
876 
877  /* For each, walk the list of container children to get combo_box */
878  for (children = gtk_container_get_children(GTK_CONTAINER(data->container));
879  children; children = children->next)
880  {
881  GtkWidget *combo_box = children->data;
882 
883  /* Get current active item if combo_box */
884  if (GTK_IS_COMBO_BOX(combo_box))
885  {
886  GtkWidget *new_combo_box;
887  gint index;
888 
889  /* Set index to current active item */
890  index = gtk_combo_box_get_active(GTK_COMBO_BOX(combo_box));
891  /* Create new combo_box to replace existing one */
892  new_combo_box = get_comb_box_widget (sw, data);
893  /* If current combo_box has focus, point to new_combo-box */
894  if (focused_widget == combo_box)
895  focused_widget = new_combo_box;
896  gtk_widget_destroy(combo_box);
897  /* Set new combo_box to current active item */
898  gtk_combo_box_set_active(GTK_COMBO_BOX(new_combo_box), index);
899  gtk_box_pack_start (GTK_BOX (data->container), new_combo_box,
900  FALSE, FALSE, 0);
901  gtk_box_reorder_child(GTK_BOX (data->container), new_combo_box, 0);
902  gtk_widget_show_all (data->container);
903  }
904  }
905  }
906  gtk_widget_grab_focus(focused_widget);
907 }
908 
909 static void
910 gnc_search_dialog_add_criterion (GNCSearchWindow *sw)
911 {
912  GNCSearchCoreType *new_sct;
913 
914  /* First, make sure that the last criterion is ok */
915  if (sw->crit_list)
916  {
917  if (!gnc_search_dialog_crit_ok (sw))
918  return;
919  }
920  else
921  {
922  sw->last_param = sw->params_list->data;
923 
924  /* no match-all situation anymore */
925  gtk_widget_set_sensitive(sw->grouping_combo, TRUE);
926  gtk_widget_hide(sw->match_all_label);
927  }
928  /* create a new criterion element */
929  new_sct = gnc_search_core_type_new_type_name
930  (gnc_search_param_get_param_type (sw->last_param));
931 
932  if (new_sct)
933  {
934  struct _crit_data *data;
935  GtkWidget *w;
936  int rows;
937 
938  w = get_element_widget (sw, new_sct);
939  data = g_object_get_data (G_OBJECT (w), "data");
940  sw->crit_list = g_list_append (sw->crit_list, data);
941 
942  rows = GTK_TABLE (sw->criteria_table)->nrows;
943  gtk_table_resize (GTK_TABLE (sw->criteria_table), rows + 1, 2);
944  attach_element (w, sw, rows);
945 
946  gnc_search_core_type_grab_focus (new_sct);
947  gnc_search_core_type_editable_enters (new_sct);
948  }
949 }
950 
951 
952 static void
953 add_criterion (GtkWidget *button, GNCSearchWindow *sw)
954 {
955  gnc_search_dialog_add_criterion (sw);
956 }
957 
958 
959 static int
960 gnc_search_dialog_close_cb (GtkDialog *dialog, GNCSearchWindow *sw)
961 {
962  g_return_val_if_fail (sw, TRUE);
963 
964  /* Unregister callback on book option changes originally registered
965  * if searching for splits */
966  if (strcmp (sw->search_for, GNC_ID_SPLIT) == 0)
967  gnc_book_option_remove_cb(OPTION_NAME_NUM_FIELD_SOURCE,
968  gnc_search_dialog_book_option_changed, sw);
969 
970  gnc_unregister_gui_component (sw->component_id);
971 
972  /* Clear the crit list */
973  g_list_free (sw->crit_list);
974 
975  /* Clear the button list */
976  g_list_free (sw->button_list);
977 
978  /* Destroy the queries */
979  if (sw->q) qof_query_destroy (sw->q);
980  if (sw->start_q) qof_query_destroy (sw->start_q);
981 
982  /* Destroy the user_data */
983  if (sw->free_cb)
984  (sw->free_cb)(sw->user_data);
985 
986  /* Destroy and exit */
987  g_free (sw);
988  return FALSE;
989 }
990 
991 
992 static void
993 refresh_handler (GHashTable *changes, gpointer data)
994 {
995  GNCSearchWindow * sw = data;
996 
997  g_return_if_fail (sw);
998  /* This assumes that results_cb will refresh itself which is the case with
999  * registers. Also, only refresh if you are already displaying results */
1000  if (!sw->result_cb && (sw->result_view != NULL))
1001  gnc_search_dialog_display_results (sw);
1002 }
1003 
1004 
1005 static void
1006 close_handler (gpointer data)
1007 {
1008  GNCSearchWindow * sw = data;
1009 
1010  g_return_if_fail (sw);
1011  gtk_widget_destroy (sw->dialog);
1012  /* DRH: should sw be freed here? */
1013 }
1014 
1015 
1016 static const gchar *
1017 type_label_to_new_button(const gchar* type_label)
1018 {
1019  if (g_strcmp0(type_label, _("Bill")) == 0)
1020  {
1021  return _("New Bill");
1022  }
1023  else if (g_strcmp0(type_label, _("Customer")) == 0)
1024  {
1025  return _("New Customer");
1026  }
1027  else if (g_strcmp0(type_label, _("Employee")) == 0)
1028  {
1029  return _("New Employee");
1030  }
1031  else if (g_strcmp0(type_label, _("Expense Voucher")) == 0)
1032  {
1033  return _("New Expense Voucher");
1034  }
1035  else if (g_strcmp0(type_label, _("Invoice")) == 0)
1036  {
1037  return _("New Invoice");
1038  }
1039  else if (g_strcmp0(type_label, _("Job")) == 0)
1040  {
1041  return _("New Job");
1042  }
1043  else if (g_strcmp0(type_label, _("Order")) == 0)
1044  {
1045  return _("New Order");
1046  }
1047  else if (g_strcmp0(type_label, _("Transaction")) == 0)
1048  {
1049  return _("New Transaction");
1050  }
1051  else if (g_strcmp0(type_label, _("Split")) == 0)
1052  {
1053  return _("New Split");
1054  }
1055  else if (g_strcmp0(type_label, _("Vendor")) == 0)
1056  {
1057  return _("New Vendor");
1058  }
1059  else
1060  {
1061  PWARN("No translatable new-button label found for search type \"%s\", please add one into dialog-search.c!", type_label);
1062  return Q_("Item represents an unknown object type (in the sense of bill, customer, invoice, transaction, split,...)|New item");
1063  }
1064 }
1065 
1066 
1067 static void
1068 gnc_search_dialog_init_widgets (GNCSearchWindow *sw, const gchar *title)
1069 {
1070  GtkBuilder *builder;
1071  GtkWidget *label, *add, *box;
1072  GtkComboBoxText *combo_box;
1073  GtkWidget *widget;
1074  GtkWidget *new_item_button;
1075  const char *type_label;
1076  gboolean active;
1077 
1078  builder = gtk_builder_new();
1079  gnc_builder_add_from_file (builder, "dialog-search.glade", "Search Dialog");
1080 
1081  /* Grab the dialog, save the dialog info */
1082  sw->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Search Dialog"));
1083  gtk_window_set_title(GTK_WINDOW(sw->dialog), title);
1084  g_object_set_data (G_OBJECT (sw->dialog), "dialog-info", sw);
1085 
1086  /* Grab the result hbox */
1087  sw->result_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "result_hbox"));
1088 
1089  /* Grab the search-table widget */
1090  sw->criteria_table = GTK_WIDGET(gtk_builder_get_object (builder, "criteria_table"));
1091 
1092  /* Set the type label */
1093  label = GTK_WIDGET(gtk_builder_get_object (builder, "type_label"));
1094  if (sw->type_label)
1095  type_label = sw->type_label;
1096  else
1097  type_label = _(qof_object_get_type_label (sw->search_for));
1098  gtk_label_set_text (GTK_LABEL (label), type_label);
1099 
1100  /* Set the 'add criterion' button */
1101  add = gtk_button_new_from_stock (GTK_STOCK_ADD);
1102 
1103  g_signal_connect (G_OBJECT (add), "clicked", G_CALLBACK (add_criterion), sw);
1104  box = GTK_WIDGET(gtk_builder_get_object (builder, "add_button_box"));
1105  gtk_box_pack_start (GTK_BOX (box), add, FALSE, FALSE, 3);
1106  gtk_widget_show (add);
1107 
1108  /* Set the match-type menu */
1109  sw->grouping_combo = gtk_combo_box_text_new();
1110  combo_box = GTK_COMBO_BOX_TEXT(sw->grouping_combo);
1111  gtk_combo_box_text_append_text(combo_box, _("all criteria are met"));
1112  gtk_combo_box_text_append_text(combo_box, _("any criteria are met"));
1113  gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), sw->grouping);
1114  g_signal_connect(combo_box, "changed", G_CALLBACK (match_combo_changed), sw);
1115 
1116  box = GTK_WIDGET(gtk_builder_get_object (builder, "type_menu_box"));
1117  gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET(combo_box), FALSE, FALSE, 3);
1118  gtk_widget_show(GTK_WIDGET(combo_box));
1119 
1120  /* Grab the 'all items match' label */
1121  sw->match_all_label = GTK_WIDGET(gtk_builder_get_object (builder, "match_all_label"));
1122 
1123  /* if there's no original query, make the narrow, add, delete buttons inaccessible */
1124  sw->new_rb = GTK_WIDGET(gtk_builder_get_object (builder, "new_search_radiobutton"));
1125  g_signal_connect (sw->new_rb, "toggled",
1126  G_CALLBACK (search_type_cb), sw);
1127  sw->narrow_rb = GTK_WIDGET(gtk_builder_get_object (builder, "narrow_search_radiobutton"));
1128  g_signal_connect (sw->narrow_rb, "toggled",
1129  G_CALLBACK (search_type_cb), sw);
1130  sw->add_rb = GTK_WIDGET(gtk_builder_get_object (builder, "add_search_radiobutton"));
1131  g_signal_connect (sw->add_rb, "toggled",
1132  G_CALLBACK (search_type_cb), sw);
1133  sw->del_rb = GTK_WIDGET(gtk_builder_get_object (builder, "delete_search_radiobutton"));
1134  g_signal_connect (sw->del_rb, "toggled",
1135  G_CALLBACK (search_type_cb), sw);
1136 
1137  active = gnc_prefs_get_bool(sw->prefs_group, GNC_PREF_ACTIVE_ONLY);
1138  sw->active_only_check = GTK_WIDGET(gtk_builder_get_object (builder, "active_only_check"));
1139  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sw->active_only_check), active);
1140  g_signal_connect (sw->active_only_check, "toggled",
1141  G_CALLBACK (search_active_only_cb), sw);
1142 
1143  /* Figure out if we this object-type has an "active" parameter, and
1144  * if not, then set the active-check button insensitive
1145  */
1146  if (qof_class_get_parameter (sw->search_for, QOF_PARAM_ACTIVE) == NULL)
1147  gtk_widget_set_sensitive (sw->active_only_check, FALSE);
1148 
1149  /* Deal with the find button */
1150  widget = GTK_WIDGET(gtk_builder_get_object (builder, "find_button"));
1151  g_signal_connect (widget, "clicked",
1152  G_CALLBACK (search_find_cb), sw);
1153 
1154  /* Deal with the cancel button */
1155  sw->cancel_button = GTK_WIDGET(gtk_builder_get_object (builder, "cancel_button"));
1156  g_signal_connect (sw->cancel_button, "clicked",
1157  G_CALLBACK (search_cancel_cb), sw);
1158 
1159  /* Deal with the close button */
1160  sw->close_button = GTK_WIDGET(gtk_builder_get_object (builder, "close_button"));
1161  g_signal_connect (sw->close_button, "clicked",
1162  G_CALLBACK (search_cancel_cb), sw);
1163 
1164  /* Deal with the new_item button */
1165  new_item_button = GTK_WIDGET(gtk_builder_get_object (builder, "new_item_button"));
1166  gtk_button_set_label (GTK_BUTTON(new_item_button),
1167  type_label_to_new_button(type_label));
1168  g_signal_connect (new_item_button, "clicked",
1169  G_CALLBACK (search_new_item_cb), sw);
1170 
1171  /* Deal with the help button */
1172  widget = GTK_WIDGET(gtk_builder_get_object (builder, "help_button"));
1173  g_signal_connect (widget, "clicked",
1174  G_CALLBACK (search_help_cb), sw);
1175 
1176  /* add the first criterion */
1177  gnc_search_dialog_add_criterion (sw);
1178 
1179  /* register to update criterion/criteria labels based on book option changes
1180  * if searching for splits */
1181  if (strcmp (sw->search_for, GNC_ID_SPLIT) == 0)
1182  gnc_book_option_register_cb(OPTION_NAME_NUM_FIELD_SOURCE,
1183  gnc_search_dialog_book_option_changed, sw);
1184 
1185  /* Hide the 'new' button if there is no new_item_cb */
1186  if (!sw->new_item_cb)
1187  gtk_widget_hide (new_item_button);
1188 
1189  /* Connect all the signals */
1190  gtk_builder_connect_signals (builder, sw);
1191 
1192  /* Register ourselves */
1193  sw->component_id = gnc_register_gui_component (DIALOG_SEARCH_CM_CLASS,
1194  refresh_handler,
1195  close_handler, sw);
1196  gnc_gui_component_set_session (sw->component_id,
1197  gnc_get_current_session());
1198 
1199  /* And setup the close callback */
1200  g_signal_connect (G_OBJECT (sw->dialog), "destroy",
1201  G_CALLBACK (gnc_search_dialog_close_cb), sw);
1202 
1203  gnc_search_dialog_reset_widgets (sw);
1204  gnc_search_dialog_show_close_cancel (sw);
1205 
1206  g_object_unref(G_OBJECT(builder));
1207 }
1208 
1209 
1210 void
1211 gnc_search_dialog_destroy (GNCSearchWindow *sw)
1212 {
1213  if (!sw) return;
1214  if (sw->prefs_group)
1215  gnc_save_window_size(sw->prefs_group, GTK_WINDOW(sw->dialog));
1216  gnc_close_gui_component (sw->component_id);
1217 }
1218 
1219 
1220 void
1221 gnc_search_dialog_raise (GNCSearchWindow *sw)
1222 {
1223  if (!sw) return;
1224  gtk_window_present (GTK_WINDOW(sw->dialog));
1225 }
1226 
1228 gnc_search_dialog_create (QofIdTypeConst obj_type, const gchar *title,
1229  GList *param_list,
1230  GList *display_list,
1231  QofQuery *start_query, QofQuery *show_start_query,
1232  GNCSearchCallbackButton *callbacks,
1233  GNCSearchResultCB result_callback,
1234  GNCSearchNewItemCB new_item_cb,
1235  gpointer user_data, GNCSearchFree free_cb,
1236  const gchar *prefs_group,
1237  const gchar *type_label)
1238 {
1239  GNCSearchWindow *sw = g_new0 (GNCSearchWindow, 1);
1240 
1241  g_return_val_if_fail (obj_type, NULL);
1242  g_return_val_if_fail (*obj_type != '\0', NULL);
1243  g_return_val_if_fail (param_list, NULL);
1244 
1245  /* Make sure the caller supplies callbacks xor result_callback */
1246  g_return_val_if_fail ((callbacks && !result_callback) ||
1247  (!callbacks && result_callback), NULL);
1248 
1249  if (callbacks)
1250  g_return_val_if_fail (display_list, NULL);
1251 
1252  sw->search_for = obj_type;
1253  sw->params_list = param_list;
1254  sw->display_list = display_list;
1255  sw->buttons = callbacks;
1256  sw->result_cb = result_callback;
1257  sw->new_item_cb = new_item_cb;
1258  sw->user_data = user_data;
1259  sw->free_cb = free_cb;
1260  sw->prefs_group = prefs_group;
1261  sw->type_label = type_label;
1262 
1263  /* Grab the get_guid function */
1264  sw->get_guid = qof_class_get_parameter (sw->search_for, QOF_PARAM_GUID);
1265  if (start_query)
1266  sw->start_q = qof_query_copy (start_query);
1267  sw->q = show_start_query;
1268 
1269  gnc_search_dialog_init_widgets (sw, title);
1270  if (sw->prefs_group)
1271  gnc_restore_window_size(sw->prefs_group, GTK_WINDOW(sw->dialog));
1272  gtk_widget_show(sw->dialog);
1273 
1274  /* Maybe display the original query results? */
1275  if (callbacks && show_start_query)
1276  {
1277  gnc_search_dialog_reset_widgets (sw);
1278  gnc_search_dialog_display_results (sw);
1279  }
1280 
1281  return sw;
1282 }
1283 
1284 
1285 /* Register an on-close signal with the Search Dialog */
1286 guint gnc_search_dialog_connect_on_close (GNCSearchWindow *sw,
1287  GCallback func,
1288  gpointer user_data)
1289 {
1290  g_return_val_if_fail (sw, 0);
1291  g_return_val_if_fail (func, 0);
1292  g_return_val_if_fail (user_data, 0);
1293 
1294  return g_signal_connect (G_OBJECT (sw->dialog), "destroy",
1295  func, user_data);
1296 
1297 }
1298 
1299 
1300 /* Un-register the signal handlers with the Search Dialog */
1301 void gnc_search_dialog_disconnect (GNCSearchWindow *sw, gpointer user_data)
1302 {
1303  g_return_if_fail (sw);
1304  g_return_if_fail (user_data);
1305 
1306  g_signal_handlers_disconnect_matched (sw->dialog, G_SIGNAL_MATCH_DATA,
1307  0, 0, NULL, NULL, user_data);
1308 }
1309 
1310 
1311 /* Clear all callbacks with this Search Window */
1312 void gnc_search_dialog_set_select_cb (GNCSearchWindow *sw,
1313  GNCSearchSelectedCB selected_cb,
1314  gpointer user_data,
1315  gboolean allow_clear)
1316 {
1317  g_return_if_fail (sw);
1318 
1319  sw->selected_cb = selected_cb;
1320  sw->select_arg = user_data;
1321  sw->allow_clear = allow_clear;
1322 
1323  /* Show or hide the select button */
1324  if (sw->select_button)
1325  {
1326  if (selected_cb)
1327  gtk_widget_show (sw->select_button);
1328  else
1329  gtk_widget_hide (sw->select_button);
1330  }
1331 
1332  /* Show the proper close/cancel button */
1333  gnc_search_dialog_show_close_cancel (sw);
1334 }
1335 
1336 
1337 /* TEST CODE BELOW HERE */
1338 
1339 static GList *
1340 get_params_list (QofIdTypeConst type)
1341 {
1342  GList *list = NULL;
1343 
1344  list = gnc_search_param_prepend (list, "Txn: All Accounts",
1346  type, SPLIT_TRANS, TRANS_SPLITLIST,
1347  SPLIT_ACCOUNT_GUID, NULL);
1348  list = gnc_search_param_prepend (list, "Split Account", GNC_ID_ACCOUNT,
1349  type, SPLIT_ACCOUNT, QOF_PARAM_GUID,
1350  NULL);
1351  list = gnc_search_param_prepend (list, "Split->Txn->Void?", NULL, type,
1352  SPLIT_TRANS, TRANS_VOID_STATUS, NULL);
1353  list = gnc_search_param_prepend (list, "Split Int64", NULL, type,
1354  "d-share-int64", NULL);
1355  list = gnc_search_param_prepend (list, "Split Amount (double)", NULL, type,
1356  "d-share-amount", NULL);
1357  list = gnc_search_param_prepend (list, "Split Value (debcred)", NULL, type,
1358  SPLIT_VALUE, NULL);
1359  list = gnc_search_param_prepend (list, "Split Amount (numeric)", NULL, type,
1360  SPLIT_AMOUNT, NULL);
1361  list = gnc_search_param_prepend (list, "Date Reconciled (date)", NULL, type,
1362  SPLIT_DATE_RECONCILED, NULL);
1363  list = gnc_search_param_prepend (list, "Split Memo (string)", NULL, type,
1364  SPLIT_MEMO, NULL);
1365 
1366  return list;
1367 }
1368 
1369 
1370 static GList *
1371 get_display_list (QofIdTypeConst type)
1372 {
1373  GList *list = NULL;
1374 
1375  list = gnc_search_param_prepend (list, "Amount", NULL, type, SPLIT_AMOUNT,
1376  NULL);
1377  list = gnc_search_param_prepend (list, "Memo", NULL, type, SPLIT_MEMO, NULL);
1378  list = gnc_search_param_prepend (list, "Date", NULL, type, SPLIT_TRANS,
1379  TRANS_DATE_POSTED, NULL);
1380 
1381  return list;
1382 }
1383 
1384 
1385 static void
1386 do_nothing (gpointer *a, gpointer b)
1387 {
1388  return;
1389 }
1390 
1391 
1392 void
1393 gnc_search_dialog_test (void)
1394 {
1395  static GList *params = NULL;
1396  static GList *display = NULL;
1397  static GNCSearchCallbackButton buttons[] =
1398  {
1399  /* Don't mark these as translatable since these are only test strings! */
1400  { ("View Split"), do_nothing, NULL, TRUE },
1401  { ("New Split"), do_nothing, NULL, TRUE },
1402  { ("Do Something"), do_nothing, NULL, TRUE },
1403  { ("Do Nothing"), do_nothing, NULL, TRUE },
1404  { ("Who Cares?"), do_nothing, NULL, FALSE },
1405  { NULL }
1406  };
1407 
1408  if (params == NULL)
1409  params = get_params_list (GNC_ID_SPLIT);
1410 
1411  if (display == NULL)
1412  display = get_display_list (GNC_ID_SPLIT);
1413 
1414 /* FIXME: All this does is leak. */
1415  gnc_search_dialog_create (GNC_ID_SPLIT, _("Find Transaction"),
1416  params, display,
1417  NULL, NULL, buttons, NULL, NULL, NULL, NULL,
1418  NULL, NULL);
1419 }
1420 
void qof_query_add_term(QofQuery *query, QofQueryParamList *param_list, QofQueryPredData *pred_data, QofQueryOp op)
const char * qof_object_get_type_label(QofIdTypeConst type_name)
utility functions for the GnuCash UI
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
void qof_query_purge_terms(QofQuery *q, QofQueryParamList *param_list)
const gchar * QofIdTypeConst
Definition: qofid.h:87
QofQuery * qof_query_copy(QofQuery *q)
struct _QofQuery QofQuery
Definition: qofquery.h:90
Definition: guid.h:65
#define PWARN(format, args...)
Definition: qoflog.h:243
const QofParam * qof_class_get_parameter(QofIdTypeConst obj_name, const char *parameter)
void qof_query_destroy(QofQuery *q)
#define ACCOUNT_MATCH_ALL_TYPE
Definition: Account.h:1438
gboolean gnc_prefs_set_bool(const gchar *group, const gchar *pref_name, gboolean value)
Definition: gnc-prefs.c:282
void qof_query_set_book(QofQuery *q, QofBook *book)
#define SPLIT_ACCOUNT_GUID
Definition: Split.h:513
QofQuery * qof_query_merge(QofQuery *q1, QofQuery *q2, QofQueryOp op)
QofQuery * qof_query_invert(QofQuery *q)
void gnc_gnome_help(const char *file_name, const char *anchor)
void qof_query_add_guid_match(QofQuery *q, QofQueryParamList *param_list, const GncGUID *guid, QofQueryOp op)
Generic api to store and retrieve preferences.
QofQueryOp
Definition: qofquery.h:93
gboolean qof_book_is_readonly(const QofBook *book)
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
void qof_query_add_boolean_match(QofQuery *q, QofQueryParamList *param_list, gboolean value, QofQueryOp op)
API for Transactions and Splits (journal entries)
const gchar * QofLogModule
Definition: qofid.h:89
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:227