3
* Copyright (C) 2004 - 2006 Vivien Malerba
5
* This program is free software; you can redistribute it and/or
6
* modify it under the terms of the GNU General Public License as
7
* published by the Free Software Foundation; either version 2 of the
8
* License, or (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21
#include "query-fields-menu.h"
23
#include <glib/gi18n-lib.h>
25
static void query_fields_menu_class_init (QueryFieldsMenuClass * class);
26
static void query_fields_menu_init (QueryFieldsMenu * wid);
27
static void query_fields_menu_dispose (GObject * object);
37
static gint query_fields_menu_signals[LAST_SIGNAL] = { 0, 0 };
39
struct _QueryFieldsMenuPriv
44
GHashTable *hash_items; /* key = Query's GdaQueryTarget value = GtkMenuItem */
45
GHashTable *hash_signals; /* key = GdaEntity, value = signal id for entity_target_changed_cb() */
48
/* get a pointer to the parents to be able to call their destructor */
49
static GObjectClass *parent_class = NULL;
52
query_fields_menu_get_type (void)
54
static GType type = 0;
57
static const GTypeInfo info = {
58
sizeof (QueryFieldsMenuClass),
60
(GBaseFinalizeFunc) NULL,
61
(GClassInitFunc) query_fields_menu_class_init,
64
sizeof (QueryFieldsMenu),
66
(GInstanceInitFunc) query_fields_menu_init
69
type = g_type_register_static (GTK_TYPE_BUTTON, "QueryFieldsMenu", &info, 0);
76
query_fields_menu_class_init (QueryFieldsMenuClass * class)
78
GObjectClass *object_class = G_OBJECT_CLASS (class);
79
parent_class = g_type_class_peek_parent (class);
81
query_fields_menu_signals[FIELD_SELECTED] =
82
g_signal_new ("field_selected",
83
G_TYPE_FROM_CLASS (object_class),
85
G_STRUCT_OFFSET (QueryFieldsMenuClass, field_selected),
87
marshal_VOID__POINTER_POINTER, G_TYPE_NONE,
88
2, G_TYPE_POINTER, G_TYPE_POINTER);
89
query_fields_menu_signals[EXPR_SELECTED] =
90
g_signal_new ("expr_selected",
91
G_TYPE_FROM_CLASS (object_class),
93
G_STRUCT_OFFSET (QueryFieldsMenuClass, expr_selected),
95
marshal_VOID__STRING, G_TYPE_NONE,
97
class->field_selected = NULL;
98
class->expr_selected = NULL;
100
object_class->dispose = query_fields_menu_dispose;
104
query_fields_menu_init (QueryFieldsMenu * wid)
106
wid->priv = g_new0 (QueryFieldsMenuPriv, 1);
107
wid->priv->query = NULL;
108
wid->priv->menu = NULL;
109
wid->priv->hash_items = NULL;
110
wid->priv->hash_signals = NULL;
113
static gint any_event_cb (QueryFieldsMenu *fmenu, GdkEvent *event, gpointer data);
114
static void query_destroyed_cb (GdaQuery *query, QueryFieldsMenu *fmenu);
115
static void query_targets_changed_cb (GdaQuery *query, GdaQueryTarget *target, QueryFieldsMenu *fmenu);
118
* query_fields_menu_new
119
* @query: a #GdaQuery object
121
* Creates a new #QueryFieldsMenu widget.
123
* Returns: the new widget
126
query_fields_menu_new (GdaQuery *query)
129
QueryFieldsMenu *fmenu;
132
g_return_val_if_fail (query && GDA_IS_QUERY (query), NULL);
134
obj = g_object_new (QUERY_FIELDS_MENU_TYPE, NULL);
135
fmenu = QUERY_FIELDS_MENU (obj);
137
wid = gtk_image_new_from_stock (GTK_STOCK_ADD, GTK_ICON_SIZE_BUTTON);
138
gtk_widget_show (wid);
139
gtk_container_add (GTK_CONTAINER (fmenu), wid);
141
fmenu->priv->query = query;
143
gda_object_connect_destroy (fmenu->priv->query,
144
G_CALLBACK (query_destroyed_cb), fmenu);
145
g_signal_connect (G_OBJECT (fmenu->priv->query), "target_added",
146
G_CALLBACK (query_targets_changed_cb), fmenu);
147
g_signal_connect (G_OBJECT (fmenu->priv->query), "target_removed",
148
G_CALLBACK (query_targets_changed_cb), fmenu);
150
query_targets_changed_cb (fmenu->priv->query, NULL, fmenu);
151
g_signal_connect (G_OBJECT (obj), "event",
152
G_CALLBACK (any_event_cb), NULL);
154
return GTK_WIDGET (obj);
158
query_destroyed_cb (GdaQuery *query, QueryFieldsMenu *fmenu)
160
gtk_widget_destroy (GTK_WIDGET (fmenu));
164
hash_foreach_disconnect (GdaEntity *ent, gulong *sigid, gpointer data)
166
g_signal_handler_disconnect (G_OBJECT (ent), *sigid);
170
query_fields_menu_dispose (GObject *object)
172
QueryFieldsMenu *fmenu;
174
g_return_if_fail (object != NULL);
175
g_return_if_fail (IS_QUERY_FIELDS_MENU (object));
176
fmenu = QUERY_FIELDS_MENU (object);
179
/* Weak unref the GdaQuery if necessary */
180
if (fmenu->priv->query) {
181
g_signal_handlers_disconnect_by_func (G_OBJECT (fmenu->priv->query),
182
G_CALLBACK (query_destroyed_cb), fmenu);
183
g_signal_handlers_disconnect_by_func (G_OBJECT (fmenu->priv->query),
184
G_CALLBACK (query_targets_changed_cb), fmenu);
186
if (fmenu->priv->hash_items)
187
g_hash_table_destroy (fmenu->priv->hash_items);
188
if (fmenu->priv->hash_signals) {
189
g_hash_table_foreach (fmenu->priv->hash_signals,
190
(GHFunc) hash_foreach_disconnect, NULL);
191
g_hash_table_destroy (fmenu->priv->hash_signals);
195
/* the private area itself */
196
g_free (fmenu->priv);
200
/* for the parent class */
201
parent_class->dispose (object);
205
* pop up a menu if button pressed
208
any_event_cb (QueryFieldsMenu *fmenu, GdkEvent *event, gpointer data)
210
if (event->type == GDK_BUTTON_PRESS) {
211
GdkEventButton *bevent = (GdkEventButton *) event;
212
gtk_menu_popup (GTK_MENU (fmenu->priv->menu), NULL, NULL, NULL, NULL,
213
bevent->button, bevent->time);
214
/* Tell calling code that we have handled this event; the buck
219
/* Tell calling code that we have not handled this event; pass it on. */
225
static void update_target_mitems (GtkWidget *target_mitem, GdaEntity *ent, QueryFieldsMenu *fmenu);
226
static void entity_target_changed_cb (GdaEntity *ent, GtkWidget *target_mitem);
228
static void menu_item_mgfield_activate_cb (GtkMenuItem *mitem, QueryFieldsMenu *fmenu);
229
static void menu_item_allfields_activate_cb (GtkMenuItem *mitem, QueryFieldsMenu *fmenu);
230
static void menu_item_expr_activate_cb (GtkMenuItem *mitem, QueryFieldsMenu *fmenu);
233
* Creates or updates the top sub menus for each GdaQueryTarget
236
query_targets_changed_cb (GdaQuery *query, GdaQueryTarget *target, QueryFieldsMenu *fmenu)
238
GtkWidget *target_mitem;
240
GSList *targets, *tlist;
241
GSList *updated_items = NULL;
244
GHashTable *hash, *sigs;
247
/* build hash table and menu if not yet done */
248
if (! fmenu->priv->menu)
249
fmenu->priv->menu = gtk_menu_new ();
250
if (! fmenu->priv->hash_items)
251
fmenu->priv->hash_items = g_hash_table_new (NULL, NULL);
252
if (! fmenu->priv->hash_signals)
253
fmenu->priv->hash_signals = g_hash_table_new_full (NULL, NULL, NULL, g_free);
255
menu = GTK_MENU (fmenu->priv->menu);
256
hash = fmenu->priv->hash_items;
257
sigs = fmenu->priv->hash_signals;
259
/* update the menu structure */
260
targets = gda_query_get_targets (query);
263
GdaQueryTarget *target = GDA_QUERY_TARGET (tlist->data);
264
GdaEntity *ent = gda_query_target_get_represented_entity (GDA_QUERY_TARGET (tlist->data));
266
/* obtain or create target_item and set target_pos for the next created menu item */
267
target_mitem = g_hash_table_lookup (hash, target);
269
gchar *str = gda_query_target_get_complete_name (target);
272
target_mitem = gtk_menu_item_new_with_label (str);
274
gtk_menu_shell_insert (GTK_MENU_SHELL (menu), target_mitem, target_pos++);
275
gtk_widget_show (target_mitem);
277
g_hash_table_insert (hash, target, target_mitem);
279
sigid = g_new (gulong, 1);
280
*sigid = g_signal_connect (G_OBJECT (ent), "changed",
281
G_CALLBACK (entity_target_changed_cb), target_mitem);
282
g_hash_table_insert (sigs, ent, sigid);
284
g_object_set_data (G_OBJECT (target_mitem), "ent", ent);
285
g_object_set_data (G_OBJECT (target_mitem), "target", target);
286
g_object_set_data (G_OBJECT (target_mitem), "fmenu", fmenu);
289
target_pos = g_list_index (GTK_MENU_SHELL (menu)->children, target_mitem) + 1;
290
updated_items = g_slist_prepend (updated_items, target_mitem);
292
/* browse through all the entity's fields */
293
update_target_mitems (target_mitem, ent, fmenu);
295
tlist = g_slist_next (tlist);
297
g_slist_free (targets);
299
/* remove items which need to */
300
mitems = GTK_MENU_SHELL (menu)->children;
302
GSList *to_del = NULL, *list;
305
if (! g_slist_find (updated_items, mitems->data))
306
to_del = g_slist_prepend (to_del, mitems->data);
307
mitems = g_list_next (mitems);
312
GObject *ent = g_object_get_data (G_OBJECT (list->data), "ent");
316
sigid = g_hash_table_lookup (sigs, ent);
318
g_signal_handler_disconnect (ent, *sigid);
319
g_hash_table_remove (sigs, ent);
322
gtk_widget_destroy (GTK_WIDGET (list->data));
323
list = g_slist_next (list);
325
g_slist_free (to_del);
329
g_slist_free (updated_items);
332
/* add a menu item for field creation from a textual expression */
333
target_mitem = gtk_menu_item_new_with_label (_("From expression..."));
334
gtk_menu_shell_append (GTK_MENU_SHELL (menu), target_mitem);
335
gtk_widget_show (target_mitem);
336
g_signal_connect (G_OBJECT (target_mitem), "activate",
337
G_CALLBACK (menu_item_expr_activate_cb), fmenu);
342
* Creates or updates the list of selectable fields in the @target_mitem's contained sub-menu
345
update_target_mitems (GtkWidget *target_mitem, GdaEntity *ent, QueryFieldsMenu *fmenu)
347
GtkWidget *submenu = NULL;
349
GSList *fields, *list;
350
GtkWidget *field_mitem;
351
GdaQueryTarget *target;
353
target = g_object_get_data (G_OBJECT (target_mitem), "target");
355
submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (target_mitem));
357
mitems = GTK_MENU_SHELL (submenu)->children;
361
fields = gda_entity_get_fields (ent);
366
field_mitem = GTK_WIDGET (mitems->data);
367
alabel = gtk_bin_get_child (GTK_BIN (field_mitem));
368
gtk_label_set_text (GTK_LABEL (alabel),
369
gda_object_get_name (GDA_OBJECT (list->data)));
373
submenu = gtk_menu_new ();
374
gtk_menu_item_set_submenu (GTK_MENU_ITEM (target_mitem), submenu);
376
field_mitem = gtk_menu_item_new_with_label (gda_object_get_name
377
(GDA_OBJECT (list->data)));
378
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), field_mitem);
379
gtk_widget_show (field_mitem);
380
g_signal_connect (G_OBJECT (field_mitem), "activate",
381
G_CALLBACK (menu_item_mgfield_activate_cb), fmenu);
384
g_object_set_data (G_OBJECT (field_mitem), "GdaEntityField", list->data);
385
g_object_set_data (G_OBJECT (field_mitem), "target", target);
387
list = g_slist_next (list);
389
mitems = g_list_next (mitems);
391
g_slist_free (fields);
393
/* remove the remaining menu items, if they exist */
395
GList *tmp = g_list_copy (mitems);
398
gtk_widget_destroy (GTK_WIDGET (dlist->data));
399
dlist = g_list_next (dlist);
405
/* add a menu item for "target.*" field creation */
406
field_mitem = gtk_menu_item_new_with_label (_("*"));
407
gtk_menu_shell_append (GTK_MENU_SHELL (submenu), field_mitem);
408
gtk_widget_show (field_mitem);
409
g_signal_connect (G_OBJECT (field_mitem), "activate",
410
G_CALLBACK (menu_item_allfields_activate_cb), fmenu);
411
g_object_set_data (G_OBJECT (field_mitem), "target", target);
416
* Callback when target's represented entity has changed
419
entity_target_changed_cb (GdaEntity *ent, GtkWidget *target_mitem)
421
QueryFieldsMenu *fmenu;
423
fmenu = g_object_get_data (G_OBJECT (target_mitem), "fmenu");
424
update_target_mitems (target_mitem, ent, fmenu);
428
menu_item_mgfield_activate_cb (GtkMenuItem *mitem, QueryFieldsMenu *fmenu)
430
GdaEntityField *field;
431
GdaQueryField *newfield;
432
GdaQueryTarget *target;
434
field = g_object_get_data (G_OBJECT (mitem), "GdaEntityField");
435
g_assert (field && GDA_IS_ENTITY_FIELD (field));
436
target = g_object_get_data (G_OBJECT (mitem), "target");
437
g_assert (target && GDA_IS_QUERY_TARGET (target));
439
newfield = (GdaQueryField *) g_object_new (GDA_TYPE_QUERY_FIELD_FIELD,
440
"dict", gda_object_get_dict ((GdaObject*) fmenu->priv->query),
441
"query", fmenu->priv->query,
443
"field", field, NULL);
444
gda_entity_add_field (GDA_ENTITY (fmenu->priv->query), GDA_ENTITY_FIELD (newfield));
445
g_object_unref (newfield);
449
menu_item_allfields_activate_cb (GtkMenuItem *mitem, QueryFieldsMenu *fmenu)
451
GdaQueryField *newfield;
452
GdaQueryTarget *target;
454
target = g_object_get_data (G_OBJECT (mitem), "target");
455
g_assert (target && GDA_IS_QUERY_TARGET (target));
457
newfield = (GdaQueryField *) g_object_new (GDA_TYPE_QUERY_FIELD_ALL,
458
"dict", gda_object_get_dict ((GdaObject*) fmenu->priv->query),
459
"query", fmenu->priv->query,
460
"target", target, NULL);
461
gda_entity_add_field (GDA_ENTITY (fmenu->priv->query), GDA_ENTITY_FIELD (newfield));
462
g_object_unref (newfield);
466
menu_item_expr_activate_cb (GtkMenuItem *mitem, QueryFieldsMenu *fmenu)
469
GtkWidget *label, *hbox, *vbox, *wid;
473
dlg = gtk_dialog_new_with_buttons (_("Add a query field from an expression"),
474
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (fmenu))),
481
vbox = GTK_DIALOG (dlg)->vbox;
483
label = gtk_label_new (NULL);
484
str = g_strdup_printf ("<b>%s</b>\n<small>%s</small>", _("Textual expression:"),
485
_("The following expression will be analysed to create\n"
486
"a new field in the query"));
487
gtk_label_set_markup (GTK_LABEL (label), str);
489
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
490
gtk_widget_show (label);
491
gtk_misc_set_alignment (GTK_MISC (label), 0., -1);
493
hbox = gtk_hbox_new (FALSE, 0); /* HIG */
494
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
495
gtk_widget_show (hbox);
496
label = gtk_label_new (" ");
497
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
498
gtk_widget_show (label);
500
wid = gtk_entry_new ();
501
gtk_box_pack_start (GTK_BOX (hbox), wid, TRUE, TRUE, 0);
502
gtk_widget_show (wid);
505
result = gtk_dialog_run (GTK_DIALOG (dlg));
506
if (result == GTK_RESPONSE_OK) {
507
GError *error = NULL;
508
const gchar *cstr = gtk_entry_get_text (GTK_ENTRY (wid));
510
if (! gda_query_add_field_from_sql (fmenu->priv->query, cstr, &error)) {
515
msg = g_strdup_printf ("<b>%s</b>\n%s '%s':\n\n%s",
516
_("Error parsing/analysing field expression:"),
521
g_error_free (error);
524
msg = g_strdup_printf ("<b>%s</b>\n%s '%s'",
525
_("Error parsing/analysing field expression:"),
529
errdlg = gtk_message_dialog_new_with_markup (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR,
530
GTK_BUTTONS_CLOSE, msg);
532
gtk_dialog_run (GTK_DIALOG (errdlg));
533
gtk_widget_destroy (errdlg);
536
result = GTK_RESPONSE_CANCEL;
539
while (result != GTK_RESPONSE_CANCEL);
541
gtk_widget_destroy (dlg);