1 /*
2 * Copyright (C) 2009 - 2011 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 library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include <string.h>
23 #include <glib/gi18n-lib.h>
24 #include <libgda/libgda.h>
25 #include "gdaui-data-proxy.h"
26 #include "gdaui-data-selector.h"
27 #include "gdaui-raw-grid.h"
28 #include "gdaui-data-proxy-info.h"
29 #include "gdaui-enum-types.h"
30
31 static void gdaui_data_proxy_info_class_init (GdauiDataProxyInfoClass * class);
32 static void gdaui_data_proxy_info_init (GdauiDataProxyInfo *wid);
33 static void gdaui_data_proxy_info_dispose (GObject *object);
34
35 static void gdaui_data_proxy_info_set_property (GObject *object,
36 guint param_id,
37 const GValue *value,
38 GParamSpec *pspec);
39 static void gdaui_data_proxy_info_get_property (GObject *object,
40 guint param_id,
41 GValue *value,
42 GParamSpec *pspec);
43
44 static void modif_buttons_make (GdauiDataProxyInfo *info);
45 static void modif_buttons_update (GdauiDataProxyInfo *info);
46
47 static void data_proxy_proxy_changed_cb (GdauiDataProxy *data_proxy, GdaDataProxy *proxy, GdauiDataProxyInfo *info);
48 static void proxy_changed_cb (GdaDataProxy *proxy, GdauiDataProxyInfo *info);
49 static void proxy_sample_changed_cb (GdaDataProxy *proxy, gint sample_start, gint sample_end, GdauiDataProxyInfo *info);
50 static void proxy_row_changed_cb (GdaDataProxy *proxy, gint row, GdauiDataProxyInfo *info);
51 static void proxy_reset_cb (GdaDataProxy *wid, GdauiDataProxyInfo *info);
52
53 static void raw_grid_selection_changed_cb (GdauiRawGrid *grid, GdauiDataProxyInfo *info);
54
55
56 struct _GdauiDataProxyInfoPriv
57 {
58 GdauiDataProxy *data_proxy;
59 GdaDataProxy *proxy;
60 GdaDataModelIter *iter;
61 GdauiDataProxyInfoFlag flags; /* ORed values. */
62
63 GtkUIManager *uimanager;
64 GtkActionGroup *agroup; /* no ref held! */
65 guint merge_id_row_modif;
66 guint merge_id_row_move;
67 guint merge_id_chunck_change;
68
69 GtkWidget *buttons_bar;
70 gboolean buttons_bar_from_ui;
71 GtkWidget *tool_item;
72 GtkWidget *current_sample;
73 GtkWidget *row_spin;
74
75 guint idle_id;
76 };
77
78 /* get a pointer to the parents to be able to call their destructor */
79 static GObjectClass *parent_class = NULL;
80
81 /* properties */
82 enum {
83 PROP_0,
84 PROP_DATA_PROXY,
85 PROP_FLAGS,
86 PROP_UI_MANAGER
87 };
88
89 GType
gdaui_data_proxy_info_get_type(void)90 gdaui_data_proxy_info_get_type (void)
91 {
92 static GType type = 0;
93
94 if (G_UNLIKELY (type == 0)) {
95 static const GTypeInfo info = {
96 sizeof (GdauiDataProxyInfoClass),
97 (GBaseInitFunc) NULL,
98 (GBaseFinalizeFunc) NULL,
99 (GClassInitFunc) gdaui_data_proxy_info_class_init,
100 NULL,
101 NULL,
102 sizeof (GdauiDataProxyInfo),
103 0,
104 (GInstanceInitFunc) gdaui_data_proxy_info_init,
105 0
106 };
107
108 type = g_type_register_static (GTK_TYPE_BOX, "GdauiDataProxyInfo", &info, 0);
109 }
110
111 return type;
112 }
113
114 static void
gdaui_data_proxy_info_class_init(GdauiDataProxyInfoClass * klass)115 gdaui_data_proxy_info_class_init (GdauiDataProxyInfoClass *klass)
116 {
117 GObjectClass *object_class = G_OBJECT_CLASS (klass);
118
119 parent_class = g_type_class_peek_parent (klass);
120
121
122 object_class->dispose = gdaui_data_proxy_info_dispose;
123
124 /* Properties */
125 object_class->set_property = gdaui_data_proxy_info_set_property;
126 object_class->get_property = gdaui_data_proxy_info_get_property;
127 g_object_class_install_property (object_class, PROP_DATA_PROXY,
128 g_param_spec_object ("data-proxy", NULL, NULL, GDAUI_TYPE_DATA_PROXY,
129 G_PARAM_READABLE | G_PARAM_WRITABLE));
130 g_object_class_install_property (object_class, PROP_FLAGS,
131 g_param_spec_flags ("flags", NULL, NULL, GDAUI_TYPE_DATA_PROXY_INFO_FLAG,
132 GDAUI_DATA_PROXY_INFO_CURRENT_ROW,
133 G_PARAM_READABLE | G_PARAM_WRITABLE));
134 /**
135 * GdauiDataProxyInfo:ui-manager:
136 *
137 * Use this property to obtain the #GtkUIManager object internally used (to add new actions
138 * for example).
139 *
140 * Since: 4.2.9
141 */
142 g_object_class_install_property (object_class, PROP_UI_MANAGER,
143 g_param_spec_object ("ui-manager", NULL, NULL, GTK_TYPE_UI_MANAGER,
144 G_PARAM_READABLE));
145 }
146
147 static void
gdaui_data_proxy_info_init(GdauiDataProxyInfo * wid)148 gdaui_data_proxy_info_init (GdauiDataProxyInfo *wid)
149 {
150 wid->priv = g_new0 (GdauiDataProxyInfoPriv, 1);
151 wid->priv->data_proxy = NULL;
152 wid->priv->proxy = NULL;
153 wid->priv->row_spin = NULL;
154 wid->priv->buttons_bar = NULL;
155 wid->priv->tool_item = NULL;
156 }
157
158 /**
159 * gdaui_data_proxy_info_new:
160 * @data_proxy: a widget implementing the #GdauiDataProxy interface
161 * @flags: OR'ed values, specifying what to display in the new widget
162 *
163 * Creates a new #GdauiDataProxyInfo widget suitable to display information about @data_proxy
164 *
165 * Returns: (transfer full): the new widget
166 *
167 * Since: 4.2
168 */
169 GtkWidget *
gdaui_data_proxy_info_new(GdauiDataProxy * data_proxy,GdauiDataProxyInfoFlag flags)170 gdaui_data_proxy_info_new (GdauiDataProxy *data_proxy, GdauiDataProxyInfoFlag flags)
171 {
172 GtkWidget *info;
173
174 g_return_val_if_fail (!data_proxy || GDAUI_IS_DATA_PROXY (data_proxy), NULL);
175
176 info = (GtkWidget *) g_object_new (GDAUI_TYPE_DATA_PROXY_INFO,
177 "data-proxy", data_proxy,
178 "flags", flags, NULL);
179
180 return info;
181 }
182
183 static void
data_proxy_destroyed_cb(GdauiDataProxy * wid,GdauiDataProxyInfo * info)184 data_proxy_destroyed_cb (GdauiDataProxy *wid, GdauiDataProxyInfo *info)
185 {
186 g_assert (wid == info->priv->data_proxy);
187 g_signal_handlers_disconnect_by_func (G_OBJECT (wid),
188 G_CALLBACK (data_proxy_destroyed_cb), info);
189 g_signal_handlers_disconnect_by_func (G_OBJECT (wid),
190 G_CALLBACK (data_proxy_proxy_changed_cb), info);
191 if (GDAUI_IS_RAW_GRID (info->priv->data_proxy))
192 g_signal_handlers_disconnect_by_func (info->priv->data_proxy,
193 G_CALLBACK (raw_grid_selection_changed_cb), info);
194
195 info->priv->data_proxy = NULL;
196 }
197
198 static void
release_proxy(GdauiDataProxyInfo * info)199 release_proxy (GdauiDataProxyInfo *info)
200 {
201 g_signal_handlers_disconnect_by_func (G_OBJECT (info->priv->proxy),
202 G_CALLBACK (proxy_changed_cb), info);
203 g_signal_handlers_disconnect_by_func (G_OBJECT (info->priv->proxy),
204 G_CALLBACK (proxy_sample_changed_cb), info);
205 g_signal_handlers_disconnect_by_func (G_OBJECT (info->priv->proxy),
206 G_CALLBACK (proxy_row_changed_cb), info);
207 g_signal_handlers_disconnect_by_func (G_OBJECT (info->priv->proxy),
208 G_CALLBACK (proxy_reset_cb), info);
209 g_object_unref (info->priv->proxy);
210 info->priv->proxy = NULL;
211 }
212
213 static void iter_row_changed_cb (GdaDataModelIter *iter, gint row, GdauiDataProxyInfo *info);
214 static void
release_iter(GdauiDataProxyInfo * info)215 release_iter (GdauiDataProxyInfo *info)
216 {
217 g_signal_handlers_disconnect_by_func (info->priv->iter,
218 G_CALLBACK (iter_row_changed_cb), info);
219 g_object_unref (info->priv->iter);
220 info->priv->iter = NULL;
221 }
222
223 static void
data_proxy_proxy_changed_cb(GdauiDataProxy * data_proxy,G_GNUC_UNUSED GdaDataProxy * proxy,GdauiDataProxyInfo * info)224 data_proxy_proxy_changed_cb (GdauiDataProxy *data_proxy, G_GNUC_UNUSED GdaDataProxy *proxy, GdauiDataProxyInfo *info)
225 {
226 g_object_set (G_OBJECT (info), "data-proxy", data_proxy, NULL);
227 }
228
229 static void
gdaui_data_proxy_info_dispose(GObject * object)230 gdaui_data_proxy_info_dispose (GObject *object)
231 {
232 GdauiDataProxyInfo *info;
233
234 g_return_if_fail (object != NULL);
235 g_return_if_fail (GDAUI_IS_DATA_PROXY_INFO (object));
236 info = GDAUI_DATA_PROXY_INFO (object);
237
238 if (info->priv) {
239 if (info->priv->proxy)
240 release_proxy (info);
241 if (info->priv->iter)
242 release_iter (info);
243 if (info->priv->data_proxy)
244 data_proxy_destroyed_cb (info->priv->data_proxy, info);
245 if (info->priv->idle_id)
246 g_source_remove (info->priv->idle_id);
247
248 if (info->priv->uimanager) {
249 if (info->priv->merge_id_row_modif)
250 gtk_ui_manager_remove_ui (info->priv->uimanager,
251 info->priv->merge_id_row_modif);
252 if (info->priv->merge_id_row_move)
253 gtk_ui_manager_remove_ui (info->priv->uimanager,
254 info->priv->merge_id_row_move);
255 if (info->priv->merge_id_chunck_change)
256 gtk_ui_manager_remove_ui (info->priv->uimanager,
257 info->priv->merge_id_chunck_change);
258 g_object_unref (info->priv->uimanager);
259 }
260
261 /* the private area itself */
262 g_free (info->priv);
263 info->priv = NULL;
264 }
265
266 /* for the parent class */
267 parent_class->dispose (object);
268 }
269
270 static void
gdaui_data_proxy_info_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)271 gdaui_data_proxy_info_set_property (GObject *object,
272 guint param_id,
273 const GValue *value,
274 GParamSpec *pspec)
275 {
276 GdauiDataProxyInfo *info;
277
278 info = GDAUI_DATA_PROXY_INFO (object);
279 if (info->priv) {
280 switch (param_id) {
281 case PROP_DATA_PROXY:
282 if (info->priv->data_proxy)
283 data_proxy_destroyed_cb (info->priv->data_proxy, info);
284 if (info->priv->iter)
285 release_iter (info);
286 if (info->priv->proxy)
287 release_proxy (info);
288
289 info->priv->data_proxy = GDAUI_DATA_PROXY (g_value_get_object (value));
290 if (info->priv->data_proxy) {
291 GdaDataProxy *proxy;
292 GdaDataModelIter *iter;
293
294 /* data widget */
295 g_signal_connect (info->priv->data_proxy, "destroy",
296 G_CALLBACK (data_proxy_destroyed_cb), info);
297 g_signal_connect (info->priv->data_proxy, "proxy-changed",
298 G_CALLBACK (data_proxy_proxy_changed_cb), info);
299 if (GDAUI_IS_RAW_GRID (info->priv->data_proxy))
300 g_signal_connect (info->priv->data_proxy, "selection-changed",
301 G_CALLBACK (raw_grid_selection_changed_cb), info);
302
303 /* proxy */
304 proxy = gdaui_data_proxy_get_proxy (info->priv->data_proxy);
305 if (proxy) {
306 info->priv->proxy = proxy;
307 g_object_ref (info->priv->proxy);
308 g_signal_connect (G_OBJECT (proxy), "changed",
309 G_CALLBACK (proxy_changed_cb), info);
310 g_signal_connect (G_OBJECT (proxy), "sample-changed",
311 G_CALLBACK (proxy_sample_changed_cb), info);
312 g_signal_connect (G_OBJECT (proxy), "row-inserted",
313 G_CALLBACK (proxy_row_changed_cb), info);
314 g_signal_connect (G_OBJECT (proxy), "row-removed",
315 G_CALLBACK (proxy_row_changed_cb), info);
316 g_signal_connect (G_OBJECT (proxy), "reset",
317 G_CALLBACK (proxy_reset_cb), info);
318
319
320 /* iter */
321 iter = gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR
322 (info->priv->data_proxy));
323 info->priv->iter = iter;
324 if (iter) {
325 g_object_ref (G_OBJECT (iter));
326 g_signal_connect (iter, "row-changed",
327 G_CALLBACK (iter_row_changed_cb), info);
328 }
329 }
330 modif_buttons_update (info);
331 }
332 break;
333 case PROP_FLAGS:
334 info->priv->flags = g_value_get_flags (value);
335 modif_buttons_make (info);
336 modif_buttons_update (info);
337 break;
338 default:
339 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
340 break;
341 }
342 }
343 }
344
345 static void
gdaui_data_proxy_info_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)346 gdaui_data_proxy_info_get_property (GObject *object,
347 guint param_id,
348 GValue *value,
349 GParamSpec *pspec)
350 {
351 GdauiDataProxyInfo *info;
352
353 info = GDAUI_DATA_PROXY_INFO (object);
354 if (info->priv) {
355 switch (param_id) {
356 case PROP_DATA_PROXY:
357 g_value_set_object (value, info->priv->data_proxy);
358 break;
359 case PROP_FLAGS:
360 g_value_set_flags (value, info->priv->flags);
361 break;
362 case PROP_UI_MANAGER:
363 g_value_set_object (value, info->priv->uimanager);
364 break;
365 default:
366 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
367 break;
368 }
369 }
370 }
371
372
373 static void
proxy_changed_cb(G_GNUC_UNUSED GdaDataProxy * proxy,G_GNUC_UNUSED GdauiDataProxyInfo * info)374 proxy_changed_cb (G_GNUC_UNUSED GdaDataProxy *proxy, G_GNUC_UNUSED GdauiDataProxyInfo *info)
375 {
376 modif_buttons_update (info);
377 }
378
379 static void
proxy_sample_changed_cb(G_GNUC_UNUSED GdaDataProxy * proxy,G_GNUC_UNUSED gint sample_start,G_GNUC_UNUSED gint sample_end,G_GNUC_UNUSED GdauiDataProxyInfo * info)380 proxy_sample_changed_cb (G_GNUC_UNUSED GdaDataProxy *proxy, G_GNUC_UNUSED gint sample_start,
381 G_GNUC_UNUSED gint sample_end, G_GNUC_UNUSED GdauiDataProxyInfo *info)
382 {
383 modif_buttons_update (info);
384 }
385
386 static void
proxy_row_changed_cb(G_GNUC_UNUSED GdaDataProxy * proxy,G_GNUC_UNUSED gint row,GdauiDataProxyInfo * info)387 proxy_row_changed_cb (G_GNUC_UNUSED GdaDataProxy *proxy, G_GNUC_UNUSED gint row, GdauiDataProxyInfo *info)
388 {
389 modif_buttons_update (info);
390 }
391
392 static void
proxy_reset_cb(G_GNUC_UNUSED GdaDataProxy * wid,GdauiDataProxyInfo * info)393 proxy_reset_cb (G_GNUC_UNUSED GdaDataProxy *wid, GdauiDataProxyInfo *info)
394 {
395 modif_buttons_make (info);
396 modif_buttons_update (info);
397 }
398
399 static void
iter_row_changed_cb(G_GNUC_UNUSED GdaDataModelIter * iter,G_GNUC_UNUSED gint row,GdauiDataProxyInfo * info)400 iter_row_changed_cb (G_GNUC_UNUSED GdaDataModelIter *iter, G_GNUC_UNUSED gint row, GdauiDataProxyInfo *info)
401 {
402 modif_buttons_update (info);
403 }
404
405 static void
raw_grid_selection_changed_cb(G_GNUC_UNUSED GdauiRawGrid * grid,GdauiDataProxyInfo * info)406 raw_grid_selection_changed_cb (G_GNUC_UNUSED GdauiRawGrid *grid, GdauiDataProxyInfo *info)
407 {
408 modif_buttons_update (info);
409 }
410
411 /*
412 *
413 * Modification buttons (Commit changes, Reset info, New entry, Delete)
414 *
415 */
416 static const gchar *ui_base =
417 "<ui>"
418 " <toolbar name='ToolBar'>"
419 " <placeholder name='RowModif'/>"
420 " <placeholder name='RowModifExtension'/>"
421 " <placeholder name='RowMove'/>"
422 " <placeholder name='ChunkChange'/>"
423 " <toolitem action='ActionFilter'/>"
424 " </toolbar>"
425 "</ui>";
426
427 static const gchar *ui_row_modif =
428 "<ui>"
429 " <toolbar name='ToolBar'>"
430 " <placeholder name='RowModif'>"
431 " <toolitem action='ActionNew'/>"
432 " <toolitem action='ActionDelete'/>"
433 " <toolitem action='ActionCommit'/>"
434 " <toolitem action='ActionReset'/>"
435 " </placeholder>"
436 " </toolbar>"
437 "</ui>";
438 static const gchar *ui_row_move =
439 "<ui>"
440 " <toolbar name='ToolBar'>"
441 " <placeholder name='RowMove'>"
442 " <toolitem action='ActionFirstRecord'/>"
443 " <toolitem action='ActionPrevRecord'/>"
444 " <toolitem action='ActionNextRecord'/>"
445 " <toolitem action='ActionLastRecord'/>"
446 " </placeholder>"
447 " </toolbar>"
448 "</ui>";
449 static const gchar *ui_chunck_change =
450 "<ui>"
451 " <toolbar name='ToolBar'>"
452 " <placeholder name='ChunkChange'>"
453 " <toolitem action='ActionFirstChunck'/>"
454 " <toolitem action='ActionPrevChunck'/>"
455 " <toolitem action='ActionNextChunck'/>"
456 " <toolitem action='ActionLastChunck'/>"
457 " </placeholder>"
458 " </toolbar>"
459 "</ui>";
460
461
462 static void row_spin_changed_cb (GtkSpinButton *spin, GdauiDataProxyInfo *info);
463 static void
modif_buttons_make(GdauiDataProxyInfo * info)464 modif_buttons_make (GdauiDataProxyInfo *info)
465 {
466 GtkWidget *wid;
467 GdauiDataProxyInfoFlag flags = info->priv->flags;
468
469 if (! info->priv->data_proxy)
470 return;
471
472 if (info->priv->tool_item) {
473 /* remove tool_item from toolbar */
474 gtk_container_remove (GTK_CONTAINER (info->priv->buttons_bar),
475 info->priv->tool_item);
476 gtk_widget_unparent (info->priv->tool_item);
477 }
478
479 if (info->priv->uimanager) {
480 if (info->priv->merge_id_row_modif) {
481 gtk_ui_manager_remove_ui (info->priv->uimanager, info->priv->merge_id_row_modif);
482 info->priv->merge_id_row_modif = 0;
483 }
484 if (info->priv->merge_id_row_move) {
485 gtk_ui_manager_remove_ui (info->priv->uimanager, info->priv->merge_id_row_move);
486 info->priv->merge_id_row_move = 0;
487 }
488 if (info->priv->merge_id_chunck_change) {
489 gtk_ui_manager_remove_ui (info->priv->uimanager, info->priv->merge_id_chunck_change);
490 info->priv->merge_id_chunck_change = 0;
491 }
492 gtk_ui_manager_remove_action_group (info->priv->uimanager, info->priv->agroup);
493 info->priv->agroup = NULL;
494 }
495 else {
496 info->priv->uimanager = gtk_ui_manager_new ();
497 gtk_ui_manager_add_ui_from_string (info->priv->uimanager, ui_base, -1, NULL);
498 }
499
500 info->priv->agroup = gdaui_data_proxy_get_actions_group (info->priv->data_proxy);
501 gtk_ui_manager_insert_action_group (info->priv->uimanager, info->priv->agroup, 0);
502
503 if (flags & (GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS |
504 GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS |
505 GDAUI_DATA_PROXY_INFO_CHUNCK_CHANGE_BUTTONS)) {
506 GtkUIManager *ui;
507 ui = info->priv->uimanager;
508 if (flags & GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS)
509 info->priv->merge_id_row_modif = gtk_ui_manager_add_ui_from_string (ui, ui_row_modif,
510 -1, NULL);
511 if (flags & GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS)
512 info->priv->merge_id_row_move = gtk_ui_manager_add_ui_from_string (ui, ui_row_move,
513 -1, NULL);
514 if (flags & GDAUI_DATA_PROXY_INFO_CHUNCK_CHANGE_BUTTONS)
515 info->priv->merge_id_chunck_change = gtk_ui_manager_add_ui_from_string (ui, ui_chunck_change,
516 -1, NULL);
517 }
518
519 /* get rid of previous toolbar if any */
520 if (info->priv->buttons_bar) {
521 if (gtk_widget_get_parent (info->priv->buttons_bar)) {
522 gtk_container_remove (GTK_CONTAINER (info), info->priv->buttons_bar);
523 gtk_widget_unparent (info->priv->buttons_bar);
524 }
525 if (info->priv->buttons_bar_from_ui)
526 g_object_unref (info->priv->buttons_bar);
527 else
528 gtk_widget_destroy (info->priv->buttons_bar);
529 info->priv->buttons_bar = NULL;
530 }
531
532 /* create new toolbar */
533 GtkUIManager *ui;
534 ui = info->priv->uimanager;
535 info->priv->buttons_bar = gtk_ui_manager_get_widget (ui, "/ToolBar");
536 if (info->priv->buttons_bar)
537 info->priv->buttons_bar_from_ui = TRUE;
538 else {
539 info->priv->buttons_bar = gtk_toolbar_new ();
540 info->priv->buttons_bar_from_ui = FALSE;
541 }
542 g_object_ref_sink (info->priv->buttons_bar);
543 gtk_toolbar_set_icon_size (GTK_TOOLBAR (info->priv->buttons_bar), GTK_ICON_SIZE_MENU);
544 g_object_set (G_OBJECT (info->priv->buttons_bar), "toolbar-style", GTK_TOOLBAR_ICONS, NULL);
545 gtk_box_pack_start (GTK_BOX (info), info->priv->buttons_bar, TRUE, TRUE, 0);
546 gtk_widget_show (info->priv->buttons_bar);
547
548 if (flags & GDAUI_DATA_PROXY_INFO_CURRENT_ROW) {
549 if (info->priv->tool_item) {
550 /* remove the current contents */
551 gtk_widget_destroy (gtk_bin_get_child (GTK_BIN (info->priv->tool_item)));
552 info->priv->row_spin = NULL;
553 info->priv->current_sample = NULL;
554 gtk_toolbar_insert (GTK_TOOLBAR (info->priv->buttons_bar),
555 GTK_TOOL_ITEM (info->priv->tool_item), -1);
556 }
557 else {
558 GtkToolItem *ti;
559 ti = gtk_tool_item_new ();
560 gtk_toolbar_insert (GTK_TOOLBAR (info->priv->buttons_bar), ti, -1);
561 info->priv->tool_item = GTK_WIDGET (g_object_ref (G_OBJECT (ti)));
562 }
563
564 GtkWidget *toolwid;
565 PangoContext *pc;
566 PangoFontDescription *fd, *fdc;
567 pc = gtk_widget_get_pango_context (GTK_WIDGET (info));
568 fd = pango_context_get_font_description (pc);
569 fdc = pango_font_description_copy (fd);
570 pango_font_description_set_size (fdc,
571 pango_font_description_get_size (fd) * .8);
572
573 if (flags & GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS) {
574 toolwid = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
575
576 /* read-write spin counter (mainly for forms) */
577 wid = gtk_spin_button_new_with_range (0, 1, 1);
578
579 gtk_widget_override_font (wid, fdc);
580 gtk_spin_button_set_digits (GTK_SPIN_BUTTON (wid), 0);
581 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (wid), TRUE);
582 gtk_box_pack_start (GTK_BOX (toolwid), wid, FALSE, TRUE, 2);
583 gtk_widget_set_sensitive (wid, FALSE);
584 info->priv->row_spin = wid;
585 g_signal_connect (G_OBJECT (wid), "value-changed",
586 G_CALLBACK (row_spin_changed_cb), info);
587
588 /* rows counter */
589 wid = gtk_label_new (" /?");
590 gtk_widget_override_font (wid, fdc);
591 info->priv->current_sample = wid;
592 gtk_box_pack_start (GTK_BOX (toolwid), wid, FALSE, FALSE, 2);
593 }
594 else {
595 /* read-only counter (mainly for grids) */
596 wid = gtk_label_new ("? - ? /?");
597 gtk_widget_override_font (wid, fdc);
598 info->priv->current_sample = wid;
599 toolwid = wid;
600 }
601
602 pango_font_description_free (fdc);
603
604 gtk_container_add (GTK_CONTAINER (info->priv->tool_item), toolwid);
605 gtk_widget_show_all (info->priv->tool_item);
606 }
607 else if (info->priv->tool_item)
608 gtk_widget_hide (info->priv->tool_item);
609 }
610
611 static void
row_spin_changed_cb(GtkSpinButton * spin,GdauiDataProxyInfo * info)612 row_spin_changed_cb (GtkSpinButton *spin, GdauiDataProxyInfo *info)
613 {
614 gint row, nrows;
615 gint value = gtk_spin_button_get_value (spin);
616 nrows = gda_data_model_get_n_rows (GDA_DATA_MODEL (info->priv->proxy));
617
618 if ((value >= 1) && (value <= nrows))
619 row = value - 1;
620 else if (value > nrows)
621 row = nrows - 1;
622 else
623 row = 0;
624 gda_data_model_iter_move_to_row (gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (info->priv->data_proxy)),
625 row);
626 }
627
628 static gboolean idle_modif_buttons_update (GdauiDataProxyInfo *info);
629 static void
modif_buttons_update(GdauiDataProxyInfo * info)630 modif_buttons_update (GdauiDataProxyInfo *info)
631 {
632 if (info->priv->idle_id == 0)
633 info->priv->idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
634 (GSourceFunc) idle_modif_buttons_update,
635 g_object_ref (info), g_object_unref);
636 }
637
638
639 #define BLOCK_SPIN (g_signal_handlers_block_by_func (G_OBJECT (info->priv->row_spin), \
640 G_CALLBACK (row_spin_changed_cb), info))
641 #define UNBLOCK_SPIN (g_signal_handlers_unblock_by_func (G_OBJECT (info->priv->row_spin), \
642 G_CALLBACK (row_spin_changed_cb), info))
643 static gboolean
idle_modif_buttons_update(GdauiDataProxyInfo * info)644 idle_modif_buttons_update (GdauiDataProxyInfo *info)
645 {
646 GdaDataModelIter *model_iter;
647 gboolean wrows, filtered_proxy = FALSE;
648 gint row;
649
650 gint proxy_rows = 0;
651 gint proxied_rows = 0;
652 gint all_rows = 0;
653
654 GtkAction *action;
655 gint sample_first_row = 0, sample_last_row = 0, sample_size = 0;
656 GdauiDataProxyInfoFlag flags = 0;
657
658 model_iter = gdaui_data_selector_get_data_set (GDAUI_DATA_SELECTOR (info->priv->data_proxy));
659 if (info->priv->proxy) {
660 filtered_proxy = gda_data_proxy_get_filter_expr (info->priv->proxy) ? TRUE : FALSE;
661 proxy_rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (info->priv->proxy));
662 if (filtered_proxy) {
663 proxied_rows = gda_data_proxy_get_filtered_n_rows (info->priv->proxy);
664 all_rows = proxied_rows;
665 }
666 else {
667 proxied_rows = gda_data_proxy_get_proxied_model_n_rows (info->priv->proxy);
668 all_rows = proxied_rows + gda_data_proxy_get_n_new_rows (info->priv->proxy);
669 }
670
671 /* samples don't take into account the proxy's inserted rows */
672 sample_first_row = gda_data_proxy_get_sample_start (info->priv->proxy);
673 sample_last_row = gda_data_proxy_get_sample_end (info->priv->proxy);
674 sample_size = gda_data_proxy_get_sample_size (info->priv->proxy);
675
676 flags = gda_data_model_get_access_flags (GDA_DATA_MODEL (info->priv->proxy));
677 }
678
679 /* sensitiveness of the text indications and of the spin button */
680 wrows = (proxy_rows <= 0) ? FALSE : TRUE;
681 row = model_iter ? gda_data_model_iter_get_row (model_iter) : 0;
682 if (info->priv->flags & GDAUI_DATA_PROXY_INFO_CURRENT_ROW) {
683 if (proxy_rows < 0) {
684 if (info->priv->flags & GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS) {
685 BLOCK_SPIN;
686 gtk_spin_button_set_range (GTK_SPIN_BUTTON (info->priv->row_spin), 0, 1);
687 gtk_spin_button_set_value (GTK_SPIN_BUTTON (info->priv->row_spin), 0);
688 UNBLOCK_SPIN;
689 gtk_label_set_text (GTK_LABEL (info->priv->current_sample), " /?");
690 }
691 else
692 gtk_label_set_text (GTK_LABEL (info->priv->current_sample), "? - ? /?");
693 }
694 else {
695 gchar *str;
696 gint total;
697
698 total = sample_first_row + proxy_rows;
699 if (info->priv->flags & GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS) {
700 if (total <= 0)
701 str = g_strdup (" / 0");
702 else {
703 if (filtered_proxy)
704 str = g_strdup_printf (" / (%d)", proxy_rows);
705 else
706 str = g_strdup_printf (" / %d", proxy_rows);
707 }
708 BLOCK_SPIN;
709 gtk_spin_button_set_range (GTK_SPIN_BUTTON (info->priv->row_spin),
710 proxy_rows > 0 ? 1 : 0,
711 proxy_rows);
712 if (row >= 0)
713 if (gtk_spin_button_get_value (GTK_SPIN_BUTTON (info->priv->row_spin)) != row+1)
714 gtk_spin_button_set_value (GTK_SPIN_BUTTON (info->priv->row_spin), row+1);
715 UNBLOCK_SPIN;
716 }
717 else {
718 if (total <= 0)
719 str = g_strdup_printf ("0 - 0 / 0");
720 else {
721 if (all_rows < 0)
722 str = g_strdup_printf ("%d - %d /?", sample_first_row + 1, total);
723 else {
724 if (filtered_proxy)
725 str = g_strdup_printf ("%d - %d / (%d)",
726 sample_first_row + 1, total, all_rows);
727 else
728 str = g_strdup_printf ("%d - %d / %d",
729 sample_first_row + 1, total, all_rows);
730 }
731 }
732 }
733
734 gtk_label_set_text (GTK_LABEL (info->priv->current_sample), str);
735 g_free (str);
736 }
737
738 gtk_widget_set_sensitive (info->priv->current_sample, wrows);
739 if (info->priv->row_spin)
740 gtk_widget_set_sensitive (info->priv->row_spin, wrows && (row >= 0));
741 }
742
743 /* current row modifications */
744 if (info->priv->buttons_bar) {
745 gboolean changed = FALSE;
746 gboolean to_be_deleted = FALSE;
747 gboolean is_inserted = FALSE;
748 gboolean force_del_btn = FALSE;
749 gboolean force_undel_btn = FALSE;
750 gboolean has_selection;
751
752 has_selection = (row >= 0) ? TRUE : FALSE;
753 if (info->priv->proxy) {
754 changed = gda_data_proxy_has_changed (info->priv->proxy);
755
756 if (has_selection) {
757 to_be_deleted = gda_data_proxy_row_is_deleted (info->priv->proxy, row);
758 is_inserted = gda_data_proxy_row_is_inserted (info->priv->proxy, row);
759 }
760 else
761 if (GDAUI_IS_RAW_GRID (info->priv->data_proxy)) {
762 /* bad for encapsulation, but very useful... */
763 GList *sel, *list;
764
765 sel = _gdaui_raw_grid_get_selection ((GdauiRawGrid*) info->priv->data_proxy);
766 if (sel) {
767 list = sel;
768 while (list && (!force_del_btn || !force_undel_btn)) {
769 if ((GPOINTER_TO_INT (list->data) != -1) &&
770 gda_data_proxy_row_is_deleted (info->priv->proxy,
771 GPOINTER_TO_INT (list->data)))
772 force_undel_btn = TRUE;
773 else
774 force_del_btn = TRUE;
775 list = g_list_next (list);
776 }
777 list = sel;
778
779 is_inserted = TRUE;
780 while (list && is_inserted) {
781 if (GPOINTER_TO_INT (list->data) != -1)
782 is_inserted = FALSE;
783 list = g_list_next (list);
784 }
785 g_list_free (sel);
786 }
787 }
788 }
789
790 if (info->priv->flags & GDAUI_DATA_PROXY_INFO_ROW_MODIFY_BUTTONS) {
791 GdauiDataProxyWriteMode mode;
792 mode = gdaui_data_proxy_get_write_mode (info->priv->data_proxy);
793
794 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowModif/ActionCommit");
795 g_object_set (G_OBJECT (action), "sensitive", changed ? TRUE : FALSE, NULL);
796 if (mode == GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE)
797 gtk_action_set_visible (action, FALSE);
798 else
799 gtk_action_set_visible (action, TRUE);
800
801 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowModif/ActionReset");
802 g_object_set (G_OBJECT (action), "sensitive", changed ? TRUE : FALSE, NULL);
803 if (mode == GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE)
804 gtk_action_set_visible (action, FALSE);
805 else
806 gtk_action_set_visible (action, TRUE);
807
808 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowModif/ActionNew");
809 g_object_set (G_OBJECT (action), "sensitive",
810 flags & GDA_DATA_MODEL_ACCESS_INSERT ? TRUE : FALSE, NULL);
811
812 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowModif/ActionDelete");
813 gtk_action_block_activate (action);
814 gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), to_be_deleted);
815 gtk_action_unblock_activate (action);
816
817 if (to_be_deleted) {
818 wrows = (flags & GDA_DATA_MODEL_ACCESS_DELETE) &&
819 (force_undel_btn || has_selection);
820 g_object_set (G_OBJECT (action), "sensitive", wrows, NULL);
821 gtk_action_set_tooltip (action, _("Undelete the selected entry"));
822 }
823 else {
824 wrows = is_inserted ||
825 ((flags & GDA_DATA_MODEL_ACCESS_DELETE) &&
826 (force_del_btn || has_selection));
827 g_object_set (G_OBJECT (action), "sensitive", wrows, NULL);
828 gtk_action_set_tooltip (action, _("Delete the selected entry"));
829 }
830
831 if ((mode == GDAUI_DATA_PROXY_WRITE_ON_ROW_CHANGE) ||
832 (mode == GDAUI_DATA_PROXY_WRITE_ON_VALUE_CHANGE) ||
833 (mode == GDAUI_DATA_PROXY_WRITE_ON_VALUE_ACTIVATED))
834 gtk_action_set_visible (action, FALSE);
835 else
836 gtk_action_set_visible (action, TRUE);
837 }
838 }
839
840 /* current row moving */
841 if (info->priv->flags & GDAUI_DATA_PROXY_INFO_ROW_MOVE_BUTTONS) {
842 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowMove/ActionFirstRecord");
843 g_object_set (G_OBJECT (action), "sensitive", (row <= 0) ? FALSE : TRUE, NULL);
844 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowMove/ActionPrevRecord");
845 g_object_set (G_OBJECT (action), "sensitive", (row <= 0) ? FALSE : TRUE, NULL);
846 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowMove/ActionNextRecord");
847 g_object_set (G_OBJECT (action), "sensitive", (row == proxy_rows -1) || (row < 0) ? FALSE : TRUE,
848 NULL);
849 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/RowMove/ActionLastRecord");
850 g_object_set (G_OBJECT (action), "sensitive", (row == proxy_rows -1) || (row < 0) ? FALSE : TRUE,
851 NULL);
852 }
853
854 /* chunck indications */
855 if (info->priv->flags & GDAUI_DATA_PROXY_INFO_CHUNCK_CHANGE_BUTTONS) {
856 gboolean abool;
857 wrows = (sample_size > 0) ? TRUE : FALSE;
858 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/ChunkChange/ActionFirstChunck");
859 g_object_set (G_OBJECT (action), "sensitive", wrows && sample_first_row > 0 ? TRUE : FALSE, NULL);
860 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/ChunkChange/ActionPrevChunck");
861 g_object_set (G_OBJECT (action), "sensitive", wrows && sample_first_row > 0 ? TRUE : FALSE, NULL);
862 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/ChunkChange/ActionNextChunck");
863 abool = (proxied_rows != -1) ? wrows && (sample_last_row < proxied_rows - 1) : TRUE;
864 g_object_set (G_OBJECT (action), "sensitive", abool, NULL);
865 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/ChunkChange/ActionLastChunck");
866 g_object_set (G_OBJECT (action), "sensitive", wrows && (sample_last_row < proxied_rows - 1), NULL);
867 }
868
869 /* filter */
870 action = gtk_ui_manager_get_action (info->priv->uimanager, "/ToolBar/ActionFilter");
871 if (info->priv->flags & GDAUI_DATA_PROXY_INFO_NO_FILTER)
872 g_object_set (G_OBJECT (action), "visible", FALSE, NULL);
873 else
874 g_object_set (G_OBJECT (action), "visible", TRUE, NULL);
875
876 if (info->priv->uimanager)
877 gtk_ui_manager_ensure_update (info->priv->uimanager);
878
879 /* remove IDLE */
880 info->priv->idle_id = 0;
881 return FALSE;
882 }
883