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