GnuCash  5.6-150-g038405b370+
dialog-query-view.c
1 /*
2  * dialog-query-view.c -- a simple dialog to display a query view and
3  * allow users to select items (or close the view)
4  *
5  * Created By: Derek Atkins <derek@ihtfp.com>
6  * Copyright (c) 2003 Derek Atkins <warlord@MIT.EDU>
7  * Copyright (c) 2012 Robert Fewell
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 of
12  * the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, contact:
21  *
22  * Free Software Foundation Voice: +1-617-542-5942
23  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
24  * Boston, MA 02110-1301, USA gnu@gnu.org
25  */
26 
27 #include <config.h>
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 
31 #include "qof.h"
32 
33 #include "dialog-utils.h"
34 #include "gnc-component-manager.h"
35 
36 #include "dialog-query-view.h"
37 #include "gnc-query-view.h"
38 
40 {
41  GtkWidget * dialog;
42  GtkWidget * label;
43  GtkWidget * qview;
44  GtkWidget * button_box;
45  GNCDisplayViewButton * buttons;
46  const gchar * pref_group;
47  gpointer user_data;
48  GList * books;
49  gint component_id;
50 };
51 
52 static void
53 dqv_clear_booklist (DialogQueryView *dqv)
54 {
55  GList *node;
56 
57  g_return_if_fail (dqv);
58 
59  for (node = dqv->books; node; node = node->next)
60  guid_free ((GncGUID*)node->data);
61  g_list_free (dqv->books);
62  dqv->books = NULL;
63 }
64 
65 static void
66 dqv_build_booklist (DialogQueryView *dqv, Query *q)
67 {
68  GList *node;
69 
70  g_return_if_fail (dqv);
71 
72  for (node = qof_query_get_books(q); node; node = node->next)
73  {
74  QofBook *book = node->data;
75  GncGUID *guid = guid_malloc();
76  *guid = *(qof_book_get_guid(book));
77  dqv->books = g_list_prepend(dqv->books, guid);
78  }
79 }
80 
81 static void
82 gnc_dialog_query_run_callback (GNCDisplayViewButton *cb, gpointer item,
83  DialogQueryView *dqv)
84 {
85  if (!cb)
86  return;
87 
88  if (cb->cb_fcn)
89  (cb->cb_fcn)(GTK_WINDOW (dqv->dialog), item, dqv->user_data);
90 }
91 
92 static void
93 gnc_dialog_query_view_button_clicked (GtkButton *button, DialogQueryView *dqv)
94 {
96  gpointer entry;
97 
98  g_return_if_fail (dqv);
99  entry = gnc_query_view_get_selected_entry (GNC_QUERY_VIEW (dqv->qview));
100  if (!entry)
101  return;
102 
103  cb = g_object_get_data (G_OBJECT (button), "data");
104  g_return_if_fail (cb);
105 
106  gnc_dialog_query_run_callback (cb, entry, dqv);
107 }
108 
109 static void
110 gnc_dialog_query_view_double_click_entry (GNCQueryView *qview, gpointer item,
111  gpointer user_data)
112 {
113  DialogQueryView *dqv = user_data;
114 
115  g_return_if_fail (dqv);
116  g_return_if_fail (item);
117 
118  if (!dqv->buttons)
119  return;
120 
121  gnc_dialog_query_run_callback (dqv->buttons, item, dqv);
122 }
123 
124 static void
125 dqv_save_window_size (DialogQueryView *dqv)
126 {
127  g_return_if_fail (dqv);
128 
129  if (dqv->pref_group)
130  gnc_save_window_size (dqv->pref_group, GTK_WINDOW(dqv->dialog));
131 }
132 
133 static int
134 gnc_dialog_query_view_delete_cb (GtkDialog *dialog, GdkEvent *event, DialogQueryView *dqv)
135 {
136  g_return_val_if_fail (dqv, TRUE);
137 
138  dqv_save_window_size (dqv);
139 
140  gnc_unregister_gui_component (dqv->component_id);
141 
142  /* destroy the book list */
143  dqv_clear_booklist (dqv);
144 
145  /* Destroy and exit */
146  gtk_widget_destroy(dqv->dialog);
147  g_free (dqv);
148  return FALSE;
149 }
150 
151 static void
152 close_handler (gpointer data)
153 {
154  DialogQueryView *dqv = data;
155 
156  g_return_if_fail (dqv);
157  gnc_dialog_query_view_delete_cb (GTK_DIALOG(dqv->dialog), NULL, dqv);
158 }
159 
160 static void
161 gnc_dialog_query_view_refresh_handler (GHashTable *changes, gpointer user_data)
162 {
163  DialogQueryView *dqv = (DialogQueryView *)user_data;
164  const EventInfo *info;
165  GList *node;
166 
167  if (changes)
168  {
169  for (node = dqv->books; node; node = node->next)
170  {
171  info = gnc_gui_get_entity_events (changes, (const GncGUID*)(node->data));
172  if (info && (info->event_mask & QOF_EVENT_DESTROY))
173  {
174  gnc_close_gui_component (dqv->component_id);
175  return;
176  }
177  }
178  }
179 }
180 
181 static void
182 gnc_dialog_query_view_close (GtkButton *button, DialogQueryView *dqv)
183 {
184  dqv_save_window_size (dqv);
185 
186  /* Don't select anything */
187  gnc_dialog_query_view_destroy (dqv);
188 }
189 
190 static gboolean
191 dqv_window_key_press_cb (GtkWidget *widget, GdkEventKey *event,
192  gpointer user_data)
193 {
194  DialogQueryView *dqv = user_data;
195 
196  if (event->keyval == GDK_KEY_Escape)
197  dqv_save_window_size (dqv);
198 
199  return FALSE;
200 }
201 
202 /*****************************************************************/
203 /* PUBLIC INTERFACES */
204 
205 DialogQueryView *
206 gnc_dialog_query_view_new (GtkWindow *parent, GList *param_list, Query *q, const gchar *pref_group)
207 {
208  GtkBuilder *builder;
209  DialogQueryView *dqv;
210  GtkWidget *result_hbox, *close, *scrollWin, *frame;
211  GList *node;
212 
213  dqv = g_new0 (DialogQueryView, 1);
214  builder = gtk_builder_new();
215  gnc_builder_add_from_file (builder, "dialog-query-view.glade", "query_view_dialog");
216  dqv->pref_group = pref_group;
217 
218  /* Grab the dialog, save the dialog info */
219  dqv->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "query_view_dialog"));
220  g_object_set_data (G_OBJECT (dqv->dialog), "dialog-info", dqv);
221  gtk_window_set_transient_for(GTK_WINDOW(dqv->dialog), parent);
222 
223  // Set the name for this dialog so it can be easily manipulated with css
224  gtk_widget_set_name (GTK_WIDGET(dqv->dialog), "gnc-id-query-view");
225 
226  /* grab the widgets */
227  dqv->label = GTK_WIDGET(gtk_builder_get_object (builder, "dialog_label"));
228  result_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "result_hbox"));
229  close = GTK_WIDGET(gtk_builder_get_object (builder, "close_button"));
230 
231  /* build the query list */
232  dqv->qview = gnc_query_view_new (param_list, q);
233 
234  frame = gtk_frame_new(NULL);
235 
236  scrollWin = gtk_scrolled_window_new (NULL, NULL);
237  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW (scrollWin),
238  GTK_POLICY_AUTOMATIC,
239  GTK_POLICY_AUTOMATIC);
240  gtk_container_set_border_width(GTK_CONTAINER(scrollWin), 5);
241 
242  gtk_container_add(GTK_CONTAINER(scrollWin), dqv->qview);
243  gtk_container_add(GTK_CONTAINER(frame), scrollWin);
244 
245  gtk_box_pack_start (GTK_BOX (result_hbox), frame, TRUE, TRUE, 3);
246 
247  /* Create the button_box */
248  dqv->button_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
249  gtk_box_set_homogeneous (GTK_BOX (dqv->button_box), FALSE);
250 
251  gtk_box_pack_start (GTK_BOX (result_hbox), dqv->button_box, FALSE, FALSE, 3);
252 
253  /* connect the double-click signal of the qview */
254  g_signal_connect (G_OBJECT (dqv->qview), "double_click_entry",
255  G_CALLBACK(gnc_dialog_query_view_double_click_entry), dqv);
256 
257  /* connect to the close button */
258  g_signal_connect (G_OBJECT (close), "clicked",
259  G_CALLBACK (gnc_dialog_query_view_close), dqv);
260 
261  /* connect to the cleanup */
262  g_signal_connect (G_OBJECT (dqv->dialog), "delete_event",
263  G_CALLBACK (gnc_dialog_query_view_delete_cb), dqv);
264 
265  /* register ourselves */
266  dqv->component_id = gnc_register_gui_component ("GNC Dialog Query View",
267  gnc_dialog_query_view_refresh_handler,
268  close_handler, dqv);
269 
270  /* Build the book list */
271  dqv_build_booklist (dqv, q);
272 
273  /* and register the books */
274  for (node = dqv->books; node; node = node->next)
275  gnc_gui_component_watch_entity (dqv->component_id, (GncGUID*)node->data,
276  QOF_EVENT_DESTROY);
277 
278  g_signal_connect (G_OBJECT (dqv->dialog), "key_press_event",
279  G_CALLBACK (dqv_window_key_press_cb), dqv);
280 
281  if (pref_group)
282  gnc_restore_window_size (pref_group, GTK_WINDOW(dqv->dialog), GTK_WINDOW(parent));
283 
284 
285  g_object_unref(G_OBJECT(builder));
286 
287  return dqv;
288 }
289 
290 void gnc_dialog_query_view_set_title (DialogQueryView *dqv, const char *title)
291 {
292  if (!dqv || !title) return;
293  gtk_window_set_title (GTK_WINDOW (dqv->dialog), title);
294 }
295 
296 void gnc_dialog_query_view_set_label (DialogQueryView *dqv, const char *label)
297 {
298  if (!dqv || !label) return;
299  gtk_label_set_text (GTK_LABEL(dqv->label), label);
300 }
301 
302 void gnc_dialog_query_view_set_buttons (DialogQueryView *dqv,
303  GNCDisplayViewButton *buttons,
304  gpointer user_data)
305 {
306  GtkWidget *button;
307  int i;
308 
309  if (!dqv || !buttons) return;
310  g_return_if_fail (dqv->buttons == NULL);
311 
312  dqv->buttons = buttons;
313  dqv->user_data = user_data;
314 
315  /* build up the buttons */
316  for (i = 0; buttons[i].label; i++)
317  {
318  /* Note: The "label" member of the GNCDisplayListButton still
319  * isn't translated. Hence, we must translate it here. */
320  button = gtk_button_new_with_label (_(buttons[i].label));
321  g_object_set_data (G_OBJECT (button), "data", &(dqv->buttons[i]));
322  g_signal_connect (G_OBJECT (button), "clicked",
323  G_CALLBACK(gnc_dialog_query_view_button_clicked), dqv);
324  gtk_box_pack_start (GTK_BOX (dqv->button_box), button, FALSE, FALSE, 3);
325  }
326 }
327 
328 void gnc_dialog_query_view_set_numerics (DialogQueryView *dqv, gboolean abs,
329  gboolean inv_sort)
330 {
331  if (!dqv) return;
332 
333  gnc_query_view_set_numerics (GNC_QUERY_VIEW(dqv->qview), abs, inv_sort);
334 }
335 
336 void gnc_dialog_query_view_refresh (DialogQueryView *dqv)
337 {
338  if (!dqv) return;
339 
340  gnc_query_view_refresh (GNC_QUERY_VIEW(dqv->qview));
341  gtk_widget_show_all (dqv->dialog);
342 }
343 
344 void gnc_dialog_query_view_destroy (DialogQueryView *dqv)
345 {
346  if (!dqv) return;
347  gnc_close_gui_component (dqv->component_id);
348 }
349 
350 DialogQueryView *
351 gnc_dialog_query_view_create (GtkWindow *parent, GList *param_list, Query *q,
352  const char *title, const char *label,
353  gboolean abs, gboolean inv_sort,
354  gint sort_column, GtkSortType order,
355  gint expand_column,
356  GNCDisplayViewButton *buttons,
357  const gchar *pref_group, gpointer user_data)
358 {
359  DialogQueryView *dqv;
360 
361  if (!param_list || !q)
362  return NULL;
363 
364  dqv = gnc_dialog_query_view_new (parent, param_list, q, pref_group);
365  if (!dqv)
366  return NULL;
367 
368  if (title)
369  gnc_dialog_query_view_set_title (dqv, title);
370 
371  if (label)
372  gnc_dialog_query_view_set_label (dqv, label);
373 
374  gnc_dialog_query_view_set_numerics (dqv, abs, inv_sort);
375 
376  if (buttons)
377  gnc_dialog_query_view_set_buttons (dqv, buttons, user_data);
378 
379  gnc_dialog_query_view_refresh (dqv);
380 
381  /* Set the sort order */
382  gnc_query_sort_order (GNC_QUERY_VIEW (dqv->qview), sort_column, order);
383 
384  /* Set the column that expands, columns start from 0 */
385  gnc_query_set_expand_column (GNC_QUERY_VIEW (dqv->qview), expand_column);
386 
387  /* Unselect all rows */
388  gnc_query_view_unselect_all (GNC_QUERY_VIEW (dqv->qview));
389 
390  return dqv;
391 }
GncGUID * guid_malloc(void)
Allocate memory for a GUID.
Definition: guid.cpp:104
#define qof_book_get_guid(X)
deprecated
Definition: qofbook.h:441
The type used to store guids in C.
Definition: guid.h:75
A Query.
Definition: qofquery.cpp:74
GList * qof_query_get_books(QofQuery *q)
Return the list of books we&#39;re using.
Definition: qofquery.cpp:1341