1 /*
2 * Copyright (C) 2009 - 2012 Vivien Malerba <malerba@gnome-db.org>
3 * Copyright (C) 2010 David King <davidk@openismus.com>
4 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21 #include <glib/gi18n-lib.h>
22 #include <string.h>
23 #include <gtk/gtk.h>
24 #include <libgda/gda-tree.h>
25 #include "query-favorite-selector.h"
26 #include "../mgr-favorites.h"
27 #include <libgda-ui/gdaui-tree-store.h>
28 #include "../dnd.h"
29 #include "../support.h"
30 #include "marshal.h"
31 #include "../gdaui-bar.h"
32 #include <gdk/gdkkeysyms.h>
33 #include <libgda-ui/internal/popup-container.h>
34 #include "query-editor.h"
35
36 struct _QueryFavoriteSelectorPrivate {
37 BrowserConnection *bcnc;
38 GdaTree *tree;
39 GtkWidget *treeview;
40 guint idle_update_favorites;
41
42 GtkWidget *popup_menu;
43 GtkWidget *popup_properties;
44 GtkWidget *properties_name;
45 GtkWidget *properties_action;
46 GtkWidget *properties_text;
47 gint properties_id;
48 gint properties_position;
49 guint prop_save_timeout;
50 };
51
52 static void query_favorite_selector_class_init (QueryFavoriteSelectorClass *klass);
53 static void query_favorite_selector_init (QueryFavoriteSelector *tsel,
54 QueryFavoriteSelectorClass *klass);
55 static void query_favorite_selector_dispose (GObject *object);
56
57 static void favorites_changed_cb (ToolsFavorites *bfav, QueryFavoriteSelector *tsel);
58
59 enum {
60 SELECTION_CHANGED,
61 LAST_SIGNAL
62 };
63
64 static guint query_favorite_selector_signals[LAST_SIGNAL] = { 0 };
65 static GObjectClass *parent_class = NULL;
66
67 /* columns of the resulting GtkTreeModel */
68 enum {
69 COLUMN_POSITION = 0,
70 COLUMN_ICON = 1,
71 COLUMN_CONTENTS = 2,
72 COLUMN_TYPE = 3,
73 COLUMN_ID = 4,
74 COLUMN_NAME = 5,
75 COLUMN_SUMMARY = 6
76 };
77
78
79 /*
80 * QueryFavoriteSelector class implementation
81 */
82
83 static void
query_favorite_selector_class_init(QueryFavoriteSelectorClass * klass)84 query_favorite_selector_class_init (QueryFavoriteSelectorClass *klass)
85 {
86 GObjectClass *object_class = G_OBJECT_CLASS (klass);
87
88 parent_class = g_type_class_peek_parent (klass);
89
90 /* signals */
91 query_favorite_selector_signals [SELECTION_CHANGED] =
92 g_signal_new ("selection-changed",
93 G_TYPE_FROM_CLASS (object_class),
94 G_SIGNAL_RUN_FIRST,
95 G_STRUCT_OFFSET (QueryFavoriteSelectorClass, selection_changed),
96 NULL, NULL,
97 _qe_marshal_VOID__INT_ENUM_STRING, G_TYPE_NONE,
98 3, G_TYPE_INT, G_TYPE_UINT, G_TYPE_STRING);
99 klass->selection_changed = NULL;
100
101 object_class->dispose = query_favorite_selector_dispose;
102 }
103
104
105 static void
query_favorite_selector_init(QueryFavoriteSelector * tsel,G_GNUC_UNUSED QueryFavoriteSelectorClass * klass)106 query_favorite_selector_init (QueryFavoriteSelector *tsel, G_GNUC_UNUSED QueryFavoriteSelectorClass *klass)
107 {
108 tsel->priv = g_new0 (QueryFavoriteSelectorPrivate, 1);
109 tsel->priv->idle_update_favorites = 0;
110 tsel->priv->prop_save_timeout = 0;
111
112 gtk_orientable_set_orientation (GTK_ORIENTABLE (tsel), GTK_ORIENTATION_VERTICAL);
113 }
114
115 static void
query_favorite_selector_dispose(GObject * object)116 query_favorite_selector_dispose (GObject *object)
117 {
118 QueryFavoriteSelector *tsel = (QueryFavoriteSelector *) object;
119
120 /* free memory */
121 if (tsel->priv) {
122 if (tsel->priv->idle_update_favorites != 0)
123 g_source_remove (tsel->priv->idle_update_favorites);
124 if (tsel->priv->tree)
125 g_object_unref (tsel->priv->tree);
126
127 if (tsel->priv->bcnc) {
128 g_signal_handlers_disconnect_by_func (browser_connection_get_favorites (tsel->priv->bcnc),
129 G_CALLBACK (favorites_changed_cb), tsel);
130 g_object_unref (tsel->priv->bcnc);
131 }
132
133 if (tsel->priv->popup_properties)
134 gtk_widget_destroy (tsel->priv->popup_properties);
135 if (tsel->priv->popup_menu)
136 gtk_widget_destroy (tsel->priv->popup_menu);
137 if (tsel->priv->prop_save_timeout)
138 g_source_remove (tsel->priv->prop_save_timeout);
139
140 g_free (tsel->priv);
141 tsel->priv = NULL;
142 }
143
144 parent_class->dispose (object);
145 }
146
147 GType
query_favorite_selector_get_type(void)148 query_favorite_selector_get_type (void)
149 {
150 static GType type = 0;
151
152 if (G_UNLIKELY (type == 0)) {
153 static const GTypeInfo info = {
154 sizeof (QueryFavoriteSelectorClass),
155 (GBaseInitFunc) NULL,
156 (GBaseFinalizeFunc) NULL,
157 (GClassInitFunc) query_favorite_selector_class_init,
158 NULL,
159 NULL,
160 sizeof (QueryFavoriteSelector),
161 0,
162 (GInstanceInitFunc) query_favorite_selector_init,
163 0
164 };
165 type = g_type_register_static (GTK_TYPE_BOX, "QueryFavoriteSelector",
166 &info, 0);
167 }
168 return type;
169 }
170
171 static void
favorite_delete_selected(QueryFavoriteSelector * tsel)172 favorite_delete_selected (QueryFavoriteSelector *tsel)
173 {
174 GtkTreeModel *model;
175 GtkTreeSelection *select;
176 GtkTreeIter iter;
177
178 select = gtk_tree_view_get_selection (GTK_TREE_VIEW (tsel->priv->treeview));
179 if (gtk_tree_selection_get_selected (select, &model, &iter)) {
180 ToolsFavorites *bfav;
181 ToolsFavoritesAttributes fav;
182 GError *lerror = NULL;
183
184 memset (&fav, 0, sizeof (ToolsFavoritesAttributes));
185 gtk_tree_model_get (model, &iter,
186 COLUMN_ID, &(fav.id), -1);
187 bfav = browser_connection_get_favorites (tsel->priv->bcnc);
188 if (!gda_tools_favorites_delete (bfav, 0, &fav, NULL)) {
189 browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*)tsel),
190 _("Could not remove favorite: %s"),
191 lerror && lerror->message ? lerror->message : _("No detail"));
192 if (lerror)
193 g_error_free (lerror);
194 }
195 else {
196 /* remove any associated action */
197 gint id;
198 gchar *tmp;
199 tmp = g_strdup_printf ("QUERY%d", fav.id);
200 id = gda_tools_favorites_find (bfav, 0, tmp, &fav, NULL);
201 if (id >= 0) {
202 gda_tools_favorites_delete (bfav, 0, &fav, NULL);
203 /*g_print ("ACTION_DELETED %d: %s\n", fav.id, tmp);*/
204 }
205 g_free (tmp);
206 }
207 }
208 }
209
210 static gboolean
key_press_event_cb(G_GNUC_UNUSED GtkTreeView * treeview,GdkEventKey * event,QueryFavoriteSelector * tsel)211 key_press_event_cb (G_GNUC_UNUSED GtkTreeView *treeview, GdkEventKey *event,
212 QueryFavoriteSelector *tsel)
213 {
214 if (event->keyval == GDK_KEY_Delete) {
215 favorite_delete_selected (tsel);
216 return TRUE;
217 }
218 return FALSE; /* not handled */
219 }
220
221
222 static void
selection_changed_cb(GtkTreeView * treeview,G_GNUC_UNUSED GtkTreePath * path,G_GNUC_UNUSED GtkTreeViewColumn * column,QueryFavoriteSelector * tsel)223 selection_changed_cb (GtkTreeView *treeview, G_GNUC_UNUSED GtkTreePath *path,
224 G_GNUC_UNUSED GtkTreeViewColumn *column, QueryFavoriteSelector *tsel)
225 {
226 GtkTreeModel *model;
227 GtkTreeSelection *select;
228 GtkTreeIter iter;
229
230 select = gtk_tree_view_get_selection (treeview);
231 if (gtk_tree_selection_get_selected (select, &model, &iter)) {
232 gchar *str;
233 guint type;
234 gint fav_id;
235 gtk_tree_model_get (model, &iter,
236 COLUMN_ID, &fav_id,
237 COLUMN_TYPE, &type,
238 COLUMN_CONTENTS, &str, -1);
239 g_signal_emit (tsel, query_favorite_selector_signals [SELECTION_CHANGED], 0, fav_id, type, str);
240 g_free (str);
241 }
242 }
243
244 static gboolean
prop_save_timeout(QueryFavoriteSelector * tsel)245 prop_save_timeout (QueryFavoriteSelector *tsel)
246 {
247 ToolsFavorites *bfav;
248 ToolsFavoritesAttributes fav;
249 GError *error = NULL;
250 gboolean allok, actiondel = TRUE;
251
252 bfav = browser_connection_get_favorites (tsel->priv->bcnc);
253
254 memset (&fav, 0, sizeof (ToolsFavoritesAttributes));
255 fav.id = tsel->priv->properties_id;
256 fav.type = GDA_TOOLS_FAVORITES_QUERIES;
257 fav.name = (gchar*) gtk_entry_get_text (GTK_ENTRY (tsel->priv->properties_name));
258 fav.descr = NULL;
259 fav.contents = query_editor_get_all_text (QUERY_EDITOR (tsel->priv->properties_text));
260
261 allok = gda_tools_favorites_add (bfav, 0, &fav, ORDER_KEY_QUERIES,
262 tsel->priv->properties_position, &error);
263 if (! allok) {
264 browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) tsel),
265 _("Could not add favorite: %s"),
266 error && error->message ? error->message : _("No detail"));
267 if (error)
268 g_error_free (error);
269 }
270 g_free (fav.contents);
271
272 if (allok && (fav.id >= 0)) {
273 gboolean is_action;
274 gint qid = fav.id;
275 is_action = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tsel->priv->properties_action));
276 if (is_action) {
277 fav.id = -1;
278 fav.type = GDA_TOOLS_FAVORITES_ACTIONS;
279 fav.name = (gchar*) gtk_entry_get_text (GTK_ENTRY (tsel->priv->properties_name));
280 fav.descr = NULL;
281 fav.contents = g_strdup_printf ("QUERY%d", qid);
282 allok = gda_tools_favorites_add (bfav, 0, &fav, -1,
283 tsel->priv->properties_position, &error);
284 if (! allok) {
285 browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) tsel),
286 _("Could not add action: %s"),
287 error && error->message ? error->message : _("No detail"));
288 if (error)
289 g_error_free (error);
290 }
291 else
292 actiondel = FALSE;
293 /*g_print ("ACTION_ADDED %d: %s\n", fav.id, fav.contents);*/
294 g_free (fav.contents);
295 }
296 }
297
298 if (actiondel && (tsel->priv->properties_id >= 0)) {
299 /* remove action */
300 gint id;
301 gchar *tmp;
302 tmp = g_strdup_printf ("QUERY%d", tsel->priv->properties_id);
303 id = gda_tools_favorites_find (bfav, 0, tmp, &fav, NULL);
304 if (id >= 0) {
305 gda_tools_favorites_delete (bfav, 0, &fav, NULL);
306 /*g_print ("ACTION_DELETED %d: %s\n", fav.id, tmp);*/
307 }
308 g_free (tmp);
309 }
310
311 tsel->priv->prop_save_timeout = 0;
312 return FALSE; /* remove timeout */
313 }
314
315 static void
property_changed_cb(G_GNUC_UNUSED GtkWidget * multiple,QueryFavoriteSelector * tsel)316 property_changed_cb (G_GNUC_UNUSED GtkWidget *multiple, QueryFavoriteSelector *tsel)
317 {
318 if (tsel->priv->prop_save_timeout)
319 g_source_remove (tsel->priv->prop_save_timeout);
320 tsel->priv->prop_save_timeout = g_timeout_add (100, (GSourceFunc) prop_save_timeout, tsel);
321 }
322
323 static void
properties_activated_cb(GtkMenuItem * mitem,QueryFavoriteSelector * tsel)324 properties_activated_cb (GtkMenuItem *mitem, QueryFavoriteSelector *tsel)
325 {
326 if (! tsel->priv->popup_properties) {
327 GtkWidget *pcont, *vbox, *hbox, *label, *entry, *text, *grid;
328 gchar *str;
329 gfloat align;
330
331 pcont = popup_container_new (GTK_WIDGET (mitem));
332 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
333 gtk_container_add (GTK_CONTAINER (pcont), vbox);
334
335 label = gtk_label_new ("");
336 str = g_strdup_printf ("<b>%s:</b>", _("Favorite's properties"));
337 gtk_label_set_markup (GTK_LABEL (label), str);
338 g_free (str);
339 gtk_misc_get_alignment (GTK_MISC (label), NULL, &align);
340 gtk_misc_set_alignment (GTK_MISC (label), 0., align);
341 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
342
343 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); /* HIG */
344 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 5);
345 label = gtk_label_new (" ");
346 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
347
348 grid = gtk_grid_new ();
349 gtk_box_pack_start (GTK_BOX (hbox), grid, TRUE, TRUE, 0);
350
351 label = gtk_label_new ("");
352 str = g_strdup_printf ("<b>%s:</b>", _("Name"));
353 gtk_label_set_markup (GTK_LABEL (label), str);
354 g_free (str);
355 gtk_misc_get_alignment (GTK_MISC (label), NULL, &align);
356 gtk_misc_set_alignment (GTK_MISC (label), 0., align);
357 gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
358
359 label = gtk_label_new ("");
360 str = g_strdup_printf ("<b>%s:</b>", _("SQL Code"));
361 gtk_label_set_markup (GTK_LABEL (label), str);
362 g_free (str);
363 gtk_misc_set_alignment (GTK_MISC (label), 0., 0.);
364 gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
365
366 label = gtk_label_new ("");
367 str = g_strdup_printf ("<b>%s:</b>", _("Is action"));
368 gtk_label_set_markup (GTK_LABEL (label), str);
369 g_free (str);
370 gtk_widget_set_tooltip_text (label, _("Check this option to make this favorite an action\n"
371 "which can be proposed for execution from grids\n"
372 "containing data. The parameters required to execute\n"
373 "the query will be defined from the row selected in the grid"));
374 gtk_misc_get_alignment (GTK_MISC (label), NULL, &align);
375 gtk_misc_set_alignment (GTK_MISC (label), 0., align);
376 gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
377
378 entry = gtk_entry_new ();
379 gtk_grid_attach (GTK_GRID (grid), entry, 1, 0, 1, 1);
380 tsel->priv->properties_name = entry;
381 g_signal_connect (entry, "changed",
382 G_CALLBACK (property_changed_cb), tsel);
383
384 text = query_editor_new ();
385 query_editor_show_tooltip (QUERY_EDITOR (text), FALSE);
386 gtk_widget_set_size_request (GTK_WIDGET (text), 400, 300);
387 gtk_grid_attach (GTK_GRID (grid), text, 1, 1, 1, 1);
388 tsel->priv->properties_text = text;
389 g_signal_connect (text, "changed",
390 G_CALLBACK (property_changed_cb), tsel);
391
392 entry = gtk_check_button_new ();
393 gtk_grid_attach (GTK_GRID (grid), entry, 1, 2, 1, 1);
394 tsel->priv->properties_action = entry;
395 g_signal_connect (entry, "toggled",
396 G_CALLBACK (property_changed_cb), tsel);
397
398 tsel->priv->popup_properties = pcont;
399 gtk_widget_show_all (vbox);
400 }
401
402 /* adjust contents */
403 GtkTreeSelection *selection;
404 GtkTreeModel *model;
405 GtkTreeIter iter;
406 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tsel->priv->treeview));
407 if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
408 gchar *name, *contents;
409
410 gtk_tree_model_get (model, &iter,
411 COLUMN_ID, &(tsel->priv->properties_id),
412 COLUMN_POSITION, &(tsel->priv->properties_position),
413 COLUMN_NAME, &name,
414 COLUMN_CONTENTS, &contents, -1);
415
416 g_signal_handlers_block_by_func (tsel->priv->properties_name,
417 G_CALLBACK (property_changed_cb), tsel);
418 gtk_entry_set_text (GTK_ENTRY (tsel->priv->properties_name), name);
419 g_signal_handlers_unblock_by_func (tsel->priv->properties_name,
420 G_CALLBACK (property_changed_cb), tsel);
421 g_free (name);
422
423 g_signal_handlers_block_by_func (tsel->priv->properties_text,
424 G_CALLBACK (property_changed_cb), tsel);
425 query_editor_set_text (QUERY_EDITOR (tsel->priv->properties_text), contents);
426 g_signal_handlers_unblock_by_func (tsel->priv->properties_text,
427 G_CALLBACK (property_changed_cb), tsel);
428 g_free (contents);
429
430 /* action, if any */
431 g_signal_handlers_block_by_func (tsel->priv->properties_action,
432 G_CALLBACK (property_changed_cb), tsel);
433 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tsel->priv->properties_action), FALSE);
434 if (tsel->priv->properties_id >= 0) {
435 gint id;
436 gchar *tmp;
437 ToolsFavorites *bfav;
438 ToolsFavoritesAttributes fav;
439 bfav = browser_connection_get_favorites (tsel->priv->bcnc);
440 tmp = g_strdup_printf ("QUERY%d", tsel->priv->properties_id);
441 id = gda_tools_favorites_find (bfav, 0, tmp, &fav, NULL);
442 if (id >= 0) {
443 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (tsel->priv->properties_action),
444 TRUE);
445 /*g_print ("ACTION_USED %d: %s\n", fav.id, tmp);*/
446 }
447 g_free (tmp);
448 }
449 g_signal_handlers_unblock_by_func (tsel->priv->properties_action,
450 G_CALLBACK (property_changed_cb), tsel);
451
452 gtk_widget_show (tsel->priv->popup_properties);
453 }
454 }
455
456 static void
delete_activated_cb(G_GNUC_UNUSED GtkMenuItem * mitem,QueryFavoriteSelector * tsel)457 delete_activated_cb (G_GNUC_UNUSED GtkMenuItem *mitem, QueryFavoriteSelector *tsel)
458 {
459 favorite_delete_selected (tsel);
460 }
461
462 static void
do_popup_menu(G_GNUC_UNUSED GtkWidget * widget,GdkEventButton * event,QueryFavoriteSelector * tsel)463 do_popup_menu (G_GNUC_UNUSED GtkWidget *widget, GdkEventButton *event, QueryFavoriteSelector *tsel)
464 {
465 int button, event_time;
466
467 if (! tsel->priv->popup_menu) {
468 GtkWidget *menu, *mitem;
469
470 menu = gtk_menu_new ();
471 g_signal_connect (menu, "deactivate",
472 G_CALLBACK (gtk_widget_hide), NULL);
473
474 mitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_PROPERTIES, NULL);
475 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
476 gtk_widget_show (mitem);
477 g_signal_connect (mitem, "activate",
478 G_CALLBACK (properties_activated_cb), tsel);
479
480 mitem = gtk_image_menu_item_new_from_stock (GTK_STOCK_DELETE, NULL);
481 gtk_menu_shell_append (GTK_MENU_SHELL (menu), mitem);
482 gtk_widget_show (mitem);
483 g_signal_connect (mitem, "activate",
484 G_CALLBACK (delete_activated_cb), tsel);
485
486 tsel->priv->popup_menu = menu;
487 }
488
489 if (event) {
490 button = event->button;
491 event_time = event->time;
492 }
493 else {
494 button = 0;
495 event_time = gtk_get_current_event_time ();
496 }
497
498 gtk_menu_popup (GTK_MENU (tsel->priv->popup_menu), NULL, NULL, NULL, NULL,
499 button, event_time);
500 }
501
502
503 static gboolean
popup_menu_cb(GtkWidget * widget,QueryFavoriteSelector * tsel)504 popup_menu_cb (GtkWidget *widget, QueryFavoriteSelector *tsel)
505 {
506 do_popup_menu (widget, NULL, tsel);
507 return TRUE;
508 }
509
510 static gboolean
button_press_event_cb(GtkTreeView * treeview,GdkEventButton * event,QueryFavoriteSelector * tsel)511 button_press_event_cb (GtkTreeView *treeview, GdkEventButton *event, QueryFavoriteSelector *tsel)
512 {
513 if (event->button == 3 && event->type == GDK_BUTTON_PRESS) {
514 do_popup_menu ((GtkWidget*) treeview, event, tsel);
515 return TRUE;
516 }
517
518 return FALSE;
519 }
520
521 static void cell_data_func (GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
522 GtkTreeModel *tree_model, GtkTreeIter *iter, gpointer data);
523 static gboolean idle_update_favorites (QueryFavoriteSelector *tsel);
524 static gboolean tree_store_drag_drop_cb (GdauiTreeStore *store, const gchar *path,
525 GtkSelectionData *selection_data, QueryFavoriteSelector *tsel);
526 static gboolean tree_store_drag_can_drag_cb (GdauiTreeStore *store, const gchar *path,
527 QueryFavoriteSelector *tsel);
528 static gboolean tree_store_drag_get_cb (GdauiTreeStore *store, const gchar *path,
529 GtkSelectionData *selection_data, QueryFavoriteSelector *tsel);
530 /**
531 * query_favorite_selector_new
532 *
533 * Returns: a new #GtkWidget
534 */
535 GtkWidget *
query_favorite_selector_new(BrowserConnection * bcnc)536 query_favorite_selector_new (BrowserConnection *bcnc)
537 {
538 QueryFavoriteSelector *tsel;
539 GdaTreeManager *manager;
540
541 g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
542 tsel = QUERY_FAVORITE_SELECTOR (g_object_new (QUERY_FAVORITE_SELECTOR_TYPE, NULL));
543
544 tsel->priv->bcnc = g_object_ref (bcnc);
545 g_signal_connect (browser_connection_get_favorites (tsel->priv->bcnc), "favorites-changed",
546 G_CALLBACK (favorites_changed_cb), tsel);
547
548 /* create tree managers */
549 tsel->priv->tree = gda_tree_new ();
550 manager = mgr_favorites_new (bcnc, GDA_TOOLS_FAVORITES_QUERIES, ORDER_KEY_QUERIES);
551 gda_tree_add_manager (tsel->priv->tree, manager);
552 g_object_unref (manager);
553
554 /* update the tree's contents */
555 if (! gda_tree_update_all (tsel->priv->tree, NULL)) {
556 if (tsel->priv->idle_update_favorites == 0)
557 tsel->priv->idle_update_favorites = g_idle_add ((GSourceFunc) idle_update_favorites, tsel);
558 }
559
560 /* header */
561 GtkWidget *label;
562 gchar *str;
563 str = g_strdup_printf ("<b>%s</b>", _("Favorites"));
564 label = gdaui_bar_new (str);
565 g_free (str);
566 gdaui_bar_set_icon_from_pixbuf (GDAUI_BAR (label), browser_get_pixbuf_icon (BROWSER_ICON_BOOKMARK));
567 gtk_box_pack_start (GTK_BOX (tsel), label, FALSE, FALSE, 0);
568 gtk_widget_show (label);
569
570 /* tree model */
571 GtkTreeModel *model;
572 GtkWidget *treeview;
573 GtkCellRenderer *renderer;
574 GtkTreeViewColumn *column;
575
576 model = gdaui_tree_store_new (tsel->priv->tree, 7,
577 G_TYPE_INT, MGR_FAVORITES_POSITION_ATT_NAME,
578 G_TYPE_OBJECT, "icon",
579 G_TYPE_STRING, MGR_FAVORITES_CONTENTS_ATT_NAME,
580 G_TYPE_UINT, MGR_FAVORITES_TYPE_ATT_NAME,
581 G_TYPE_INT, MGR_FAVORITES_ID_ATT_NAME,
582 G_TYPE_STRING, MGR_FAVORITES_NAME_ATT_NAME,
583 G_TYPE_STRING, "summary");
584 treeview = browser_make_tree_view (model);
585 tsel->priv->treeview = treeview;
586 g_object_unref (model);
587
588 /* icon */
589 column = gtk_tree_view_column_new ();
590
591 renderer = gtk_cell_renderer_pixbuf_new ();
592 gtk_tree_view_column_pack_start (column, renderer, FALSE);
593 gtk_tree_view_column_add_attribute (column, renderer, "pixbuf", COLUMN_ICON);
594 g_object_set ((GObject*) renderer, "yalign", 0., NULL);
595
596 /* text */
597 renderer = gtk_cell_renderer_text_new ();
598 gtk_tree_view_column_pack_start (column, renderer, TRUE);
599 gtk_tree_view_column_set_cell_data_func (column, renderer, (GtkTreeCellDataFunc) cell_data_func,
600 NULL, NULL);
601 gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
602 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
603
604 /* scrolled window packing */
605 GtkWidget *sw;
606 sw = gtk_scrolled_window_new (NULL, NULL);
607 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
608 GTK_SHADOW_ETCHED_IN);
609 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
610 GTK_POLICY_NEVER,
611 GTK_POLICY_AUTOMATIC);
612 gtk_container_add (GTK_CONTAINER (sw), treeview);
613 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
614
615 gtk_box_pack_start (GTK_BOX (tsel), sw, TRUE, TRUE, 0);
616 gtk_widget_show_all (sw);
617 g_signal_connect (G_OBJECT (treeview), "row-activated",
618 G_CALLBACK (selection_changed_cb), tsel);
619 g_signal_connect (G_OBJECT (treeview), "key-press-event",
620 G_CALLBACK (key_press_event_cb), tsel);
621 g_signal_connect (G_OBJECT (treeview), "popup-menu",
622 G_CALLBACK (popup_menu_cb), tsel);
623 g_signal_connect (G_OBJECT (treeview), "button-press-event",
624 G_CALLBACK (button_press_event_cb), tsel);
625
626 /* DnD */
627 gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (treeview), dbo_table, G_N_ELEMENTS (dbo_table),
628 GDK_ACTION_COPY);
629 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (treeview), GDK_BUTTON1_MASK,
630 dbo_table, G_N_ELEMENTS (dbo_table),
631 GDK_ACTION_COPY | GDK_ACTION_MOVE);
632 g_signal_connect (model, "drag-drop",
633 G_CALLBACK (tree_store_drag_drop_cb), tsel);
634 g_signal_connect (model, "drag-can-drag",
635 G_CALLBACK (tree_store_drag_can_drag_cb), tsel);
636 g_signal_connect (model, "drag-get",
637 G_CALLBACK (tree_store_drag_get_cb), tsel);
638
639 return (GtkWidget*) tsel;
640 }
641
642 static void
cell_data_func(G_GNUC_UNUSED GtkTreeViewColumn * tree_column,GtkCellRenderer * cell,GtkTreeModel * tree_model,GtkTreeIter * iter,G_GNUC_UNUSED gpointer data)643 cell_data_func (G_GNUC_UNUSED GtkTreeViewColumn *tree_column, GtkCellRenderer *cell,
644 GtkTreeModel *tree_model, GtkTreeIter *iter, G_GNUC_UNUSED gpointer data)
645 {
646 gchar *name, *summary;
647 gchar *markup, *tmp1, *tmp2;
648
649 gtk_tree_model_get (tree_model, iter,
650 COLUMN_NAME, &name, COLUMN_SUMMARY, &summary, -1);
651 tmp1 = g_markup_printf_escaped ("%s", name);
652 tmp2 = g_markup_printf_escaped ("%s", summary);
653 g_free (name);
654 g_free (summary);
655
656 markup = g_strdup_printf ("%s\n<small>%s</small>", tmp1, tmp2);
657 g_free (tmp1);
658 g_free (tmp2);
659
660 g_object_set ((GObject*) cell, "markup", markup, NULL);
661 g_free (markup);
662 }
663
664
665 static gboolean
idle_update_favorites(QueryFavoriteSelector * tsel)666 idle_update_favorites (QueryFavoriteSelector *tsel)
667 {
668 gboolean done;
669 done = gda_tree_update_all (tsel->priv->tree, NULL);
670 if (done)
671 tsel->priv->idle_update_favorites = 0;
672 else
673 tsel->priv->idle_update_favorites = g_timeout_add_seconds (1, (GSourceFunc) idle_update_favorites,
674 tsel);
675 return FALSE;
676 }
677
678 static gboolean
tree_store_drag_drop_cb(G_GNUC_UNUSED GdauiTreeStore * store,const gchar * path,GtkSelectionData * selection_data,QueryFavoriteSelector * tsel)679 tree_store_drag_drop_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
680 GtkSelectionData *selection_data, QueryFavoriteSelector *tsel)
681 {
682 ToolsFavorites *bfav;
683 ToolsFavoritesAttributes fav;
684 GError *error = NULL;
685 gint pos;
686 gboolean retval = TRUE;
687 gint id;
688 bfav = browser_connection_get_favorites (tsel->priv->bcnc);
689
690 id = gda_tools_favorites_find (bfav, 0, (gchar*) gtk_selection_data_get_data (selection_data),
691 &fav, NULL);
692 if (id < 0) {
693 memset (&fav, 0, sizeof (ToolsFavoritesAttributes));
694 fav.id = -1;
695 fav.type = GDA_TOOLS_FAVORITES_QUERIES;
696 fav.name = _("Unnamed query");
697 fav.descr = NULL;
698 fav.contents = (gchar*) gtk_selection_data_get_data (selection_data);
699 }
700
701 pos = atoi (path);
702 /*g_print ("%s() path => %s, pos: %d\n", __FUNCTION__, path, pos);*/
703
704 if (! gda_tools_favorites_add (bfav, 0, &fav, ORDER_KEY_QUERIES, pos, &error)) {
705 browser_show_error ((GtkWindow*) gtk_widget_get_toplevel ((GtkWidget*) tsel),
706 _("Could not add favorite: %s"),
707 error && error->message ? error->message : _("No detail"));
708 if (error)
709 g_error_free (error);
710 retval = FALSE;
711 }
712
713 if (id >= 0)
714 gda_tools_favorites_reset_attributes (&fav);
715
716 return retval;
717 }
718
719 static gboolean
tree_store_drag_can_drag_cb(G_GNUC_UNUSED GdauiTreeStore * store,const gchar * path,QueryFavoriteSelector * tsel)720 tree_store_drag_can_drag_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
721 QueryFavoriteSelector *tsel)
722 {
723 GdaTreeNode *node;
724 node = gda_tree_get_node (tsel->priv->tree, path, FALSE);
725 if (node) {
726 const GValue *cvalue;
727 cvalue = gda_tree_node_get_node_attribute (node, "fav_contents");
728 if (cvalue)
729 return TRUE;
730 }
731 return FALSE;
732 }
733
734 static gboolean
tree_store_drag_get_cb(G_GNUC_UNUSED GdauiTreeStore * store,const gchar * path,GtkSelectionData * selection_data,QueryFavoriteSelector * tsel)735 tree_store_drag_get_cb (G_GNUC_UNUSED GdauiTreeStore *store, const gchar *path,
736 GtkSelectionData *selection_data,
737 QueryFavoriteSelector *tsel)
738 {
739 GdaTreeNode *node;
740 node = gda_tree_get_node (tsel->priv->tree, path, FALSE);
741 if (node) {
742 const GValue *cvalue;
743 cvalue = gda_tree_node_get_node_attribute (node, "fav_contents");
744 if (cvalue) {
745 const gchar *str;
746 str = g_value_get_string (cvalue);
747 gtk_selection_data_set (selection_data, gtk_selection_data_get_target (selection_data),
748 8, (guchar*) str, strlen (str));
749 return TRUE;
750 }
751 }
752 return FALSE;
753 }
754
755 static void
favorites_changed_cb(G_GNUC_UNUSED ToolsFavorites * bfav,QueryFavoriteSelector * tsel)756 favorites_changed_cb (G_GNUC_UNUSED ToolsFavorites *bfav, QueryFavoriteSelector *tsel)
757 {
758 if (! gda_tree_update_all (tsel->priv->tree, NULL)) {
759 if (tsel->priv->idle_update_favorites == 0)
760 tsel->priv->idle_update_favorites = g_idle_add ((GSourceFunc) idle_update_favorites, tsel);
761
762 }
763 }
764