]> Pileus Git - ~andy/gtk/blob - tests/testtreecolumns.c
Fixes #136082 and #135265, patch by Morten Welinder.
[~andy/gtk] / tests / testtreecolumns.c
1 #include <config.h>
2 #include <gtk/gtk.h>
3
4 /*
5  * README README README README README README README README README README
6  * README README README README README README README README README README
7  * README README README README README README README README README README
8  * README README README README README README README README README README
9  * README README README README README README README README README README
10  * README README README README README README README README README README
11  * README README README README README README README README README README
12  * README README README README README README README README README README
13  * README README README README README README README README README README
14  * README README README README README README README README README README
15  * README README README README README README README README README README
16  * README README README README README README README README README README
17  * README README README README README README README README README README
18  *
19  * DO NOT!!! I REPEAT DO NOT!  EVER LOOK AT THIS CODE AS AN EXAMPLE OF WHAT YOUR
20  * CODE SHOULD LOOK LIKE.
21  *
22  * IT IS VERY CONFUSING, AND IS MEANT TO TEST A LOT OF CODE IN THE TREE.  WHILE
23  * IT IS ACTUALLY CORRECT CODE, IT IS NOT USEFUL.
24  */
25
26 GtkWidget *left_tree_view;
27 GtkWidget *top_right_tree_view;
28 GtkWidget *bottom_right_tree_view;
29 GtkTreeModel *left_tree_model;
30 GtkTreeModel *top_right_tree_model;
31 GtkTreeModel *bottom_right_tree_model;
32 GtkWidget *sample_tree_view_top;
33 GtkWidget *sample_tree_view_bottom;
34
35 #define column_data "my_column_data"
36
37 static void move_row  (GtkTreeModel *src,
38                        GtkTreeIter  *src_iter,
39                        GtkTreeModel *dest,
40                        GtkTreeIter  *dest_iter);
41
42 /* Kids, don't try this at home.  */
43
44 /* Small GtkTreeModel to model columns */
45 typedef struct _ViewColumnModel ViewColumnModel;
46 typedef struct _ViewColumnModelClass ViewColumnModelClass;
47
48 struct _ViewColumnModel
49 {
50   GObject parent;
51   GtkTreeView *view;
52   GList *columns;
53   gint stamp;
54 };
55
56 struct _ViewColumnModelClass
57 {
58   GObjectClass parent_class;
59 };
60
61 static void view_column_model_init (ViewColumnModel *model)
62 {
63   model->stamp = g_random_int ();
64 }
65
66 static gint
67 view_column_model_get_n_columns (GtkTreeModel *tree_model)
68 {
69   return 2;
70 }
71
72 static GType
73 view_column_model_get_column_type (GtkTreeModel *tree_model,
74                                    gint          index)
75 {
76   switch (index)
77     {
78     case 0:
79       return G_TYPE_STRING;
80     case 1:
81       return GTK_TYPE_TREE_VIEW_COLUMN;
82     default:
83       return G_TYPE_INVALID;
84     }
85 }
86
87 static gboolean
88 view_column_model_get_iter (GtkTreeModel *tree_model,
89                             GtkTreeIter  *iter,
90                             GtkTreePath  *path)
91
92 {
93   ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
94   GList *list;
95   gint i;
96
97   g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
98
99   i = gtk_tree_path_get_indices (path)[0];
100   list = g_list_nth (view_model->columns, i);
101
102   if (list == NULL)
103     return FALSE;
104
105   iter->stamp = view_model->stamp;
106   iter->user_data = list;
107
108   return TRUE;
109 }
110
111 static GtkTreePath *
112 view_column_model_get_path (GtkTreeModel *tree_model,
113                             GtkTreeIter  *iter)
114 {
115   ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
116   GtkTreePath *retval;
117   GList *list;
118   gint i = 0;
119
120   g_return_val_if_fail (iter->stamp == view_model->stamp, NULL);
121
122   for (list = view_model->columns; list; list = list->next)
123     {
124       if (list == (GList *)iter->user_data)
125         break;
126       i++;
127     }
128   if (list == NULL)
129     return NULL;
130
131   retval = gtk_tree_path_new ();
132   gtk_tree_path_append_index (retval, i);
133   return retval;
134 }
135
136 static void
137 view_column_model_get_value (GtkTreeModel *tree_model,
138                              GtkTreeIter  *iter,
139                              gint          column,
140                              GValue       *value)
141 {
142   ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
143
144   g_return_if_fail (column < 2);
145   g_return_if_fail (view_model->stamp == iter->stamp);
146   g_return_if_fail (iter->user_data != NULL);
147
148   if (column == 0)
149     {
150       g_value_init (value, G_TYPE_STRING);
151       g_value_set_string (value, gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (((GList *)iter->user_data)->data)));
152     }
153   else
154     {
155       g_value_init (value, GTK_TYPE_TREE_VIEW_COLUMN);
156       g_value_set_object (value, ((GList *)iter->user_data)->data);
157     }
158 }
159
160 static gboolean
161 view_column_model_iter_next (GtkTreeModel  *tree_model,
162                              GtkTreeIter   *iter)
163 {
164   ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
165
166   g_return_val_if_fail (view_model->stamp == iter->stamp, FALSE);
167   g_return_val_if_fail (iter->user_data != NULL, FALSE);
168
169   iter->user_data = ((GList *)iter->user_data)->next;
170   return iter->user_data != NULL;
171 }
172
173 static gboolean
174 view_column_model_iter_children (GtkTreeModel *tree_model,
175                                  GtkTreeIter  *iter,
176                                  GtkTreeIter  *parent)
177 {
178   ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
179
180   /* this is a list, nodes have no children */
181   if (parent)
182     return FALSE;
183
184   /* but if parent == NULL we return the list itself as children of the
185    * "root"
186    */
187
188   if (view_model->columns)
189     {
190       iter->stamp = view_model->stamp;
191       iter->user_data = view_model->columns;
192       return TRUE;
193     }
194   else
195     return FALSE;
196 }
197
198 static gboolean
199 view_column_model_iter_has_child (GtkTreeModel *tree_model,
200                                   GtkTreeIter  *iter)
201 {
202   return FALSE;
203 }
204
205 static gint
206 view_column_model_iter_n_children (GtkTreeModel *tree_model,
207                                    GtkTreeIter  *iter)
208 {
209   return g_list_length (((ViewColumnModel *)tree_model)->columns);
210 }
211
212 static gint
213 view_column_model_iter_nth_child (GtkTreeModel *tree_model,
214                                   GtkTreeIter  *iter,
215                                   GtkTreeIter  *parent,
216                                   gint          n)
217 {
218   ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
219
220   if (parent)
221     return FALSE;
222
223   iter->stamp = view_model->stamp;
224   iter->user_data = g_list_nth ((GList *)view_model->columns, n);
225
226   return (iter->user_data != NULL);
227 }
228
229 static gboolean
230 view_column_model_iter_parent (GtkTreeModel *tree_model,
231                                GtkTreeIter  *iter,
232                                GtkTreeIter  *child)
233 {
234   return FALSE;
235 }
236
237 static void
238 view_column_model_tree_model_init (GtkTreeModelIface *iface)
239 {
240   iface->get_n_columns = view_column_model_get_n_columns;
241   iface->get_column_type = view_column_model_get_column_type;
242   iface->get_iter = view_column_model_get_iter;
243   iface->get_path = view_column_model_get_path;
244   iface->get_value = view_column_model_get_value;
245   iface->iter_next = view_column_model_iter_next;
246   iface->iter_children = view_column_model_iter_children;
247   iface->iter_has_child = view_column_model_iter_has_child;
248   iface->iter_n_children = view_column_model_iter_n_children;
249   iface->iter_nth_child = view_column_model_iter_nth_child;
250   iface->iter_parent = view_column_model_iter_parent;
251 }
252
253 static gboolean
254 view_column_model_drag_data_get (GtkTreeDragSource   *drag_source,
255                                  GtkTreePath         *path,
256                                  GtkSelectionData    *selection_data)
257 {
258   if (gtk_tree_set_row_drag_data (selection_data,
259                                   GTK_TREE_MODEL (drag_source),
260                                   path))
261     return TRUE;
262   else
263     return FALSE;
264 }
265
266 static gboolean
267 view_column_model_drag_data_delete (GtkTreeDragSource *drag_source,
268                                     GtkTreePath       *path)
269 {
270   /* Nothing -- we handle moves on the dest side */
271   
272   return TRUE;
273 }
274
275 static gboolean
276 view_column_model_row_drop_possible (GtkTreeDragDest   *drag_dest,
277                                      GtkTreePath       *dest_path,
278                                      GtkSelectionData  *selection_data)
279 {
280   GtkTreeModel *src_model;
281   
282   if (gtk_tree_get_row_drag_data (selection_data,
283                                   &src_model,
284                                   NULL))
285     {
286       if (src_model == left_tree_model ||
287           src_model == top_right_tree_model ||
288           src_model == bottom_right_tree_model)
289         return TRUE;
290     }
291
292   return FALSE;
293 }
294
295 static gboolean
296 view_column_model_drag_data_received (GtkTreeDragDest   *drag_dest,
297                                       GtkTreePath       *dest,
298                                       GtkSelectionData  *selection_data)
299 {
300   GtkTreeModel *src_model;
301   GtkTreePath *src_path = NULL;
302   gboolean retval = FALSE;
303   
304   if (gtk_tree_get_row_drag_data (selection_data,
305                                   &src_model,
306                                   &src_path))
307     {
308       GtkTreeIter src_iter;
309       GtkTreeIter dest_iter;
310       gboolean have_dest;
311
312       /* We are a little lazy here, and assume if we can't convert dest
313        * to an iter, we need to append. See gtkliststore.c for a more
314        * careful handling of this.
315        */
316       have_dest = gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest), &dest_iter, dest);
317
318       if (gtk_tree_model_get_iter (src_model, &src_iter, src_path))
319         {
320           if (src_model == left_tree_model ||
321               src_model == top_right_tree_model ||
322               src_model == bottom_right_tree_model)
323             {
324               move_row (src_model, &src_iter, GTK_TREE_MODEL (drag_dest),
325                         have_dest ? &dest_iter : NULL);
326               retval = TRUE;
327             }
328         }
329
330       gtk_tree_path_free (src_path);
331     }
332   
333   return retval;
334 }
335
336 static void
337 view_column_model_drag_source_init (GtkTreeDragSourceIface *iface)
338 {
339   iface->drag_data_get = view_column_model_drag_data_get;
340   iface->drag_data_delete = view_column_model_drag_data_delete;
341 }
342
343 static void
344 view_column_model_drag_dest_init (GtkTreeDragDestIface *iface)
345 {
346   iface->drag_data_received = view_column_model_drag_data_received;
347   iface->row_drop_possible = view_column_model_row_drop_possible;
348 }
349
350 GType
351 view_column_model_get_type (void)
352 {
353   static GType view_column_model_type = 0;
354
355   if (!view_column_model_type)
356     {
357       static const GTypeInfo view_column_model_info =
358       {
359         sizeof (GtkListStoreClass),
360         NULL,           /* base_init */
361         NULL,           /* base_finalize */
362         NULL,           /* class_init */
363         NULL,           /* class_finalize */
364         NULL,           /* class_data */
365         sizeof (GtkListStore),
366         0,
367         (GInstanceInitFunc) view_column_model_init,
368       };
369
370       static const GInterfaceInfo tree_model_info =
371       {
372         (GInterfaceInitFunc) view_column_model_tree_model_init,
373         NULL,
374         NULL
375       };
376
377       static const GInterfaceInfo drag_source_info =
378       {
379         (GInterfaceInitFunc) view_column_model_drag_source_init,
380         NULL,
381         NULL
382       };
383
384       static const GInterfaceInfo drag_dest_info =
385       {
386         (GInterfaceInitFunc) view_column_model_drag_dest_init,
387         NULL,
388         NULL
389       };
390
391       view_column_model_type = g_type_register_static (G_TYPE_OBJECT, "ViewModelColumn", &view_column_model_info, 0);
392       g_type_add_interface_static (view_column_model_type,
393                                    GTK_TYPE_TREE_MODEL,
394                                    &tree_model_info);
395       g_type_add_interface_static (view_column_model_type,
396                                    GTK_TYPE_TREE_DRAG_SOURCE,
397                                    &drag_source_info);
398       g_type_add_interface_static (view_column_model_type,
399                                    GTK_TYPE_TREE_DRAG_DEST,
400                                    &drag_dest_info);
401     }
402
403   return view_column_model_type;
404 }
405
406 static void
407 update_columns (GtkTreeView *view, ViewColumnModel *view_model)
408 {
409   GList *old_columns = view_model->columns;
410   gint old_length, length;
411   GList *a, *b;
412
413   view_model->columns = gtk_tree_view_get_columns (view_model->view);
414
415   /* As the view tells us one change at a time, we can do this hack. */
416   length = g_list_length (view_model->columns);
417   old_length = g_list_length (old_columns);
418   if (length != old_length)
419     {
420       GtkTreePath *path;
421       gint i = 0;
422
423       /* where are they different */
424       for (a = old_columns, b = view_model->columns; a && b; a = a->next, b = b->next)
425         {
426           if (a->data != b->data)
427             break;
428           i++;
429         }
430       path = gtk_tree_path_new ();
431       gtk_tree_path_append_index (path, i);
432       if (length < old_length)
433         {
434           view_model->stamp++;
435           gtk_tree_model_row_deleted (GTK_TREE_MODEL (view_model), path);
436         }
437       else
438         {
439           GtkTreeIter iter;
440           iter.stamp = view_model->stamp;
441           iter.user_data = b;
442           gtk_tree_model_row_inserted (GTK_TREE_MODEL (view_model), path, &iter);
443         }
444       gtk_tree_path_free (path);
445     }
446   else
447     {
448       gint i;
449       gint m = 0, n = 1;
450       gint *new_order;
451       GtkTreePath *path;
452
453       new_order = g_new (int, length);
454       a = old_columns; b = view_model->columns;
455
456       while (a->data == b->data)
457         {
458           a = a->next;
459           b = b->next;
460           if (a == NULL)
461             return;
462           m++;
463         }
464
465       if (a->next->data == b->data)
466         {
467           b = b->next;
468           while (b->data != a->data)
469             {
470               b = b->next;
471               n++;
472             }
473           for (i = 0; i < m; i++)
474             new_order[i] = i;
475           for (i = m; i < m+n; i++)
476             new_order[i] = i+1;
477           new_order[i] = m;
478           for (i = m + n +1; i < length; i++)
479             new_order[i] = i;
480         }
481       else
482         {
483           a = a->next;
484           while (a->data != b->data)
485             {
486               a = a->next;
487               n++;
488             }
489           for (i = 0; i < m; i++)
490             new_order[i] = i;
491           new_order[m] = m+n;
492           for (i = m+1; i < m + n+ 1; i++)
493             new_order[i] = i - 1;
494           for (i = m + n + 1; i < length; i++)
495             new_order[i] = i;
496         }
497
498       path = gtk_tree_path_new ();
499       gtk_tree_model_rows_reordered (GTK_TREE_MODEL (view_model),
500                                      path,
501                                      NULL,
502                                      new_order);
503       gtk_tree_path_free (path);
504       g_free (new_order);
505     }
506   if (old_columns)
507     g_list_free (old_columns);
508 }
509
510 static GtkTreeModel *
511 view_column_model_new (GtkTreeView *view)
512 {
513   GtkTreeModel *retval;
514
515   retval = GTK_TREE_MODEL (g_object_new (view_column_model_get_type (), NULL));
516   ((ViewColumnModel *)retval)->view = view;
517   ((ViewColumnModel *)retval)->columns = gtk_tree_view_get_columns (view);
518
519   g_signal_connect (view, "columns_changed", G_CALLBACK (update_columns), retval);
520
521   return retval;
522 }
523
524 /* Back to sanity.
525  */
526
527 static void
528 add_clicked (GtkWidget *button, gpointer data)
529 {
530   static gint i = 0;
531
532   GtkTreeIter iter;
533   GtkTreeViewColumn *column;
534   GtkTreeSelection *selection;
535   GtkCellRenderer *cell;
536   gchar *label = g_strdup_printf ("Column %d", i);
537
538   cell = gtk_cell_renderer_text_new ();
539   column = gtk_tree_view_column_new_with_attributes (label, cell, "text", 0, NULL);
540   g_object_set_data_full (G_OBJECT (column), column_data, label, g_free);
541   gtk_tree_view_column_set_reorderable (column, TRUE);
542   gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
543   gtk_tree_view_column_set_resizable (column, TRUE);
544   gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
545   gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
546   i++;
547
548   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
549   gtk_tree_selection_select_iter (selection, &iter);
550 }
551
552 static void
553 get_visible (GtkTreeViewColumn *tree_column,
554              GtkCellRenderer   *cell,
555              GtkTreeModel      *tree_model,
556              GtkTreeIter       *iter,
557              gpointer           data)
558 {
559   GtkTreeViewColumn *column;
560
561   gtk_tree_model_get (tree_model, iter, 1, &column, -1);
562   if (column)
563     {
564       gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (cell),
565                                            gtk_tree_view_column_get_visible (column));
566     }
567 }
568
569 static void
570 set_visible (GtkCellRendererToggle *cell,
571              gchar                 *path_str,
572              gpointer               data)
573 {
574   GtkTreeView *tree_view = (GtkTreeView *) data;
575   GtkTreeViewColumn *column;
576   GtkTreeModel *model;
577   GtkTreeIter iter;
578   GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
579
580   model = gtk_tree_view_get_model (tree_view);
581
582   gtk_tree_model_get_iter (model, &iter, path);
583   gtk_tree_model_get (model, &iter, 1, &column, -1);
584
585   if (column)
586     {
587       gtk_tree_view_column_set_visible (column, ! gtk_tree_view_column_get_visible (column));
588       gtk_tree_model_row_changed (model, path, &iter);
589     }
590   gtk_tree_path_free (path);
591 }
592
593 static void
594 move_to_left (GtkTreeModel *src,
595               GtkTreeIter  *src_iter,
596               GtkTreeIter  *dest_iter)
597 {
598   GtkTreeIter iter;
599   GtkTreeViewColumn *column;
600   GtkTreeSelection *selection;
601   gchar *label;
602
603   gtk_tree_model_get (src, src_iter, 0, &label, 1, &column, -1);
604
605   if (src == top_right_tree_model)
606     gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_top), column);
607   else
608     gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
609
610   /*  gtk_list_store_remove (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data))), &iter);*/
611
612   /* Put it back on the left */
613   if (dest_iter)
614     gtk_list_store_insert_before (GTK_LIST_STORE (left_tree_model),
615                                   &iter, dest_iter);
616   else
617     gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
618   
619   gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
620   selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
621   gtk_tree_selection_select_iter (selection, &iter);
622
623   g_free (label);
624 }
625
626 static void
627 move_to_right (GtkTreeIter  *src_iter,
628                GtkTreeModel *dest,
629                GtkTreeIter  *dest_iter)
630 {
631   gchar *label;
632   GtkTreeViewColumn *column;
633   gint before = -1;
634
635   gtk_tree_model_get (GTK_TREE_MODEL (left_tree_model),
636                       src_iter, 0, &label, 1, &column, -1);
637   gtk_list_store_remove (GTK_LIST_STORE (left_tree_model), src_iter);
638
639   if (dest_iter)
640     {
641       GtkTreePath *path = gtk_tree_model_get_path (dest, dest_iter);
642       before = (gtk_tree_path_get_indices (path))[0];
643       gtk_tree_path_free (path);
644     }
645   
646   if (dest == top_right_tree_model)
647     gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_top), column, before);
648   else
649     gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_bottom), column, before);
650
651   g_free (label);
652 }
653
654 static void
655 move_up_or_down (GtkTreeModel *src,
656                  GtkTreeIter  *src_iter,
657                  GtkTreeModel *dest,
658                  GtkTreeIter  *dest_iter)
659 {
660   GtkTreeViewColumn *column;
661   gchar *label;
662   gint before = -1;
663   
664   gtk_tree_model_get (src, src_iter, 0, &label, 1, &column, -1);
665
666   if (dest_iter)
667     {
668       GtkTreePath *path = gtk_tree_model_get_path (dest, dest_iter);
669       before = (gtk_tree_path_get_indices (path))[0];
670       gtk_tree_path_free (path);
671     }
672   
673   if (src == top_right_tree_model)
674     gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_top), column);
675   else
676     gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
677
678   if (dest == top_right_tree_model)
679     gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_top), column, before);
680   else
681     gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_bottom), column, before);
682
683   g_free (label);
684 }
685
686 static void
687 move_row  (GtkTreeModel *src,
688            GtkTreeIter  *src_iter,
689            GtkTreeModel *dest,
690            GtkTreeIter  *dest_iter)
691 {
692   if (src == left_tree_model)
693     move_to_right (src_iter, dest, dest_iter);
694   else if (dest == left_tree_model)
695     move_to_left (src, src_iter, dest_iter);
696   else 
697     move_up_or_down (src, src_iter, dest, dest_iter);
698 }
699
700 static void
701 add_left_clicked (GtkWidget *button,
702                   gpointer data)
703 {
704   GtkTreeIter iter;
705
706   GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data));
707
708   gtk_tree_selection_get_selected (selection, NULL, &iter);
709
710   move_to_left (gtk_tree_view_get_model (GTK_TREE_VIEW (data)), &iter, NULL);
711 }
712
713 static void
714 add_right_clicked (GtkWidget *button, gpointer data)
715 {
716   GtkTreeIter iter;
717
718   GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
719
720   gtk_tree_selection_get_selected (selection, NULL, &iter);
721
722   move_to_right (&iter, gtk_tree_view_get_model (GTK_TREE_VIEW (data)), NULL);
723 }
724
725 static void
726 selection_changed (GtkTreeSelection *selection, GtkWidget *button)
727 {
728   if (gtk_tree_selection_get_selected (selection, NULL, NULL))
729     gtk_widget_set_sensitive (button, TRUE);
730   else
731     gtk_widget_set_sensitive (button, FALSE);
732 }
733
734 static GtkTargetEntry row_targets[] = {
735   { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, 0}
736 };
737
738 int
739 main (int argc, char *argv[])
740 {
741   GtkWidget *window;
742   GtkWidget *hbox, *vbox;
743   GtkWidget *vbox2, *bbox;
744   GtkWidget *button;
745   GtkTreeViewColumn *column;
746   GtkCellRenderer *cell;
747   GtkWidget *swindow;
748   GtkTreeModel *sample_model;
749   gint i;
750
751   gtk_init (&argc, &argv);
752
753   /* First initialize all the models for signal purposes */
754   left_tree_model = (GtkTreeModel *) gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
755   sample_model = (GtkTreeModel *) gtk_list_store_new (1, G_TYPE_STRING);
756   sample_tree_view_top = gtk_tree_view_new_with_model (sample_model);
757   sample_tree_view_bottom = gtk_tree_view_new_with_model (sample_model);
758   top_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_top));
759   bottom_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_bottom));
760   top_right_tree_view = gtk_tree_view_new_with_model (top_right_tree_model);
761   bottom_right_tree_view = gtk_tree_view_new_with_model (bottom_right_tree_model);
762
763   for (i = 0; i < 10; i++)
764     {
765       GtkTreeIter iter;
766       gchar *string = g_strdup_printf ("%d", i);
767       gtk_list_store_append (GTK_LIST_STORE (sample_model), &iter);
768       gtk_list_store_set (GTK_LIST_STORE (sample_model), &iter, 0, string, -1);
769       g_free (string);
770     }
771
772   /* Set up the test windows. */
773   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
774   g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); 
775   gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
776   gtk_window_set_title (GTK_WINDOW (window), "Top Window");
777   swindow = gtk_scrolled_window_new (NULL, NULL);
778   gtk_container_add (GTK_CONTAINER (window), swindow);
779   gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_top);
780   gtk_widget_show_all (window);
781
782   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
783   g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); 
784   gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
785   gtk_window_set_title (GTK_WINDOW (window), "Bottom Window");
786   swindow = gtk_scrolled_window_new (NULL, NULL);
787   gtk_container_add (GTK_CONTAINER (window), swindow);
788   gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_bottom);
789   gtk_widget_show_all (window);
790
791   /* Set up the main window */
792   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
793   g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); 
794   gtk_window_set_default_size (GTK_WINDOW (window), 500, 300);
795   vbox = gtk_vbox_new (FALSE, 8);
796   gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
797   gtk_container_add (GTK_CONTAINER (window), vbox);
798
799   hbox = gtk_hbox_new (FALSE, 8);
800   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
801
802   /* Left Pane */
803   cell = gtk_cell_renderer_text_new ();
804
805   swindow = gtk_scrolled_window_new (NULL, NULL);
806   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
807   left_tree_view = gtk_tree_view_new_with_model (left_tree_model);
808   gtk_container_add (GTK_CONTAINER (swindow), left_tree_view);
809   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (left_tree_view), -1,
810                                                "Unattached Columns", cell, "text", 0, NULL);
811   cell = gtk_cell_renderer_toggle_new ();
812   g_signal_connect (cell, "toggled", G_CALLBACK (set_visible), left_tree_view);
813   column = gtk_tree_view_column_new_with_attributes ("Visible", cell, NULL);
814   gtk_tree_view_append_column (GTK_TREE_VIEW (left_tree_view), column);
815
816   gtk_tree_view_column_set_cell_data_func (column, cell, get_visible, NULL, NULL);
817   gtk_box_pack_start (GTK_BOX (hbox), swindow, TRUE, TRUE, 0);
818
819   /* Middle Pane */
820   vbox2 = gtk_vbox_new (FALSE, 8);
821   gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
822   
823   bbox = gtk_vbutton_box_new ();
824   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
825   gtk_box_pack_start (GTK_BOX (vbox2), bbox, TRUE, TRUE, 0);
826
827   button = gtk_button_new_with_mnemonic ("<< (_Q)");
828   gtk_widget_set_sensitive (button, FALSE);
829   g_signal_connect (button, "clicked", G_CALLBACK (add_left_clicked), top_right_tree_view);
830   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (top_right_tree_view)),
831                     "changed", G_CALLBACK (selection_changed), button);
832   gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
833
834   button = gtk_button_new_with_mnemonic (">> (_W)");
835   gtk_widget_set_sensitive (button, FALSE);
836   g_signal_connect (button, "clicked", G_CALLBACK (add_right_clicked), top_right_tree_view);
837   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view)),
838                     "changed", G_CALLBACK (selection_changed), button);
839   gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
840
841   bbox = gtk_vbutton_box_new ();
842   gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
843   gtk_box_pack_start (GTK_BOX (vbox2), bbox, TRUE, TRUE, 0);
844
845   button = gtk_button_new_with_mnemonic ("<< (_E)");
846   gtk_widget_set_sensitive (button, FALSE);
847   g_signal_connect (button, "clicked", G_CALLBACK (add_left_clicked), bottom_right_tree_view);
848   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (bottom_right_tree_view)),
849                     "changed", G_CALLBACK (selection_changed), button);
850   gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
851
852   button = gtk_button_new_with_mnemonic (">> (_R)");
853   gtk_widget_set_sensitive (button, FALSE);
854   g_signal_connect (button, "clicked", G_CALLBACK (add_right_clicked), bottom_right_tree_view);
855   g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view)),
856                     "changed", G_CALLBACK (selection_changed), button);
857   gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
858
859   
860   /* Right Pane */
861   vbox2 = gtk_vbox_new (FALSE, 8);
862   gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
863
864   swindow = gtk_scrolled_window_new (NULL, NULL);
865   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
866   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (top_right_tree_view), FALSE);
867   cell = gtk_cell_renderer_text_new ();
868   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (top_right_tree_view), -1,
869                                                NULL, cell, "text", 0, NULL);
870   cell = gtk_cell_renderer_toggle_new ();
871   g_signal_connect (cell, "toggled", G_CALLBACK (set_visible), top_right_tree_view);
872   column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
873   gtk_tree_view_column_set_cell_data_func (column, cell, get_visible, NULL, NULL);
874   gtk_tree_view_append_column (GTK_TREE_VIEW (top_right_tree_view), column);
875
876   gtk_container_add (GTK_CONTAINER (swindow), top_right_tree_view);
877   gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
878
879   swindow = gtk_scrolled_window_new (NULL, NULL);
880   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
881   gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (bottom_right_tree_view), FALSE);
882   cell = gtk_cell_renderer_text_new ();
883   gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (bottom_right_tree_view), -1,
884                                                NULL, cell, "text", 0, NULL);
885   cell = gtk_cell_renderer_toggle_new ();
886   g_signal_connect (cell, "toggled", G_CALLBACK (set_visible), bottom_right_tree_view);
887   column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
888   gtk_tree_view_column_set_cell_data_func (column, cell, get_visible, NULL, NULL);
889   gtk_tree_view_append_column (GTK_TREE_VIEW (bottom_right_tree_view), column);
890   gtk_container_add (GTK_CONTAINER (swindow), bottom_right_tree_view);
891   gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
892
893   
894   /* Drag and Drop */
895   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (left_tree_view),
896                                           GDK_BUTTON1_MASK,
897                                           row_targets,
898                                           G_N_ELEMENTS (row_targets),
899                                           GDK_ACTION_MOVE);
900   gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (left_tree_view),
901                                         row_targets,
902                                         G_N_ELEMENTS (row_targets),
903                                         GDK_ACTION_MOVE);
904
905   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (top_right_tree_view),
906                                           GDK_BUTTON1_MASK,
907                                           row_targets,
908                                           G_N_ELEMENTS (row_targets),
909                                           GDK_ACTION_MOVE);
910   gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (top_right_tree_view),
911                                         row_targets,
912                                         G_N_ELEMENTS (row_targets),
913                                         GDK_ACTION_MOVE);
914
915   gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (bottom_right_tree_view),
916                                           GDK_BUTTON1_MASK,
917                                           row_targets,
918                                           G_N_ELEMENTS (row_targets),
919                                           GDK_ACTION_MOVE);
920   gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (bottom_right_tree_view),
921                                         row_targets,
922                                         G_N_ELEMENTS (row_targets),
923                                         GDK_ACTION_MOVE);
924
925
926   gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0);
927
928   hbox = gtk_hbox_new (FALSE, 8);
929   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
930   button = gtk_button_new_with_mnemonic ("_Add new Column");
931   g_signal_connect (button, "clicked", G_CALLBACK (add_clicked), left_tree_model);
932   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
933
934   gtk_widget_show_all (window);
935   gtk_main ();
936
937   return 0;
938 }