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