1 /* -*- Mode: C; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 3 -*- */
2 
3 /*
4  * gimv_elist.c - a set of clist and edit area widget.
5  * Copyright (C) 2001-2002 Takuro Ashie
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 3S30, Boston, MA 02111-1307, USA.
20  *
21  * $Id: gimv_elist.c,v 1.6 2004/09/22 15:37:11 makeinu Exp $
22  */
23 
24 #include "gimv_elist.h"
25 
26 #include <stdlib.h>
27 #include <string.h>
28 
29 #include "intl.h"
30 #include "gimv_marshal.h"
31 
32 
33 enum {
34    LIST_UPDATED_SIGNAL,
35    EDIT_AREA_SET_DATA_SIGNAL,
36    ACTION_CONFIRM_SIGNAL,
37    LAST_SIGNAL
38 };
39 
40 
41 #if (GTK_MAJOR_VERSION >= 2)
42 
43 #include <gobject/gvaluecollector.h>
44 
45 #define list_widget_get_row_num(widget) \
46    gtk_tree_model_iter_n_children (gtk_tree_view_get_model (GTK_TREE_VIEW (widget)), NULL);
47 
48 #define ROWDATA(columns)     columns
49 #define ROWDESTROY(columns)  columns + 1
50 #define ALL_COLUMNS(columns) columns + 2
51 
52 #else /* (GTK_MAJOR_VERSION >= 2) */
53 
54 #define list_widget_get_row_num(widget) GTK_CLIST (widget)->rows;
55 
56 #endif /* (GTK_MAJOR_VERSION >= 2) */
57 
58 
59 static void gimv_elist_init       (GimvEList *editlist);
60 static void gimv_elist_class_init (GimvEListClass *klass);
61 #ifdef USE_GTK2
62 static void gimv_elist_finalize   (GObject *object);
63 #else
64 static void gimv_elist_finalize   (GtkObject *object);
65 #endif
66 
67 /* private */
68 static void     gimv_elist_set_move_button_sensitive   (GimvEList *editlist);
69 static void     gimv_elist_set_sensitive               (GimvEList *editlist);
70 static void     gimv_elist_edit_area_set_data          (GimvEList *editlist,
71                                                         gint          row);
72 static gchar  **gimv_elist_edit_area_get_data          (GimvEList *editlist,
73                                                         GimvEListActionType type);
74 static void     gimv_elist_edit_area_reset             (GimvEList *editlist);
75 
76 
77 static GtkVBoxClass *parent_class = NULL;
78 static gint gimv_elist_signals[LAST_SIGNAL] = {0};
79 
80 
81 GtkType
gimv_elist_get_type(void)82 gimv_elist_get_type (void)
83 {
84    static GtkType gimv_elist_type = 0;
85 
86 #if (GTK_MAJOR_VERSION >= 2)
87    if (!gimv_elist_type) {
88       static const GTypeInfo gimv_elist_info = {
89          sizeof (GimvEListClass),
90          NULL,               /* base_init */
91          NULL,               /* base_finalize */
92          (GClassInitFunc)    gimv_elist_class_init,
93          NULL,               /* class_finalize */
94          NULL,               /* class_data */
95          sizeof (GimvEList),
96          0,                  /* n_preallocs */
97          (GInstanceInitFunc) gimv_elist_init,
98       };
99 
100       gimv_elist_type = g_type_register_static (GTK_TYPE_VBOX,
101                                                    "GimvEList",
102                                                    &gimv_elist_info,
103                                                    0);
104    }
105 #else /* (GTK_MAJOR_VERSION >= 2) */
106    if (!gimv_elist_type) {
107       static const GtkTypeInfo gimv_elist_info = {
108          "GimvEList",
109          sizeof (GimvEList),
110          sizeof (GimvEListClass),
111          (GtkClassInitFunc)  gimv_elist_class_init,
112          (GtkObjectInitFunc) gimv_elist_init,
113          NULL,
114          NULL,
115          (GtkClassInitFunc) NULL,
116       };
117 
118       gimv_elist_type = gtk_type_unique (gtk_vbox_get_type (),
119                                             &gimv_elist_info);
120    }
121 #endif /* (GTK_MAJOR_VERSION >= 2) */
122 
123    return gimv_elist_type;
124 }
125 
126 
127 static void
gimv_elist_init(GimvEList * editlist)128 gimv_elist_init (GimvEList *editlist)
129 {
130    editlist->clist              = NULL;
131    editlist->new_button         = NULL;
132    editlist->add_button         = NULL;
133    editlist->change_button      = NULL;
134    editlist->del_button         = NULL;
135    editlist->up_button          = NULL;
136    editlist->down_button        = NULL;
137    editlist->edit_area          = NULL;
138    editlist->move_button_area   = NULL;
139    editlist->action_button_area = NULL;
140 
141    editlist->max_row            = -1;
142    editlist->columns            = 0;
143    editlist->rows               = 0;
144    editlist->selected           = -1;
145    editlist->dest_row           = -1;
146 
147    editlist->edit_area_flags    = GIMV_ELIST_EDIT_AREA_VALUE_INITIALIZED;
148    editlist->column_func_tables = NULL;
149    editlist->get_rowdata_fn     = NULL;
150 
151 #if (GTK_MAJOR_VERSION >= 2)
152    editlist->rowdata_table
153       = g_hash_table_new (g_direct_hash, g_direct_equal);
154    editlist->rowdata_destroy_fn_table
155       = g_hash_table_new (g_direct_hash, g_direct_equal);
156 #endif /* (GTK_MAJOR_VERSION >= 2) */
157 }
158 
159 
160 static void
gimv_elist_class_init(GimvEListClass * klass)161 gimv_elist_class_init (GimvEListClass *klass)
162 {
163    GtkObjectClass *object_class;
164 
165    object_class = (GtkObjectClass *) klass;
166    parent_class = gtk_type_class (gtk_vbox_get_type ());
167 
168    gimv_elist_signals[LIST_UPDATED_SIGNAL]
169       = gtk_signal_new ("list-updated",
170                         GTK_RUN_FIRST,
171                         GTK_CLASS_TYPE(object_class),
172                         GTK_SIGNAL_OFFSET (GimvEListClass, list_updated),
173                         gtk_signal_default_marshaller,
174                         GTK_TYPE_NONE, 0);
175 
176    gimv_elist_signals[EDIT_AREA_SET_DATA_SIGNAL]
177       = gtk_signal_new ("edit-area-set-data",
178                         GTK_RUN_FIRST,
179                         GTK_CLASS_TYPE(object_class),
180                         GTK_SIGNAL_OFFSET (GimvEListClass, edit_area_set_data),
181                         gtk_signal_default_marshaller,
182                         GTK_TYPE_NONE, 0);
183 
184    gimv_elist_signals[ACTION_CONFIRM_SIGNAL]
185       = gtk_signal_new ("action-confirm",
186                         GTK_RUN_LAST,
187                         GTK_CLASS_TYPE(object_class),
188                         GTK_SIGNAL_OFFSET (GimvEListClass, action_confirm),
189                         gtk_marshal_NONE__INT_INT_POINTER,
190                         GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER);
191 
192    gtk_object_class_add_signals (object_class, gimv_elist_signals, LAST_SIGNAL);
193 
194    OBJECT_CLASS_SET_FINALIZE_FUNC (klass, gimv_elist_finalize);
195 }
196 
197 
198 static void
gimv_elist_updated(GimvEList * editlist)199 gimv_elist_updated (GimvEList *editlist)
200 {
201    g_return_if_fail (GIMV_IS_ELIST (editlist));
202 
203    gtk_signal_emit (GTK_OBJECT (editlist),
204                     gimv_elist_signals[LIST_UPDATED_SIGNAL]);
205 }
206 
207 
208 
209 /*******************************************************************************
210  *
211  *  Object class functions.
212  *
213  *******************************************************************************/
214 #if (GTK_MAJOR_VERSION >= 2)
215 static void
free_rowdata(gpointer key,gpointer value,gpointer data)216 free_rowdata (gpointer key, gpointer value, gpointer data)
217 {
218    GimvEList *editlist = data;
219    GtkDestroyNotify destroy;
220 
221    destroy = g_hash_table_lookup (editlist->rowdata_destroy_fn_table, value);
222    if (destroy)
223       destroy (value);
224 }
225 #endif /* (GTK_MAJOR_VERSION >= 2) */
226 
227 
228 static void
229 #ifdef USE_GTK2
gimv_elist_finalize(GObject * object)230 gimv_elist_finalize (GObject *object)
231 #else
232 gimv_elist_finalize (GtkObject *object)
233 #endif
234 {
235    GimvEList *editlist = GIMV_ELIST (object);
236    gint i;
237 
238    /* remove column funcs */
239    for (i = 0; i < editlist->columns; i++) {
240       GimvEListColumnFuncTable *table = editlist->column_func_tables[i];
241       if (table->destroy_fn)
242          table->destroy_fn (table->coldata);
243       g_free (table);
244       editlist->column_func_tables[i] = NULL;
245    }
246    g_free (editlist->column_func_tables);
247    editlist->column_func_tables = NULL;
248 
249 #if (GTK_MAJOR_VERSION >= 2)
250    g_hash_table_foreach (editlist->rowdata_table, free_rowdata, editlist);
251    g_hash_table_destroy (editlist->rowdata_table);
252    g_hash_table_destroy (editlist->rowdata_destroy_fn_table);
253 #endif /* (GTK_MAJOR_VERSION >= 2) */
254 
255    OBJECT_CLASS_FINALIZE_SUPER (parent_class, object);
256 }
257 
258 
259 
260 /*******************************************************************************
261  *
262  *  Callback functions for child widget.
263  *
264  *******************************************************************************/
265 #if (GTK_MAJOR_VERSION >= 2)
266 
267 static void
cb_editlist_cursor_changed(GtkTreeView * treeview,gpointer data)268 cb_editlist_cursor_changed (GtkTreeView *treeview, gpointer data)
269 {
270    GimvEList *editlist = data;
271    GtkTreeSelection *selection;
272    GtkTreeModel *model = NULL;
273    GtkTreeIter iter;
274    gboolean success;
275 
276    g_return_if_fail (treeview);
277    g_return_if_fail (editlist);
278 
279    selection = gtk_tree_view_get_selection (treeview);
280    success = gtk_tree_selection_get_selected (selection, &model, &iter);
281 
282    if (success) {
283       GtkTreePath *treepath = gtk_tree_model_get_path (model, &iter);
284       gchar *path = gtk_tree_path_to_string (treepath);
285 
286       editlist->selected = atoi (path);
287 
288       gtk_tree_path_free (treepath);
289       g_free (path);
290    } else {
291       editlist->selected = -1;
292    }
293 
294    gimv_elist_edit_area_set_data (editlist, editlist->selected);
295 
296    gimv_elist_set_sensitive (editlist);
297 }
298 
299 
300 static void
cb_editlist_row_changed(GtkTreeModel * model,GtkTreePath * treepath,GtkTreeIter * iter,gpointer data)301 cb_editlist_row_changed (GtkTreeModel *model,
302                          GtkTreePath *treepath,
303                          GtkTreeIter *iter,
304                          gpointer data)
305 {
306    GimvEList *editlist = data;
307 
308    gimv_elist_updated (editlist);
309 
310    gimv_elist_set_sensitive (editlist);
311 }
312 
313 
314 static void
cb_editlist_row_deleted(GtkTreeModel * model,GtkTreePath * treepath,gpointer data)315 cb_editlist_row_deleted (GtkTreeModel *model,
316                          GtkTreePath *treepath,
317                          gpointer data)
318 {
319    GimvEList *editlist = data;
320 
321    gimv_elist_updated (editlist);
322 
323    if (editlist->dest_row < 0) {
324       editlist->selected = -1;
325       gimv_elist_set_sensitive (editlist);
326    }
327    editlist->dest_row = -1;
328 
329    gimv_elist_edit_area_set_data (editlist, editlist->selected);
330 
331    gimv_elist_set_sensitive (editlist);
332 }
333 
334 #else /* (GTK_MAJOR_VERSION >=2) */
335 
336 static void
cb_editlist_select_row(GtkCList * clist,gint row,gint col,GdkEventButton * event,gpointer data)337 cb_editlist_select_row (GtkCList *clist, gint row, gint col,
338                         GdkEventButton *event, gpointer data)
339 {
340    GimvEList *editlist = data;
341 
342    editlist->selected = row;
343 
344    gimv_elist_edit_area_set_data (editlist, row);
345 
346    gimv_elist_set_sensitive (editlist);
347 }
348 
349 
350 static void
cb_editlist_unselect_row(GtkCList * clist,gint row,gint col,GdkEventButton * event,gpointer data)351 cb_editlist_unselect_row (GtkCList *clist, gint row, gint col,
352                           GdkEventButton *event, gpointer data)
353 {
354    GimvEList *editlist = data;
355 
356    editlist->selected = -1;
357 
358    gimv_elist_edit_area_set_data (editlist, -1);
359 
360    gimv_elist_set_sensitive (editlist);
361 }
362 
363 
364 static gint
idle_editlist_row_move(gpointer data)365 idle_editlist_row_move (gpointer data)
366 {
367    GimvEList *editlist = data;
368 
369    gimv_elist_updated (editlist);
370    gimv_elist_set_sensitive (editlist);
371 
372    return FALSE;
373 }
374 
375 
376 static void
cb_editlist_row_move(GtkCList * clist,gint arg1,gint arg2,gpointer data)377 cb_editlist_row_move (GtkCList *clist, gint arg1, gint arg2, gpointer data)
378 {
379    GimvEList *editlist = data;
380    gint src, dest = editlist->dest_row;
381    gint selected = editlist->selected;
382 
383    if (editlist->dest_row >= 0) {
384       dest = editlist->dest_row;
385       src  = arg1 == dest ? arg2 : arg1;
386    } else {
387       src  = arg1;
388       dest = arg2;
389    }
390 
391    if (selected >= 0) {
392       if (selected == src) {
393          editlist->selected = dest;
394       } else if (selected >= MIN (src, dest) && selected <= MAX (src, dest)) {
395          if (src < dest)
396             editlist->selected--;
397          else
398             editlist->selected++;
399       }
400    }
401 
402    editlist->dest_row = -1;
403 
404    gtk_idle_add (idle_editlist_row_move, editlist);
405 }
406 
407 #endif /* (GTK_MAJOR_VERSION >=2) */
408 
409 
410 static void
cb_editlist_up_button(GtkButton * button,gpointer data)411 cb_editlist_up_button (GtkButton *button, gpointer data)
412 {
413    GimvEList *editlist = data;
414 
415    gint selected = editlist->selected;
416    gint rows = editlist->rows;
417 
418    g_return_if_fail (button && editlist);
419 
420    if (selected < 1 || selected > rows - 1) return;
421 
422    editlist->dest_row = editlist->selected - 1;
423 
424 #if (GTK_MAJOR_VERSION >= 2)
425    {
426       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
427       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
428       GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
429       GtkTreePath *treepath;
430       GtkTreeIter iter, prev_iter, dest_iter;
431       gboolean success;
432 
433       GValue *values;
434       gint i, colnum = gtk_tree_model_get_n_columns (model);
435 
436       /* get src row */
437       selection = gtk_tree_view_get_selection (treeview);
438       success = gtk_tree_selection_get_selected (selection, &model, &iter);
439       if (!success) return;
440       treepath = gtk_tree_model_get_path (model, &iter);
441 
442       /* get prev row */
443       success = gtk_tree_path_prev (treepath);
444       if (!success) {
445          gtk_tree_path_free (treepath);
446          return;
447       }
448       gtk_tree_model_get_iter (model, &prev_iter, treepath);
449 
450       /* get src data */
451       values = g_new0 (GValue, colnum);
452       for (i = 0; i < colnum; i++) {
453          gtk_tree_model_get_value (model, &iter, i, &values[i]);
454       }
455 
456       /* insert dest row before prev */
457       gtk_list_store_insert_before (GTK_LIST_STORE (model),
458                                     &dest_iter, &prev_iter);
459       for (i = 0; i < colnum; i++) {
460          gtk_list_store_set_value (GTK_LIST_STORE (model), &dest_iter,
461                                    i, &values[i]);
462          g_value_unset (&values[i]);
463       }
464       g_free (values);
465 
466       /* delete src */
467       gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
468 
469       /* select dest */
470       gtk_tree_path_free (treepath);
471       treepath = gtk_tree_model_get_path (model, &dest_iter);
472       gtk_tree_view_set_cursor (treeview, treepath, NULL, FALSE);
473 
474       /* clean */
475       gtk_tree_path_free (treepath);
476    }
477 #else /* (GTK_MAJOR_VERSION >= 2) */
478    {
479       gtk_clist_swap_rows (GTK_CLIST (editlist->clist), selected, selected - 1);
480       gtk_clist_moveto (GTK_CLIST (editlist->clist), selected - 1, 0, 0, 0);
481    }
482 #endif /* (GTK_MAJOR_VERSION >= 2) */
483 }
484 
485 
486 static void
cb_editlist_down_button(GtkButton * button,gpointer data)487 cb_editlist_down_button (GtkButton *button, gpointer data)
488 {
489    GimvEList *editlist = data;
490    gint selected = editlist->selected;
491    gint rows = editlist->rows;
492 
493    g_return_if_fail (button && editlist);
494 
495    if (selected < 0 || selected > rows - 2) return;
496 
497    editlist->dest_row = editlist->selected + 1;
498 
499 #if (GTK_MAJOR_VERSION >= 2)
500    {
501       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
502       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
503       GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
504       GtkTreeIter iter, next_iter, dest_iter;
505       GtkTreePath *treepath;
506       gboolean success;
507 
508       GValue *values;
509       gint i, colnum = gtk_tree_model_get_n_columns (model);
510 
511       /* get src row */
512       selection = gtk_tree_view_get_selection (treeview);
513       success = gtk_tree_selection_get_selected (selection, &model, &iter);
514       if (!success) return;
515 
516       /* get prev row */
517       next_iter = iter;
518       success = gtk_tree_model_iter_next (model, &next_iter);
519       if (!success) return;
520 
521       /* get src data */
522       values = g_new0 (GValue, colnum);
523       for (i = 0; i < colnum; i++) {
524          gtk_tree_model_get_value (model, &iter, i, &values[i]);
525       }
526 
527       /* insert dest row before prev */
528       gtk_list_store_insert_after (GTK_LIST_STORE (model),
529                                    &dest_iter, &next_iter);
530       for (i = 0; i < colnum; i++) {
531          gtk_list_store_set_value (GTK_LIST_STORE (model), &dest_iter,
532                                    i, &values[i]);
533          g_value_unset (&values[i]);
534       }
535       g_free (values);
536 
537       /* delete src */
538       gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
539 
540       /* select dest */
541       treepath = gtk_tree_model_get_path (model, &dest_iter);
542       gtk_tree_view_set_cursor (treeview, treepath, NULL, FALSE);
543 
544       /* clean */
545       gtk_tree_path_free (treepath);
546    }
547 #else /* (GTK_MAJOR_VERSION >= 2) */
548    {
549       gtk_clist_swap_rows (GTK_CLIST (editlist->clist), selected, selected + 1);
550       gtk_clist_moveto (GTK_CLIST (editlist->clist), selected + 1, 0, 0, 0);
551    }
552 #endif /* (GTK_MAJOR_VERSION >= 2) */
553 }
554 
555 
556 static void
cb_editlist_new_button(GtkButton * button,gpointer data)557 cb_editlist_new_button (GtkButton *button, gpointer data)
558 {
559    GimvEList *editlist = data;
560    GimvEListConfirmFlags flags;
561 
562    flags = gimv_elist_action_confirm (editlist, GIMV_ELIST_ACTION_RESET);
563    if (flags & GIMV_ELIST_CONFIRM_CANNOT_NEW) return;
564 
565    gimv_elist_unselect_all (editlist);
566    gimv_elist_edit_area_reset (editlist);
567    gimv_elist_set_sensitive (editlist);
568 }
569 
570 
571 static void
cb_editlist_add_button(GtkButton * button,gpointer data)572 cb_editlist_add_button (GtkButton *button, gpointer data)
573 {
574    GimvEList *editlist = data;
575    GimvEListConfirmFlags flags;
576    gint row;
577    gchar **text;
578    gpointer rowdata = NULL;
579    GtkDestroyNotify destroy_fn = NULL;
580    gboolean set_rowdata = FALSE;
581 
582    g_return_if_fail (GIMV_IS_ELIST (editlist));
583 
584    flags = gimv_elist_action_confirm (editlist, GIMV_ELIST_ACTION_ADD);
585    if (flags & GIMV_ELIST_CONFIRM_CANNOT_ADD) return;
586 
587    text = gimv_elist_edit_area_get_data (editlist, GIMV_ELIST_ACTION_ADD);
588    g_return_if_fail (text);
589 
590    row = gimv_elist_append_row (editlist, text);
591    g_strfreev (text);
592 
593    if (editlist->get_rowdata_fn)
594       set_rowdata = editlist->get_rowdata_fn (editlist,
595                                               GIMV_ELIST_ACTION_ADD,
596                                               &rowdata, &destroy_fn);
597    if (set_rowdata) {
598       gimv_elist_set_row_data_full (editlist, row, rowdata, destroy_fn);
599    }
600 
601    gimv_elist_updated (editlist);
602 
603    gimv_elist_edit_area_reset (editlist);
604    gimv_elist_set_sensitive (editlist);
605 }
606 
607 
608 static void
cb_editlist_change_button(GtkButton * button,gpointer data)609 cb_editlist_change_button (GtkButton *button, gpointer data)
610 {
611    GimvEList *editlist = data;
612    GimvEListConfirmFlags flags;
613    gchar **text;
614    gint i;
615    gpointer rowdata = NULL;
616    GtkDestroyNotify destroy_fn = NULL;
617    gboolean set_rowdata = FALSE;
618 
619    g_return_if_fail (GIMV_IS_ELIST (editlist));
620 
621    if (editlist->selected < 0 || editlist->selected >= editlist->rows) return;
622 
623    flags = gimv_elist_action_confirm (editlist, GIMV_ELIST_ACTION_CHANGE);
624    if (flags & GIMV_ELIST_CONFIRM_CANNOT_CHANGE) return;
625 
626    text = gimv_elist_edit_area_get_data (editlist,
627                                             GIMV_ELIST_ACTION_CHANGE);
628    g_return_if_fail (text);
629 
630 #ifdef ENABLE_TREEVIEW
631    {
632       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
633       GtkTreeModel *model;
634       GtkTreeSelection *selection;
635       GtkTreeIter iter;
636       gboolean success;
637 
638       selection = gtk_tree_view_get_selection (treeview);
639       success = gtk_tree_selection_get_selected (selection, &model, &iter);
640       if (!success) {
641          g_strfreev (text);
642          return;
643       }
644 
645       for (i = 0; i < editlist->columns; i++) {
646          gtk_list_store_set (GTK_LIST_STORE (model), &iter, i, text[i], -1);
647       }
648    }
649 #else /* ENABLE_TREEVIEW */
650    {
651       GtkCList *clist = GTK_CLIST (editlist->clist);
652 
653       for (i = 0; i < editlist->columns; i++) {
654          gtk_clist_set_text (clist, editlist->selected, i, text[i]);
655       }
656    }
657 #endif /* ENABLE_TREEVIEW */
658 
659    g_strfreev (text);
660 
661    if (editlist->get_rowdata_fn)
662       set_rowdata = editlist->get_rowdata_fn (editlist,
663                                               GIMV_ELIST_ACTION_CHANGE,
664                                               &rowdata, &destroy_fn);
665    if (set_rowdata) {
666       gimv_elist_set_row_data_full (editlist, editlist->selected,
667                                        rowdata, destroy_fn);
668    }
669 
670    gimv_elist_updated (editlist);
671 
672    editlist->edit_area_flags &= ~GIMV_ELIST_EDIT_AREA_VALUE_CHANGED;
673 
674    gimv_elist_set_sensitive (editlist);
675 }
676 
677 
678 static void
cb_editlist_delete_button(GtkButton * button,gpointer data)679 cb_editlist_delete_button (GtkButton *button, gpointer data)
680 {
681    GimvEList *editlist = data;
682    GimvEListConfirmFlags flags;
683 
684    g_return_if_fail (GIMV_IS_ELIST (editlist));
685    g_return_if_fail (editlist->selected >= 0);
686 
687    flags = gimv_elist_action_confirm (editlist, GIMV_ELIST_ACTION_DELETE);
688    if (flags & GIMV_ELIST_CONFIRM_CANNOT_DELETE) return;
689 
690    gimv_elist_remove_row (editlist, editlist->selected);
691 
692    gimv_elist_updated (editlist);
693 
694    gimv_elist_set_sensitive (editlist);
695 }
696 
697 
698 /*******************************************************************************
699  *
700  *  Private functions.
701  *
702  *******************************************************************************/
703 static void
gimv_elist_set_move_button_sensitive(GimvEList * editlist)704 gimv_elist_set_move_button_sensitive (GimvEList *editlist)
705 {
706    gint rownum = editlist->rows;
707    gint selected = editlist->selected;
708    gboolean reorderble = gimv_elist_get_reorderable (editlist);
709 
710    if (!reorderble || selected < 0) {
711       gtk_widget_set_sensitive (editlist->up_button, FALSE);
712       gtk_widget_set_sensitive (editlist->down_button, FALSE);
713 
714    } else {
715       /* up button */
716       if (selected == 0)
717          gtk_widget_set_sensitive (editlist->up_button, FALSE);
718       else
719          gtk_widget_set_sensitive (editlist->up_button, TRUE);
720 
721       /* down button */
722       if (selected < rownum - 1)
723          gtk_widget_set_sensitive (editlist->down_button, TRUE);
724       else
725          gtk_widget_set_sensitive (editlist->down_button, FALSE);
726    }
727 }
728 
729 
730 static void
gimv_elist_set_sensitive(GimvEList * editlist)731 gimv_elist_set_sensitive (GimvEList *editlist)
732 {
733    gimv_elist_set_move_button_sensitive (editlist);
734    gimv_elist_set_action_button_sensitive (editlist);
735 }
736 
737 
738 static GtkWidget *
gimv_elist_create_list_widget(GimvEList * editlist,gint colnum)739 gimv_elist_create_list_widget (GimvEList *editlist, gint colnum)
740 {
741    GtkWidget *clist;
742 
743 #if (GTK_MAJOR_VERSION >= 2)
744    GtkListStore *store;
745    GtkTreeViewColumn *col;
746    GtkCellRenderer *render;
747    GType *types;
748    gint i;
749 
750    store = gtk_list_store_new (1, G_TYPE_STRING); /* this column is dummy */
751 
752    /*
753     *  types[colnum] is row data
754     *  types[colnum+1] is GtkDestroyNotify
755     */
756    types = g_new0 (GType, ALL_COLUMNS(colnum));
757    for (i = 0; i < colnum; i++)
758       types[i] = G_TYPE_STRING;
759    types[ROWDATA(colnum)]    = G_TYPE_POINTER;
760    types[ROWDESTROY(colnum)] = G_TYPE_POINTER;
761    gtk_list_store_set_column_types (store, ALL_COLUMNS (colnum), types);
762    g_free (types);
763 
764    clist = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
765    editlist->clist = clist;
766    gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (clist), TRUE);
767    gtk_tree_view_set_reorderable (GTK_TREE_VIEW (clist), TRUE);
768 
769    g_signal_connect (G_OBJECT (store), "row_changed",
770                      G_CALLBACK (cb_editlist_row_changed),
771                      editlist);
772    g_signal_connect (G_OBJECT (store), "row_deleted",
773                      G_CALLBACK (cb_editlist_row_deleted),
774                      editlist);
775    g_signal_connect (G_OBJECT (clist),"cursor_changed",
776                      G_CALLBACK (cb_editlist_cursor_changed),
777                      editlist);
778 
779    /* set column */
780    for (i = 0; i < colnum; i++) {
781       col = gtk_tree_view_column_new();
782       gtk_tree_view_column_set_resizable (col, TRUE);
783       render = gtk_cell_renderer_text_new ();
784       gtk_tree_view_column_pack_start (col, render, TRUE);
785       gtk_tree_view_column_add_attribute (col, render, "text", i);
786       gtk_tree_view_append_column (GTK_TREE_VIEW (clist), col);
787    }
788 #else /* (GTK_MAJOR_VERSION >= 2) */
789    clist = editlist->clist = gtk_clist_new (colnum);
790    gtk_clist_set_selection_mode (GTK_CLIST (clist), GTK_SELECTION_SINGLE);
791    gtk_clist_set_reorderable (GTK_CLIST (clist), TRUE);
792    gtk_clist_set_use_drag_icons (GTK_CLIST (clist), FALSE);
793 
794    gtk_signal_connect (GTK_OBJECT (clist),"row_move",
795                        GTK_SIGNAL_FUNC (cb_editlist_row_move), editlist);
796    gtk_signal_connect (GTK_OBJECT (editlist->clist), "select_row",
797                        GTK_SIGNAL_FUNC (cb_editlist_select_row), editlist);
798    gtk_signal_connect (GTK_OBJECT (editlist->clist), "unselect_row",
799                        GTK_SIGNAL_FUNC (cb_editlist_unselect_row), editlist);
800 #endif /* (GTK_MAJOR_VERSION >= 2) */
801 
802    editlist->columns = colnum;
803 
804    return clist;
805 }
806 
807 
808 static GimvEListColumnFuncTable *
gimv_elist_column_func_table_new(void)809 gimv_elist_column_func_table_new (void)
810 {
811    GimvEListColumnFuncTable *table;
812    table = g_new0 (GimvEListColumnFuncTable, 1);
813    table->widget            = NULL;
814    table->coldata           = NULL;
815    table->destroy_fn        = NULL;
816    table->set_data_fn       = NULL;
817    table->get_data_fn       = NULL;
818    table->reset_fn          = NULL;
819 
820    return table;
821 }
822 
823 
824 static void
gimv_elist_edit_area_set_data(GimvEList * editlist,gint row)825 gimv_elist_edit_area_set_data (GimvEList *editlist, gint row)
826 {
827    gint i;
828 
829    g_return_if_fail (row < editlist->rows);
830 
831    gtk_signal_emit (GTK_OBJECT (editlist),
832                     gimv_elist_signals[EDIT_AREA_SET_DATA_SIGNAL]);
833 
834    for (i = 0; i < editlist->columns; i++) {
835       GimvEListColumnFuncTable *table = editlist->column_func_tables[i];
836       gchar *text = NULL;
837 
838       if (!table) continue;
839       if (!table->set_data_fn) continue;
840 
841       if (row >= 0) {
842 #if (GTK_MAJOR_VERSION >= 2)
843          GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
844          GtkTreeModel *model = gtk_tree_view_get_model (treeview);
845          GtkTreeIter iter;
846          gboolean success;
847 
848          success = gtk_tree_model_iter_nth_child (model, &iter, NULL, row);
849          if (success) {
850             gtk_tree_model_get (model, &iter, i, &text, -1);
851          }
852 #else /* (GTK_MAJOR_VERSION >= 2) */
853          gtk_clist_get_text (GTK_CLIST (editlist->clist), row, i, &text);
854          if (text) text = g_strdup (text);
855 #endif /* (GTK_MAJOR_VERSION >= 2) */
856       }
857 
858       table->set_data_fn (editlist, table->widget, row, i,
859                           text, table->coldata);
860 
861       g_free (text);
862    }
863 
864    editlist->edit_area_flags &= ~GIMV_ELIST_EDIT_AREA_VALUE_INITIALIZED;
865    editlist->edit_area_flags &= ~GIMV_ELIST_EDIT_AREA_VALUE_CHANGED;
866 
867    gimv_elist_set_sensitive (editlist);
868 }
869 
870 
871 static gchar **
gimv_elist_edit_area_get_data(GimvEList * editlist,GimvEListActionType type)872 gimv_elist_edit_area_get_data (GimvEList *editlist, GimvEListActionType type)
873 {
874    gint i;
875    gchar **text;
876 
877    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
878    g_return_val_if_fail (editlist->columns > 0, NULL);
879 
880    text = g_new0 (gchar *, editlist->columns + 1);
881 
882    for (i = 0; i < editlist->columns; i++) {
883       GimvEListColumnFuncTable *table = editlist->column_func_tables[i];
884 
885       text[i] = NULL;
886 
887       if (!table) {
888          g_warning ("GimvEList: function table for column %d is not found", i);
889          continue;
890       }
891       if (!table->get_data_fn) {
892          g_warning ("GimvEList: get_data_fn method for column %d is notimplemented", i);
893          continue;
894       }
895 
896       text[i] = table->get_data_fn (editlist, type, table->widget, table->coldata);
897    }
898    text[editlist->columns] = NULL;
899 
900    return text;
901 }
902 
903 
904 static void
gimv_elist_edit_area_reset(GimvEList * editlist)905 gimv_elist_edit_area_reset (GimvEList *editlist)
906 {
907    gint i;
908 
909    for (i = 0; i < editlist->columns; i++) {
910       GimvEListColumnFuncTable *table = editlist->column_func_tables[i];
911 
912       if (!table) continue;
913       if (!table->reset_fn) continue;
914 
915       table->reset_fn (editlist, table->widget, table->coldata);
916    }
917 
918    editlist->edit_area_flags |= GIMV_ELIST_EDIT_AREA_VALUE_INITIALIZED;
919    editlist->edit_area_flags &= ~GIMV_ELIST_EDIT_AREA_VALUE_CHANGED;
920 
921    gimv_elist_set_sensitive (editlist);
922 }
923 
924 
925 
926 /*******************************************************************************
927  *
928  *  Public functions.
929  *
930  *******************************************************************************/
931 GtkWidget *
gimv_elist_new(gint colnum)932 gimv_elist_new (gint colnum)
933 {
934    GimvEList *editlist;
935    GtkWidget *main_vbox;
936    GtkWidget *vbox, *vbox1, *hbox, *hbox1, *scrollwin;
937    GtkWidget *clist, *button, *arrow;
938    gint i;
939 
940    g_return_val_if_fail (colnum > 0, NULL);
941 
942 #if (GTK_MAJOR_VERSION >= 2)
943    editlist = g_object_new (gimv_elist_get_type (), NULL);
944 #else /* (GTK_MAJOR_VERSION >= 2) */
945    editlist = gtk_type_new (gimv_elist_get_type ());
946 #endif /* (GTK_MAJOR_VERSION >= 2) */
947    main_vbox = GTK_WIDGET (editlist);
948 
949    /* clist */
950    hbox = gtk_hbox_new (FALSE, 0);
951    gtk_container_set_border_width(GTK_CONTAINER (hbox), 0);
952    gtk_box_pack_start (GTK_BOX (main_vbox), hbox, TRUE, TRUE, 0);
953    gtk_widget_show (hbox);
954 
955    scrollwin = gtk_scrolled_window_new (NULL, NULL);
956    gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin),
957                                    GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
958 #ifdef USE_GTK2
959    gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollwin),
960                                        GTK_SHADOW_IN);
961 #endif /* USE_GTK2 */
962    gtk_container_set_border_width(GTK_CONTAINER (scrollwin), 5);
963    gtk_box_pack_start (GTK_BOX (hbox), scrollwin, TRUE, TRUE, 0);
964    gtk_widget_set_usize (scrollwin, -1, 120);
965    gtk_widget_show (scrollwin);
966 
967    clist = gimv_elist_create_list_widget (editlist, colnum);
968    gtk_container_add (GTK_CONTAINER (scrollwin), clist);
969    gtk_widget_show (clist);
970 
971 
972    /* move buttons */
973    vbox = editlist->move_button_area = gtk_vbox_new (TRUE, 0);
974    gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 2);
975    gtk_widget_show (vbox);
976 
977    vbox1 = gtk_vbox_new (TRUE, 0);
978    gtk_box_pack_start (GTK_BOX (vbox), vbox1, FALSE, FALSE, 2);
979    gtk_widget_show (vbox1);
980 
981    button = editlist->up_button = gtk_button_new ();
982 #ifdef USE_ARROW
983    arrow = gtk_arrow_new (GTK_ARROW_UP, GTK_SHADOW_NONE);
984 #else /* USE_ARROW */
985    arrow = gtk_label_new (_("Up"));
986    gtk_misc_set_alignment (GTK_MISC (arrow), 0.5, 0.5);
987 #endif /* USE_ARROW */
988    gtk_container_add (GTK_CONTAINER (button), arrow);
989    gtk_widget_show (arrow);
990    gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 2);
991    gtk_widget_show (button);
992 
993    button = editlist->down_button = gtk_button_new ();
994 #ifdef USE_ARROW
995    arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE);
996 #else /* USE_ARROW */
997    arrow = gtk_label_new (_("Down"));
998    gtk_misc_set_alignment (GTK_MISC (arrow), 0.5, 0.5);
999 #endif /* USE_ARROW */
1000    gtk_container_add (GTK_CONTAINER (button), arrow);
1001    gtk_widget_show (arrow);
1002    gtk_box_pack_start (GTK_BOX (vbox1), button, FALSE, FALSE, 2);
1003    gtk_widget_show (button);
1004 
1005 
1006    /* edit area */
1007    editlist->edit_area = gtk_hbox_new (FALSE, 0);
1008    gtk_container_set_border_width (GTK_CONTAINER (editlist->edit_area), 5);
1009    gtk_box_pack_start (GTK_BOX (main_vbox), editlist->edit_area,
1010                        FALSE, TRUE, 0);
1011    gtk_widget_show (editlist->edit_area);
1012 
1013 
1014    /* edit buttons */
1015    hbox = editlist->action_button_area = gtk_hbox_new (FALSE, 0);
1016    gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
1017    gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, TRUE, 0);
1018    gtk_widget_show (hbox);
1019 
1020    hbox1 = gtk_hbox_new (TRUE, 0);
1021    gtk_box_pack_end (GTK_BOX (hbox), hbox1, FALSE, TRUE, 0);
1022    gtk_widget_show (hbox1);
1023 
1024    button = editlist->new_button = gtk_button_new_with_label (_("New"));
1025    gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, TRUE, 2);
1026    gtk_widget_show (button);
1027 
1028    button = editlist->add_button = gtk_button_new_with_label (_("Add"));
1029    gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, TRUE, 2);
1030    gtk_widget_show (button);
1031 
1032    button = editlist->change_button = gtk_button_new_with_label (_("Change"));
1033    gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, TRUE, 2);
1034    gtk_widget_show (button);
1035 
1036    button = editlist->del_button = gtk_button_new_with_label (_("Delete"));
1037    gtk_box_pack_start (GTK_BOX (hbox1), button, FALSE, TRUE, 2);
1038    gtk_widget_show (button);
1039 
1040 
1041 #if (GTK_MAJOR_VERSION >= 2)
1042 
1043 #ifdef USE_ARROW
1044    gtk_widget_set_size_request (editlist->up_button, 20, 20);
1045    gtk_widget_set_size_request (editlist->down_button, 20, 20);
1046 #endif /* USE_ARROW */
1047    gtk_widget_set_size_request (editlist->new_button, 70, -1);
1048 
1049    g_signal_connect (G_OBJECT (editlist->up_button), "clicked",
1050                      G_CALLBACK (cb_editlist_up_button), editlist);
1051    g_signal_connect (G_OBJECT (editlist->down_button), "clicked",
1052                      G_CALLBACK (cb_editlist_down_button), editlist);
1053    g_signal_connect (G_OBJECT (editlist->new_button), "clicked",
1054                      G_CALLBACK (cb_editlist_new_button), editlist);
1055    g_signal_connect (G_OBJECT (editlist->add_button), "clicked",
1056                      G_CALLBACK (cb_editlist_add_button), editlist);
1057    g_signal_connect (G_OBJECT (editlist->change_button), "clicked",
1058                      G_CALLBACK (cb_editlist_change_button), editlist);
1059    g_signal_connect (G_OBJECT (editlist->del_button), "clicked",
1060                      G_CALLBACK (cb_editlist_delete_button), editlist);
1061 
1062 #else /* (GTK_MAJOR_VERSION >= 2) */
1063 
1064 #ifdef USE_ARROW
1065    gtk_widget_set_usize (editlist->up_button, 20, 20);
1066    gtk_widget_set_usize (editlist->down_button, 20, 20);
1067 #endif /* USE_ARROW */
1068    gtk_widget_set_usize (editlist->new_button, 70, -1);
1069 
1070    gtk_signal_connect (GTK_OBJECT (editlist->up_button), "clicked",
1071                        GTK_SIGNAL_FUNC (cb_editlist_up_button), editlist);
1072    gtk_signal_connect (GTK_OBJECT (editlist->down_button), "clicked",
1073                        GTK_SIGNAL_FUNC (cb_editlist_down_button), editlist);
1074    gtk_signal_connect (GTK_OBJECT (editlist->new_button), "clicked",
1075                        GTK_SIGNAL_FUNC (cb_editlist_new_button), editlist);
1076    gtk_signal_connect (GTK_OBJECT (editlist->add_button), "clicked",
1077                        GTK_SIGNAL_FUNC (cb_editlist_add_button), editlist);
1078    gtk_signal_connect (GTK_OBJECT (editlist->change_button), "clicked",
1079                        GTK_SIGNAL_FUNC (cb_editlist_change_button), editlist);
1080    gtk_signal_connect (GTK_OBJECT (editlist->del_button), "clicked",
1081                        GTK_SIGNAL_FUNC (cb_editlist_delete_button), editlist);
1082 
1083 #endif /* (GTK_MAJOR_VERSION >= 2) */
1084 
1085    /* initialize column func tables */
1086    editlist->column_func_tables
1087       = g_new0 (GimvEListColumnFuncTable *, editlist->columns);
1088    for (i = 0; i < colnum; i++) {
1089       editlist->column_func_tables[i]
1090          = gimv_elist_column_func_table_new ();
1091    }
1092 
1093    gimv_elist_set_sensitive (editlist);
1094 
1095    return main_vbox;
1096 }
1097 
1098 
1099 GtkWidget *
gimv_elist_new_with_titles(gint colnum,gchar * titles[])1100 gimv_elist_new_with_titles (gint colnum, gchar *titles[])
1101 {
1102    GimvEList *editlist;
1103    gint i;
1104 
1105    editlist = GIMV_ELIST (gimv_elist_new (colnum));
1106 
1107 #if (GTK_MAJOR_VERSION >= 2)
1108    {
1109       GList *list, *node;
1110       list = gtk_tree_view_get_columns (GTK_TREE_VIEW (editlist->clist));
1111       for (node = list, i = 0; node; node = g_list_next (node), i++) {
1112          GtkTreeViewColumn *col = node->data;
1113          gtk_tree_view_column_set_title (col, titles[i]);
1114       }
1115    }
1116    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (editlist->clist), TRUE);
1117 #else /* (GTK_MAJOR_VERSION >= 2) */
1118    for (i = 0; i < colnum; i++) {
1119       gtk_clist_set_column_title (GTK_CLIST (editlist->clist),
1120                                   i, titles[i]);
1121       gtk_clist_set_column_auto_resize (GTK_CLIST (editlist->clist),
1122                                         i, TRUE);
1123    }
1124    gtk_clist_column_titles_show (GTK_CLIST (editlist->clist));
1125 #endif /* (GTK_MAJOR_VERSION >= 2) */
1126 
1127    return GTK_WIDGET (editlist);
1128 }
1129 
1130 
1131 void
gimv_elist_set_column_title_visible(GimvEList * editlist,gboolean visible)1132 gimv_elist_set_column_title_visible (GimvEList *editlist, gboolean visible)
1133 {
1134    g_return_if_fail (GIMV_IS_ELIST (editlist));
1135 
1136 #if (GTK_MAJOR_VERSION >= 2)
1137    gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (editlist->clist), visible);
1138 #else /* (GTK_MAJOR_VERSION >= 2) */
1139    if (visible)
1140       gtk_clist_column_titles_show (GTK_CLIST (editlist->clist));
1141    else
1142       gtk_clist_column_titles_hide (GTK_CLIST (editlist->clist));
1143 #endif /* (GTK_MAJOR_VERSION >= 2) */
1144 }
1145 
1146 
1147 void
gimv_elist_set_reorderable(GimvEList * editlist,gboolean reorderble)1148 gimv_elist_set_reorderable (GimvEList *editlist, gboolean reorderble)
1149 {
1150    g_return_if_fail (GIMV_IS_ELIST (editlist));
1151 
1152 #if (GTK_MAJOR_VERSION >= 2)
1153    gtk_tree_view_set_reorderable (GTK_TREE_VIEW (editlist->clist), reorderble);
1154 #else /* (GTK_MAJOR_VERSION >= 2) */
1155    gtk_clist_set_reorderable (GTK_CLIST (editlist->clist), reorderble);
1156 #endif /* (GTK_MAJOR_VERSION >= 2) */
1157 
1158    if (reorderble)
1159       gtk_widget_show (editlist->move_button_area);
1160    else
1161       gtk_widget_hide (editlist->move_button_area);
1162 }
1163 
1164 
1165 void
gimv_elist_set_auto_sort(GimvEList * editlist,gint column)1166 gimv_elist_set_auto_sort (GimvEList *editlist, gint column)
1167 {
1168    g_return_if_fail (GIMV_IS_ELIST (editlist));
1169    g_return_if_fail (column < editlist->columns);
1170 
1171 #if (GTK_MAJOR_VERSION >= 2)
1172    {
1173       GList *list, *node;
1174       list = gtk_tree_view_get_columns (GTK_TREE_VIEW (editlist->clist));
1175 
1176       for (node = list; node; node = g_list_next (node)) {
1177          GtkTreeViewColumn *treecolumn = node->data;
1178          gtk_tree_view_column_set_reorderable (treecolumn, FALSE);
1179       }
1180 
1181       if (column >= 0) {
1182          GtkTreeViewColumn *treecolumn;
1183          node = g_list_nth (list, column);
1184          treecolumn = node->data;
1185          gtk_tree_view_column_set_reorderable (treecolumn, TRUE);
1186          gtk_tree_view_column_set_sort_column_id (treecolumn, column);
1187          gtk_tree_view_column_set_sort_order (treecolumn, GTK_SORT_ASCENDING);
1188       }
1189 
1190       g_list_free (list);
1191    }
1192 #else /* (GTK_MAJOR_VERSION >= 2) */
1193    if (column < 0)
1194       gtk_clist_set_auto_sort (GTK_CLIST (editlist->clist), FALSE);
1195    else
1196       gtk_clist_set_auto_sort (GTK_CLIST (editlist->clist), TRUE);
1197 
1198    gtk_clist_set_sort_column (GTK_CLIST (editlist->clist), column);
1199 #endif /* (GTK_MAJOR_VERSION >= 2) */
1200 }
1201 
1202 
1203 gboolean
gimv_elist_get_reorderable(GimvEList * editlist)1204 gimv_elist_get_reorderable (GimvEList *editlist)
1205 {
1206    g_return_val_if_fail (GIMV_IS_ELIST (editlist), FALSE);
1207 
1208 #if (GTK_MAJOR_VERSION >= 2)
1209    return gtk_tree_view_get_reorderable (GTK_TREE_VIEW (editlist->clist));
1210 #else /* (GTK_MAJOR_VERSION >= 2) */
1211    return GTK_CLIST_REORDERABLE (GTK_CLIST (editlist->clist));
1212 #endif /* (GTK_MAJOR_VERSION >= 2) */
1213 }
1214 
1215 
1216 gint
gimv_elist_append_row(GimvEList * editlist,gchar * data[])1217 gimv_elist_append_row (GimvEList *editlist, gchar *data[])
1218 {
1219    gint retval;
1220 
1221    g_return_val_if_fail (GIMV_IS_ELIST (editlist), -1);
1222    g_return_val_if_fail (editlist->max_row < 0
1223                          || editlist->rows <= editlist->max_row, -1);
1224 
1225 #if (GTK_MAJOR_VERSION >= 2)
1226 
1227    {
1228       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
1229       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
1230       GtkListStore *store = GTK_LIST_STORE (model);
1231       GtkTreeIter iter;
1232       gint i;
1233 
1234       gtk_list_store_append (store, &iter);
1235 
1236       for (i = 0; i < editlist->columns; i++) {
1237          gtk_list_store_set (store, &iter, i, data[i], -1);
1238       }
1239    }
1240    editlist->rows = list_widget_get_row_num(editlist->clist);
1241    retval = editlist->rows - 1;
1242 
1243 #else /* (GTK_MAJOR_VERSION >= 2) */
1244 
1245    retval = gtk_clist_append (GTK_CLIST (editlist->clist), data);
1246    editlist->rows = list_widget_get_row_num(editlist->clist);
1247 
1248 #endif /* (GTK_MAJOR_VERSION >= 2) */
1249 
1250    gimv_elist_set_sensitive (editlist);
1251 
1252    return retval;
1253 }
1254 
1255 
1256 void
gimv_elist_remove_row(GimvEList * editlist,gint row)1257 gimv_elist_remove_row (GimvEList *editlist, gint row)
1258 {
1259    g_return_if_fail (GIMV_IS_ELIST (editlist));
1260    g_return_if_fail (row >= 0 && row < editlist->rows);
1261 
1262    gimv_elist_set_row_data (editlist, row, NULL);
1263 
1264 #if (GTK_MAJOR_VERSION >= 2)
1265    {
1266       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
1267       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
1268       GtkListStore *store = GTK_LIST_STORE (model);
1269       GtkTreeIter iter;
1270       gboolean success;
1271 
1272       success = gtk_tree_model_iter_nth_child (model, &iter, NULL, row);
1273       if (success) {
1274          gtk_list_store_remove (store, &iter);
1275          editlist->selected = -1;
1276       }
1277    }
1278 #else /* (GTK_MAJOR_VERSION >= 2) */
1279    gtk_clist_remove (GTK_CLIST (editlist->clist), row);
1280 #endif /* (GTK_MAJOR_VERSION >= 2) */
1281 
1282    editlist->rows = list_widget_get_row_num(editlist->clist);
1283 
1284    gimv_elist_updated (editlist);
1285    gimv_elist_set_sensitive (editlist);
1286 }
1287 
1288 
1289 gint
gimv_elist_get_n_rows(GimvEList * editlist)1290 gimv_elist_get_n_rows (GimvEList *editlist)
1291 {
1292    g_return_val_if_fail (GIMV_IS_ELIST (editlist), -1);
1293 
1294    return editlist->rows;
1295 }
1296 
1297 
1298 gint
gimv_elist_get_selected_row(GimvEList * editlist)1299 gimv_elist_get_selected_row (GimvEList *editlist)
1300 {
1301    g_return_val_if_fail (GIMV_IS_ELIST (editlist), -1);
1302 
1303    return editlist->selected;
1304 }
1305 
1306 
1307 gchar **
gimv_elist_get_row_text(GimvEList * editlist,gint row)1308 gimv_elist_get_row_text (GimvEList *editlist, gint row)
1309 {
1310    gchar **text;
1311    gint i;
1312 
1313    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
1314    g_return_val_if_fail (row >= 0 &&  row < editlist->rows, NULL);
1315    g_return_val_if_fail (editlist->columns > 0, NULL);
1316 
1317    text = g_new0 (gchar *, editlist->columns + 1);
1318 
1319 #if (GTK_MAJOR_VERSION >= 2)
1320 
1321    {
1322       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
1323       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
1324       GtkTreeIter iter;
1325       gboolean success;
1326 
1327       success = gtk_tree_model_iter_nth_child (model, &iter, NULL, row);
1328       g_return_val_if_fail (success, NULL);
1329 
1330       for (i = 0; i < editlist->columns; i++) {
1331          text[i] = NULL;
1332          gtk_tree_model_get (model, &iter, i, &text[i], -1);
1333          if (!text[i])
1334             text[i] = g_strdup ("");
1335       }
1336    }
1337 
1338 #else /* (GTK_MAJOR_VERSION >= 2) */
1339 
1340    for (i = 0; i < editlist->columns; i++) {
1341       text[i] = NULL;
1342       gtk_clist_get_text (GTK_CLIST (editlist->clist), row, i, &text[i]);
1343       if (text[i])
1344          text[i] = g_strdup (text[i]);
1345       else
1346          text[i] = g_strdup ("");
1347    }
1348 
1349 #endif /* (GTK_MAJOR_VERSION >= 2) */
1350 
1351    text[editlist->columns] = NULL;
1352 
1353    return text;
1354 }
1355 
1356 
1357 gchar *
gimv_elist_get_cell_text(GimvEList * editlist,gint row,gint col)1358 gimv_elist_get_cell_text (GimvEList *editlist, gint row, gint col)
1359 {
1360    gchar *text = NULL;
1361 
1362    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
1363    g_return_val_if_fail (row >= 0 &&  row < editlist->rows, NULL);
1364    g_return_val_if_fail (editlist->columns > 0, NULL);
1365    g_return_val_if_fail (col < editlist->columns, NULL);
1366 
1367 #if (GTK_MAJOR_VERSION >= 2)
1368 
1369    {
1370       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
1371       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
1372       GtkTreeIter iter;
1373       gboolean success;
1374 
1375       success = gtk_tree_model_iter_nth_child (model, &iter, NULL, row);
1376       g_return_val_if_fail (success, NULL);
1377 
1378       gtk_tree_model_get (model, &iter, col, &text, -1);
1379    }
1380 
1381 #else /* (GTK_MAJOR_VERSION >= 2) */
1382 
1383    {
1384       gboolean success;
1385       success = gtk_clist_get_text (GTK_CLIST (editlist->clist),
1386                                     row, col, &text);
1387       if (!success) return NULL;
1388       text = g_strdup (text);
1389    }
1390 
1391 #endif /* (GTK_MAJOR_VERSION >= 2) */
1392 
1393    return text;
1394 }
1395 
1396 
1397 void
gimv_elist_set_row_data(GimvEList * editlist,gint row,gpointer data)1398 gimv_elist_set_row_data (GimvEList *editlist,
1399                          gint          row,
1400                          gpointer      data)
1401 {
1402    g_return_if_fail (GIMV_IS_ELIST (editlist));
1403    g_return_if_fail (row >= 0 &&  row < editlist->rows);
1404 
1405    gimv_elist_set_row_data_full (editlist, row, data, NULL);
1406 }
1407 
1408 
1409 void
gimv_elist_set_row_data_full(GimvEList * editlist,gint row,gpointer data,GtkDestroyNotify destroy_fn)1410 gimv_elist_set_row_data_full (GimvEList *editlist,
1411                               gint          row,
1412                               gpointer      data,
1413                               GtkDestroyNotify destroy_fn)
1414 {
1415    g_return_if_fail (GIMV_IS_ELIST (editlist));
1416    g_return_if_fail (row >= 0 &&  row < editlist->rows);
1417 
1418 #if (GTK_MAJOR_VERSION >= 2)
1419    {
1420       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
1421       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
1422       GtkTreeIter iter;
1423       GtkDestroyNotify destroy;
1424       gboolean success;
1425       gpointer rowdata = gimv_elist_get_row_data (editlist, row);
1426 
1427       if (rowdata) {
1428          destroy = g_hash_table_lookup (editlist->rowdata_destroy_fn_table,
1429                                         rowdata);
1430          if (destroy) {
1431             destroy (rowdata);
1432             g_hash_table_remove (editlist->rowdata_destroy_fn_table, rowdata);
1433          }
1434 
1435          g_hash_table_remove (editlist->rowdata_table, rowdata);
1436       }
1437 
1438       success = gtk_tree_model_iter_nth_child (model, &iter, NULL, row);
1439       g_return_if_fail (success);
1440 
1441       gtk_list_store_set (GTK_LIST_STORE (model), &iter,
1442                           ROWDATA(editlist->columns),    data,
1443                           ROWDESTROY(editlist->columns), destroy_fn,
1444                           -1);
1445 
1446       if (data) {
1447          g_hash_table_insert (editlist->rowdata_table,
1448                               data, data);
1449          g_hash_table_insert (editlist->rowdata_destroy_fn_table,
1450                               data, destroy_fn);
1451       }
1452    }
1453 #else /* (GTK_MAJOR_VERSION >= 2) */
1454    gtk_clist_set_row_data_full (GTK_CLIST (editlist->clist), row,
1455                                 data, destroy_fn);
1456 #endif /* (GTK_MAJOR_VERSION >= 2) */
1457 
1458    gimv_elist_updated (editlist);
1459 }
1460 
1461 
1462 gpointer
gimv_elist_get_row_data(GimvEList * editlist,gint row)1463 gimv_elist_get_row_data (GimvEList *editlist,
1464                             gint          row)
1465 {
1466    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
1467    g_return_val_if_fail (row >= 0 &&  row < editlist->rows, NULL);
1468 
1469 #if (GTK_MAJOR_VERSION >= 2)
1470    {
1471       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
1472       GtkTreeModel *model = gtk_tree_view_get_model (treeview);
1473       GtkTreeIter iter;
1474       gboolean success;
1475       gpointer data;
1476 
1477       success = gtk_tree_model_iter_nth_child (model, &iter, NULL, row);
1478       if (!success) return NULL;
1479 
1480       gtk_tree_model_get (model, &iter,
1481                           ROWDATA (editlist->columns), &data, -1);
1482 
1483       return data;
1484    }
1485 #else /* (GTK_MAJOR_VERSION >= 2) */
1486    return gtk_clist_get_row_data (GTK_CLIST (editlist->clist), row);
1487 #endif /* (GTK_MAJOR_VERSION >= 2) */
1488 }
1489 
1490 
1491 void
gimv_elist_unselect_all(GimvEList * editlist)1492 gimv_elist_unselect_all (GimvEList *editlist)
1493 {
1494    g_return_if_fail (GIMV_IS_ELIST (editlist));
1495 
1496 #if (GTK_MAJOR_VERSION >= 2)
1497    {
1498       GtkTreeView *treeview = GTK_TREE_VIEW (editlist->clist);
1499       GtkTreeSelection *selection = gtk_tree_view_get_selection (treeview);
1500 
1501       gtk_tree_selection_unselect_all (selection);
1502       editlist->selected = -1;
1503    }
1504 #else /* (GTK_MAJOR_VERSION >= 2) */
1505    gtk_clist_unselect_all (GTK_CLIST (editlist->clist));
1506 #endif /* (GTK_MAJOR_VERSION >= 2) */
1507 
1508    gimv_elist_set_sensitive (editlist);
1509 }
1510 
1511 
1512 void
gimv_elist_set_max_row(GimvEList * editlist,gint rownum)1513 gimv_elist_set_max_row (GimvEList *editlist, gint rownum)
1514 {
1515    g_return_if_fail (GIMV_IS_ELIST (editlist));
1516 
1517    editlist->max_row = rownum;
1518 }
1519 
1520 
1521 void
gimv_elist_set_column_funcs(GimvEList * editlist,GtkWidget * widget,gint column,GimvEListSetDataFn set_data_fn,GimvEListGetDataFn get_data_fn,GimvEListResetFn reset_fn,gpointer coldata,GtkDestroyNotify destroy_fn)1522 gimv_elist_set_column_funcs (GimvEList *editlist,
1523                              GtkWidget *widget,
1524                              gint column,
1525                              GimvEListSetDataFn set_data_fn,
1526                              GimvEListGetDataFn get_data_fn,
1527                              GimvEListResetFn   reset_fn,
1528                              gpointer coldata,
1529                              GtkDestroyNotify destroy_fn)
1530 {
1531    GimvEListColumnFuncTable *table;
1532 
1533    g_return_if_fail (GIMV_IS_ELIST (editlist));
1534    g_return_if_fail (column >= 0 && column < editlist->columns);
1535 
1536    table = editlist->column_func_tables[column];
1537 
1538    table->widget      = widget;
1539    table->coldata     = coldata;
1540    table->destroy_fn  = destroy_fn;
1541 
1542    table->set_data_fn = set_data_fn;
1543    table->get_data_fn = get_data_fn;
1544    table->reset_fn    = reset_fn;
1545 }
1546 
1547 
1548 void
gimv_elist_set_get_row_data_func(GimvEList * editlist,GimvEListGetRowDataFn get_rowdata_func)1549 gimv_elist_set_get_row_data_func (GimvEList *editlist,
1550                                      GimvEListGetRowDataFn get_rowdata_func)
1551 {
1552    g_return_if_fail (GIMV_IS_ELIST (editlist));
1553 
1554    editlist->get_rowdata_fn = get_rowdata_func;
1555 }
1556 
1557 
1558 void
gimv_elist_edit_area_set_value_changed(GimvEList * editlist)1559 gimv_elist_edit_area_set_value_changed (GimvEList *editlist)
1560 {
1561    g_return_if_fail (GIMV_IS_ELIST (editlist));
1562 
1563    editlist->edit_area_flags &= ~GIMV_ELIST_EDIT_AREA_VALUE_INITIALIZED;
1564    editlist->edit_area_flags |= GIMV_ELIST_EDIT_AREA_VALUE_CHANGED;
1565 
1566    gimv_elist_set_sensitive (editlist);
1567 }
1568 
1569 
1570 GimvEListConfirmFlags
gimv_elist_action_confirm(GimvEList * editlist,GimvEListActionType type)1571 gimv_elist_action_confirm (GimvEList *editlist,
1572                            GimvEListActionType type)
1573 {
1574    GimvEListConfirmFlags retval = 0;
1575 
1576    g_return_val_if_fail (GIMV_IS_ELIST (editlist), retval);
1577 
1578    if (editlist->edit_area_flags & GIMV_ELIST_EDIT_AREA_VALUE_INITIALIZED)
1579       retval |= GIMV_ELIST_CONFIRM_CANNOT_NEW;
1580 
1581    if (editlist->max_row >= 0 && editlist->rows >= editlist->max_row)
1582       retval |= GIMV_ELIST_CONFIRM_CANNOT_ADD;
1583 
1584    if (!(editlist->edit_area_flags & GIMV_ELIST_EDIT_AREA_VALUE_CHANGED))
1585       retval |= GIMV_ELIST_CONFIRM_CANNOT_CHANGE;
1586 
1587    if (editlist->selected < 0 || editlist->selected >= editlist->rows) {
1588       retval |= GIMV_ELIST_CONFIRM_CANNOT_CHANGE;
1589       retval |= GIMV_ELIST_CONFIRM_CANNOT_DELETE;
1590    }
1591 
1592    gtk_signal_emit (GTK_OBJECT (editlist),
1593                     gimv_elist_signals[ACTION_CONFIRM_SIGNAL],
1594                     type,
1595                     editlist->selected,
1596                     &retval);
1597 
1598    return retval;
1599 }
1600 
1601 
1602 void
gimv_elist_set_action_button_sensitive(GimvEList * editlist)1603 gimv_elist_set_action_button_sensitive (GimvEList *editlist)
1604 {
1605    GimvEListConfirmFlags flags;
1606 
1607    g_return_if_fail (GIMV_IS_ELIST (editlist));
1608 
1609    flags = gimv_elist_action_confirm (editlist,
1610                                          GIMV_ELIST_ACTION_SET_SENSITIVE);
1611 
1612    gtk_widget_set_sensitive (editlist->new_button,
1613                              !(flags & GIMV_ELIST_CONFIRM_CANNOT_NEW));
1614    gtk_widget_set_sensitive (editlist->add_button,
1615                              !(flags & GIMV_ELIST_CONFIRM_CANNOT_ADD));
1616    gtk_widget_set_sensitive (editlist->change_button,
1617                              !(flags & GIMV_ELIST_CONFIRM_CANNOT_CHANGE));
1618    gtk_widget_set_sensitive (editlist->del_button,
1619                              !(flags & GIMV_ELIST_CONFIRM_CANNOT_DELETE));
1620 }
1621 
1622 
1623 
1624 /*******************************************************************************
1625  *
1626  *  convenient function to create entry.
1627  *
1628  *******************************************************************************/
1629 typedef struct GimvEListEntryData_Tag
1630 {
1631    GimvEList *editlist;
1632    GtkWidget    *entry;
1633    gchar        *init_string;
1634    gboolean      allow_empty;
1635 } GimvEListEntryData;
1636 
1637 
1638 static void
cb_editlist_entry_set_data(GimvEList * editlist,GtkWidget * widget,gint row,gint col,const gchar * text,gpointer coldata)1639 cb_editlist_entry_set_data (GimvEList *editlist, GtkWidget *widget,
1640                             gint row, gint col,
1641                             const gchar *text, gpointer coldata)
1642 {
1643    GimvEListEntryData *entry_data = coldata;
1644 
1645    g_return_if_fail (GIMV_IS_ELIST (editlist));
1646    g_return_if_fail (GTK_IS_ENTRY (widget));
1647    g_return_if_fail (entry_data);
1648 
1649    if (text)
1650       gtk_entry_set_text (GTK_ENTRY (widget), text);
1651 }
1652 
1653 
1654 static gchar *
cb_editlist_entry_get_data(GimvEList * editlist,GimvEListActionType type,GtkWidget * widget,gpointer coldata)1655 cb_editlist_entry_get_data (GimvEList *editlist,
1656                             GimvEListActionType type,
1657                             GtkWidget *widget,
1658                             gpointer coldata)
1659 {
1660    GimvEListEntryData *entry_data = coldata;
1661    const gchar *text;
1662 
1663    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
1664    g_return_val_if_fail (GTK_IS_ENTRY (widget), NULL);
1665    g_return_val_if_fail (entry_data, NULL);
1666 
1667    text = gtk_entry_get_text (GTK_ENTRY (widget));
1668 
1669    if (text)
1670       return g_strdup (text);
1671    else
1672       return NULL;
1673 }
1674 
1675 
1676 static void
cb_editlist_entry_reset(GimvEList * editlist,GtkWidget * widget,gpointer coldata)1677 cb_editlist_entry_reset (GimvEList *editlist,
1678                          GtkWidget *widget,
1679                          gpointer coldata)
1680 {
1681    GimvEListEntryData *entry_data = coldata;
1682 
1683    g_return_if_fail (GIMV_IS_ELIST (editlist));
1684    g_return_if_fail (GTK_IS_ENTRY (widget));
1685    g_return_if_fail (entry_data);
1686 
1687    gtk_entry_set_text (GTK_ENTRY (widget), entry_data->init_string);
1688 }
1689 
1690 
1691 static void
cb_editlist_entry_changed(GtkEntry * entry,gpointer data)1692 cb_editlist_entry_changed (GtkEntry *entry, gpointer data)
1693 {
1694    GimvEListEntryData *entry_data = data;
1695    GimvEList *editlist;
1696    const gchar *text;
1697 
1698    g_return_if_fail (entry_data);
1699    g_return_if_fail (GIMV_IS_ELIST (entry_data->editlist));
1700 
1701    editlist = entry_data->editlist;
1702 
1703    text = gtk_entry_get_text (entry);
1704 
1705    gimv_elist_edit_area_set_value_changed (editlist);
1706 }
1707 
1708 
1709 static void
editlist_entry_destroy(gpointer data)1710 editlist_entry_destroy (gpointer data)
1711 {
1712    GimvEListEntryData *entry_data = data;
1713 
1714    g_free (entry_data->init_string);
1715    g_free (entry_data);
1716 }
1717 
1718 
1719 static void
cb_editlist_entry_confirm(GimvEList * editlist,GimvEListActionType type,gint selected_row,GimvEListConfirmFlags * flags,gpointer data)1720 cb_editlist_entry_confirm (GimvEList *editlist,
1721                            GimvEListActionType type,
1722                            gint selected_row,
1723                            GimvEListConfirmFlags *flags,
1724                            gpointer data)
1725 {
1726    GimvEListEntryData *entry_data = data;
1727    const gchar *text;
1728 
1729    text = gtk_entry_get_text (GTK_ENTRY (entry_data->entry));
1730    if (!entry_data->allow_empty && (!text || !*text)) {
1731       *flags |= GIMV_ELIST_CONFIRM_CANNOT_ADD;
1732       *flags |= GIMV_ELIST_CONFIRM_CANNOT_CHANGE;
1733    }
1734 
1735    return;
1736 }
1737 
1738 
1739 GtkWidget *
gimv_elist_create_entry(GimvEList * editlist,gint column,const gchar * init_string,gboolean allow_empty)1740 gimv_elist_create_entry (GimvEList *editlist, gint column,
1741                          const gchar *init_string,
1742                          gboolean allow_empty)
1743 {
1744    GimvEListEntryData *entry_data;
1745    GtkWidget *entry;
1746 
1747    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
1748    g_return_val_if_fail (column >= 0 && column < editlist->columns, NULL);
1749 
1750    entry_data = g_new0 (GimvEListEntryData, 1);
1751    entry_data->editlist = editlist;
1752    if (!init_string || !*init_string)
1753       entry_data->init_string = g_strdup ("\0");
1754    else
1755       entry_data->init_string = g_strdup (init_string);
1756    entry_data->allow_empty = allow_empty;
1757 
1758    entry_data->entry = entry = gtk_entry_new ();
1759 
1760    gtk_entry_set_text (GTK_ENTRY (entry_data->entry), entry_data->init_string);
1761 
1762    gimv_elist_set_column_funcs (editlist,
1763                                 entry, column,
1764                                 cb_editlist_entry_set_data,
1765                                 cb_editlist_entry_get_data,
1766                                 cb_editlist_entry_reset,
1767                                 entry_data,
1768                                 editlist_entry_destroy);
1769 
1770 #if (GTK_MAJOR_VERSION >= 2)
1771    g_signal_connect (G_OBJECT (editlist), "action_confirm",
1772                      G_CALLBACK (cb_editlist_entry_confirm),
1773                      entry_data);
1774    g_signal_connect (G_OBJECT (entry),"changed",
1775                      G_CALLBACK (cb_editlist_entry_changed),
1776                      entry_data);
1777 #else /* (GTK_MAJOR_VERSION >= 2) */
1778    gtk_signal_connect (GTK_OBJECT (editlist), "action_confirm",
1779                        GTK_SIGNAL_FUNC (cb_editlist_entry_confirm),
1780                        entry_data);
1781    gtk_signal_connect (GTK_OBJECT (entry),"changed",
1782                        GTK_SIGNAL_FUNC (cb_editlist_entry_changed),
1783                        entry_data);
1784 #endif /* (GTK_MAJOR_VERSION >= 2) */
1785 
1786    gimv_elist_set_sensitive (editlist);
1787 
1788    return entry;
1789 }
1790 
1791 
1792 
1793 /*******************************************************************************
1794  *
1795  *  convenient function to create check button.
1796  *
1797  *******************************************************************************/
1798 typedef struct GimvEListCheckButtonData_Tag
1799 {
1800    GimvEList *editlist;
1801    gboolean   init_value;
1802    gchar     *true_string;
1803    gchar     *false_string;
1804 } GimvEListCheckButtonData;
1805 
1806 static void
cb_editlist_check_button_set_data(GimvEList * editlist,GtkWidget * widget,gint row,gint col,const gchar * text,gpointer coldata)1807 cb_editlist_check_button_set_data (GimvEList *editlist, GtkWidget *widget,
1808                                    gint row, gint col,
1809                                    const gchar *text, gpointer coldata)
1810 {
1811    GimvEListCheckButtonData *button_data = coldata;
1812 
1813    g_return_if_fail (GIMV_IS_ELIST (editlist));
1814    g_return_if_fail (GTK_IS_CHECK_BUTTON (widget));
1815    g_return_if_fail (button_data);
1816 
1817    if (row < 0) return;
1818 
1819    if (text && *text && !strcmp (text, button_data->true_string)) {
1820       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
1821    } else {
1822       gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), FALSE);
1823    }
1824 }
1825 
1826 
1827 static gchar *
cb_editlist_check_button_get_data(GimvEList * editlist,GimvEListActionType type,GtkWidget * widget,gpointer coldata)1828 cb_editlist_check_button_get_data (GimvEList *editlist,
1829                                    GimvEListActionType type,
1830                                    GtkWidget *widget,
1831                                    gpointer coldata)
1832 {
1833    GimvEListCheckButtonData *button_data = coldata;
1834 
1835    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
1836    g_return_val_if_fail (GTK_IS_CHECK_BUTTON (widget), NULL);
1837    g_return_val_if_fail (button_data, NULL);
1838 
1839    if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
1840       return g_strdup (button_data->true_string);
1841    else
1842       return g_strdup (button_data->false_string);
1843 }
1844 
1845 
1846 static void
cb_editlist_check_button_reset(GimvEList * editlist,GtkWidget * widget,gpointer coldata)1847 cb_editlist_check_button_reset (GimvEList *editlist,
1848                                 GtkWidget *widget,
1849                                 gpointer coldata)
1850 {
1851    GimvEListCheckButtonData *button_data = coldata;
1852 
1853    g_return_if_fail (GIMV_IS_ELIST (editlist));
1854    g_return_if_fail (GTK_IS_CHECK_BUTTON (widget));
1855 
1856    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
1857                                  button_data->init_value);
1858 }
1859 
1860 
1861 static void
cb_editlist_check_button_toggled(GtkCheckButton * check_button,gpointer data)1862 cb_editlist_check_button_toggled (GtkCheckButton *check_button, gpointer data)
1863 {
1864    GimvEListCheckButtonData *button_data = data;
1865    gimv_elist_edit_area_set_value_changed (button_data->editlist);
1866 }
1867 
1868 
1869 static void
editlist_check_button_destroy(gpointer data)1870 editlist_check_button_destroy (gpointer data)
1871 {
1872    GimvEListCheckButtonData *button_data = data;
1873 
1874    g_free (button_data->true_string);
1875    g_free (button_data->false_string);
1876    g_free (button_data);
1877 }
1878 
1879 
1880 GtkWidget *
gimv_elist_create_check_button(GimvEList * editlist,gint column,const gchar * label,gboolean init_value,const gchar * true_string,const gchar * false_string)1881 gimv_elist_create_check_button (GimvEList *editlist, gint column,
1882                                 const gchar *label,
1883                                 gboolean init_value,
1884                                 const gchar *true_string,
1885                                 const gchar *false_string)
1886 {
1887    GimvEListCheckButtonData *button_data;
1888    GtkWidget *check_button;
1889 
1890    g_return_val_if_fail (GIMV_IS_ELIST (editlist), NULL);
1891    g_return_val_if_fail (column >= 0 && column < editlist->columns, NULL);
1892    g_return_val_if_fail (true_string && *true_string, NULL);
1893    g_return_val_if_fail (false_string && *false_string, NULL);
1894 
1895    button_data = g_new0 (GimvEListCheckButtonData, 1);
1896    button_data->editlist     = editlist;
1897    button_data->init_value   = init_value;
1898    button_data->true_string  = g_strdup (true_string);
1899    button_data->false_string = g_strdup (false_string);
1900 
1901    if (label)
1902       check_button = gtk_check_button_new_with_label (label);
1903    else
1904       check_button = gtk_check_button_new ();
1905 
1906    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button),
1907                                  button_data->init_value);
1908 
1909    gimv_elist_set_column_funcs (GIMV_ELIST (editlist),
1910                                    check_button, column,
1911                                    cb_editlist_check_button_set_data,
1912                                    cb_editlist_check_button_get_data,
1913                                    cb_editlist_check_button_reset,
1914                                    button_data,
1915                                    editlist_check_button_destroy);
1916 
1917 #if (GTK_MAJOR_VERSION >= 2)
1918    g_signal_connect (G_OBJECT (check_button),"toggled",
1919                      G_CALLBACK (cb_editlist_check_button_toggled),
1920                      button_data);
1921 #else /* (GTK_MAJOR_VERSION >= 2) */
1922    gtk_signal_connect (GTK_OBJECT (check_button),"toggled",
1923                        GTK_SIGNAL_FUNC (cb_editlist_check_button_toggled),
1924                        button_data);
1925 #endif /* (GTK_MAJOR_VERSION >= 2) */
1926 
1927    gimv_elist_set_sensitive (editlist);
1928 
1929    return check_button;
1930 }
1931