4 GtkWidget *left_tree_view;
5 GtkWidget *top_right_tree_view;
6 GtkWidget *bottom_right_tree_view;
7 GtkTreeModel *left_tree_model;
8 GtkTreeModel *top_right_tree_model;
9 GtkTreeModel *bottom_right_tree_model;
10 GtkWidget *sample_tree_view_top;
11 GtkWidget *sample_tree_view_bottom;
13 #define column_data "my_column_data"
17 /* Kids, don't try this at home.
20 /* Small GtkTreeModel to model columns */
21 typedef struct _ViewColumnModel ViewColumnModel;
22 typedef struct _ViewColumnModelClass ViewColumnModelClass;
24 struct _ViewColumnModel
32 struct _ViewColumnModelClass
34 GObjectClass parent_class;
37 static void view_column_model_class_init (ViewColumnModelClass *model)
41 static void view_column_model_init (ViewColumnModel *model)
43 model->stamp = g_random_int ();
47 view_column_model_get_n_columns (GtkTreeModel *tree_model)
53 view_column_model_get_column_type (GtkTreeModel *tree_model,
61 return GTK_TYPE_TREE_VIEW_COLUMN;
63 return G_TYPE_INVALID;
68 view_column_model_get_iter (GtkTreeModel *tree_model,
73 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
77 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
79 i = gtk_tree_path_get_indices (path)[0];
80 list = g_list_nth (view_model->columns, i);
85 iter->stamp = view_model->stamp;
86 iter->user_data = list;
92 view_column_model_get_path (GtkTreeModel *tree_model,
95 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
100 g_return_val_if_fail (iter->stamp == view_model->stamp, NULL);
102 for (list = view_model->columns; list; list = list->next)
104 if (list == (GList *)iter->user_data)
111 retval = gtk_tree_path_new ();
112 gtk_tree_path_append_index (retval, i);
117 view_column_model_get_value (GtkTreeModel *tree_model,
122 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
124 g_return_if_fail (column < 2);
125 g_return_if_fail (view_model->stamp == iter->stamp);
126 g_return_if_fail (iter->user_data != NULL);
130 g_value_init (value, G_TYPE_STRING);
131 g_value_set_string (value, gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (((GList *)iter->user_data)->data)));
135 g_value_init (value, GTK_TYPE_TREE_VIEW_COLUMN);
136 g_value_set_object (value, ((GList *)iter->user_data)->data);
141 view_column_model_iter_next (GtkTreeModel *tree_model,
144 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
146 g_return_val_if_fail (view_model->stamp == iter->stamp, FALSE);
147 g_return_val_if_fail (iter->user_data != NULL, FALSE);
149 iter->user_data = ((GList *)iter->user_data)->next;
150 return iter->user_data != NULL;
154 view_column_model_iter_children (GtkTreeModel *tree_model,
158 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
160 /* this is a list, nodes have no children */
164 /* but if parent == NULL we return the list itself as children of the
168 if (view_model->columns)
170 iter->stamp = view_model->stamp;
171 iter->user_data = view_model->columns;
179 view_column_model_iter_has_child (GtkTreeModel *tree_model,
186 view_column_model_iter_n_children (GtkTreeModel *tree_model,
189 return g_list_length (((ViewColumnModel *)tree_model)->columns);
193 view_column_model_iter_nth_child (GtkTreeModel *tree_model,
198 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
203 iter->stamp = view_model->stamp;
204 iter->user_data = g_list_nth ((GList *)view_model->columns, n);
206 return (iter->user_data != NULL);
210 view_column_model_iter_parent (GtkTreeModel *tree_model,
218 view_column_model_tree_model_init (GtkTreeModelIface *iface)
220 iface->get_n_columns = view_column_model_get_n_columns;
221 iface->get_column_type = view_column_model_get_column_type;
222 iface->get_iter = view_column_model_get_iter;
223 iface->get_path = view_column_model_get_path;
224 iface->get_value = view_column_model_get_value;
225 iface->iter_next = view_column_model_iter_next;
226 iface->iter_children = view_column_model_iter_children;
227 iface->iter_has_child = view_column_model_iter_has_child;
228 iface->iter_n_children = view_column_model_iter_n_children;
229 iface->iter_nth_child = view_column_model_iter_nth_child;
230 iface->iter_parent = view_column_model_iter_parent;
235 view_column_model_get_type (void)
237 static GType view_column_model_type = 0;
239 if (!view_column_model_type)
241 static const GTypeInfo view_column_model_info =
243 sizeof (GtkListStoreClass),
244 NULL, /* base_init */
245 NULL, /* base_finalize */
246 (GClassInitFunc) view_column_model_class_init,
247 NULL, /* class_finalize */
248 NULL, /* class_data */
249 sizeof (GtkListStore),
251 (GInstanceInitFunc) view_column_model_init,
254 static const GInterfaceInfo tree_model_info =
256 (GInterfaceInitFunc) view_column_model_tree_model_init,
261 view_column_model_type = g_type_register_static (G_TYPE_OBJECT, "ViewModelColumn", &view_column_model_info, 0);
262 g_type_add_interface_static (view_column_model_type,
267 return view_column_model_type;
271 update_columns (GtkTreeView *view, ViewColumnModel *view_model)
273 GList *old_columns = view_model->columns;
274 gint old_length, length;
277 view_model->columns = gtk_tree_view_get_columns (view_model->view);
279 /* As the view tells us one change at a time, we can do this hack. */
280 length = g_list_length (view_model->columns);
281 old_length = g_list_length (old_columns);
282 if (length != old_length)
287 /* where are they different */
288 for (a = old_columns, b = view_model->columns; a && b; a = a->next, b = b->next)
290 if (a->data != b->data)
294 path = gtk_tree_path_new ();
295 gtk_tree_path_append_index (path, i);
296 if (length < old_length)
299 gtk_tree_model_deleted (GTK_TREE_MODEL (view_model), path);
304 iter.stamp = view_model->stamp;
306 gtk_tree_model_inserted (GTK_TREE_MODEL (view_model), path, &iter);
308 gtk_tree_path_free (path);
317 new_order = g_new (int, length);
318 a = old_columns; b = view_model->columns;
320 while (a->data == b->data)
329 if (a->next->data == b->data)
332 while (b->data != a->data)
337 for (i = 0; i < m; i++)
339 for (i = m; i < m+n; i++)
342 for (i = m + n +1; i < length; i++)
348 while (a->data != b->data)
353 for (i = 0; i < m; i++)
356 for (i = m+1; i < m + n+ 1; i++)
357 new_order[i] = i - 1;
358 for (i = m + n + 1; i < length; i++)
362 path = gtk_tree_path_new ();
363 gtk_tree_model_reordered (GTK_TREE_MODEL (view_model),
367 gtk_tree_path_free (path);
371 g_list_free (old_columns);
374 static GtkTreeModel *
375 view_column_model_new (GtkTreeView *view)
377 GtkTreeModel *retval;
379 retval = GTK_TREE_MODEL (g_object_new (view_column_model_get_type (), NULL));
380 ((ViewColumnModel *)retval)->view = view;
381 ((ViewColumnModel *)retval)->columns = gtk_tree_view_get_columns (view);
383 gtk_signal_connect (GTK_OBJECT (view), "columns_changed", GTK_SIGNAL_FUNC (update_columns), retval);
392 add_clicked (GtkWidget *button, gpointer data)
397 GtkTreeViewColumn *column;
398 GtkTreeSelection *selection;
399 GtkCellRenderer *cell;
400 gchar *label = g_strdup_printf ("Column %d", i);
402 cell = gtk_cell_renderer_text_new ();
403 column = gtk_tree_view_column_new_with_attributes (label, cell, "text", 0, NULL);
404 g_object_set_data_full (G_OBJECT (column), column_data, label, g_free);
405 gtk_tree_view_column_set_reorderable (column, TRUE);
406 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_RESIZEABLE);
407 gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
408 gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
411 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
412 gtk_tree_selection_select_iter (selection, &iter);
416 get_visible (GtkTreeViewColumn *tree_column,
417 GtkCellRenderer *cell,
418 GtkTreeModel *tree_model,
422 GtkTreeViewColumn *column;
424 gtk_tree_model_get (tree_model, iter, 1, &column, -1);
427 gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (cell),
433 set_visible (GtkCellRendererToggle *cell,
437 GtkTreeView *tree_view = (GtkTreeView *) data;
438 GtkTreeViewColumn *column;
441 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
443 model = gtk_tree_view_get_model (tree_view);
445 gtk_tree_model_get_iter (model, &iter, path);
446 gtk_tree_model_get (model, &iter, 1, &column, -1);
450 gtk_tree_view_column_set_visible (column, ! gtk_tree_view_column_get_visible (column));
451 gtk_tree_model_range_changed (model, path, &iter, path, &iter);
453 gtk_tree_path_free (path);
457 add_left_clicked (GtkWidget *button,
462 GtkTreeViewColumn *column;
464 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data));
466 gtk_tree_selection_get_selected (selection, NULL, &iter);
467 gtk_tree_model_get (gtk_tree_view_get_model (GTK_TREE_VIEW (data)),
468 &iter, 0, &label, 1, &column, -1);
470 if (GTK_WIDGET (data) == top_right_tree_view)
471 gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_top), column);
473 gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
475 /* gtk_list_store_remove (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data))), &iter);*/
477 /* Put it back on the left */
478 gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
479 gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
480 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
481 gtk_tree_selection_select_iter (selection, &iter);
487 add_right_clicked (GtkWidget *button, gpointer data)
491 GtkTreeViewColumn *column;
493 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
495 gtk_tree_selection_get_selected (selection, NULL, &iter);
496 gtk_tree_model_get (GTK_TREE_MODEL (left_tree_model),
497 &iter, 0, &label, 1, &column, -1);
498 gtk_list_store_remove (GTK_LIST_STORE (left_tree_model), &iter);
500 if (GTK_WIDGET (data) == top_right_tree_view)
501 gtk_tree_view_append_column (GTK_TREE_VIEW (sample_tree_view_top), column);
503 gtk_tree_view_append_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
508 selection_changed (GtkTreeSelection *selection, GtkWidget *button)
510 if (gtk_tree_selection_get_selected (selection, NULL, NULL))
511 gtk_widget_set_sensitive (button, TRUE);
513 gtk_widget_set_sensitive (button, FALSE);
516 static GtkTargetEntry row_targets[] = {
517 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, 0}
521 main (int argc, char *argv[])
524 GtkWidget *hbox, *vbox;
525 GtkWidget *vbox2, *bbox;
527 GtkTreeViewColumn *column;
528 GtkCellRenderer *cell;
530 GtkTreeModel *sample_model;
533 gtk_init (&argc, &argv);
535 /* First initialize all the models for signal purposes */
536 left_tree_model = (GtkTreeModel *) gtk_list_store_new_with_types (2, G_TYPE_STRING, GTK_TYPE_POINTER);
537 sample_model = (GtkTreeModel *) gtk_list_store_new_with_types (1, G_TYPE_STRING);
538 sample_tree_view_top = gtk_tree_view_new_with_model (sample_model);
539 sample_tree_view_bottom = gtk_tree_view_new_with_model (sample_model);
540 top_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_top));
541 bottom_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_bottom));
542 top_right_tree_view = gtk_tree_view_new_with_model (top_right_tree_model);
543 bottom_right_tree_view = gtk_tree_view_new_with_model (bottom_right_tree_model);
545 for (i = 0; i < 10; i++)
548 gchar *string = g_strdup_printf ("%d", i);
549 gtk_list_store_append (GTK_LIST_STORE (sample_model), &iter);
550 gtk_list_store_set (GTK_LIST_STORE (sample_model), &iter, 0, string, -1);
554 /* Set up the test windows. */
555 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
556 gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
557 gtk_window_set_title (GTK_WINDOW (window), "Top Window");
558 swindow = gtk_scrolled_window_new (NULL, NULL);
559 gtk_container_add (GTK_CONTAINER (window), swindow);
560 gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_top);
561 gtk_widget_show_all (window);
563 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
564 gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
565 gtk_window_set_title (GTK_WINDOW (window), "Bottom Window");
566 swindow = gtk_scrolled_window_new (NULL, NULL);
567 gtk_container_add (GTK_CONTAINER (window), swindow);
568 gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_bottom);
569 gtk_widget_show_all (window);
571 /* Set up the main window */
572 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
573 gtk_window_set_default_size (GTK_WINDOW (window), 500, 300);
574 vbox = gtk_vbox_new (FALSE, 8);
575 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
576 gtk_container_add (GTK_CONTAINER (window), vbox);
578 hbox = gtk_hbox_new (FALSE, 8);
579 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
582 cell = gtk_cell_renderer_text_new ();
584 swindow = gtk_scrolled_window_new (NULL, NULL);
585 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
586 left_tree_view = gtk_tree_view_new_with_model (left_tree_model);
587 gtk_container_add (GTK_CONTAINER (swindow), left_tree_view);
588 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (left_tree_view), -1,
589 "Unattached Columns", cell, "text", 0, NULL);
590 cell = gtk_cell_renderer_toggle_new ();
591 g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, left_tree_view, NULL, FALSE, FALSE);
592 column = gtk_tree_view_column_new_with_attributes ("Visible", cell, NULL);
593 gtk_tree_view_append_column (GTK_TREE_VIEW (left_tree_view), column);
594 g_object_unref (G_OBJECT (column));
595 gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
596 gtk_box_pack_start (GTK_BOX (hbox), swindow, TRUE, TRUE, 0);
599 vbox2 = gtk_vbox_new (FALSE, 8);
600 gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
602 bbox = gtk_vbutton_box_new ();
603 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
604 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), 0, 0);
605 gtk_box_pack_start (GTK_BOX (vbox2), bbox, TRUE, TRUE, 0);
607 button = gtk_button_new_with_label ("<<");
608 gtk_widget_set_sensitive (button, FALSE);
609 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_left_clicked), top_right_tree_view);
610 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (top_right_tree_view))),
611 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
612 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
614 button = gtk_button_new_with_label (">>");
615 gtk_widget_set_sensitive (button, FALSE);
616 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_right_clicked), top_right_tree_view);
617 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view))),
618 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
619 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
621 bbox = gtk_vbutton_box_new ();
622 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
623 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), 0, 0);
624 gtk_box_pack_start (GTK_BOX (vbox2), bbox, TRUE, TRUE, 0);
626 button = gtk_button_new_with_label ("<<");
627 gtk_widget_set_sensitive (button, FALSE);
628 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_left_clicked), bottom_right_tree_view);
629 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (bottom_right_tree_view))),
630 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
631 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
633 button = gtk_button_new_with_label (">>");
634 gtk_widget_set_sensitive (button, FALSE);
635 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_right_clicked), bottom_right_tree_view);
636 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view))),
637 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
638 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
642 vbox2 = gtk_vbox_new (FALSE, 8);
643 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
645 swindow = gtk_scrolled_window_new (NULL, NULL);
646 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
647 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (top_right_tree_view), FALSE);
648 cell = gtk_cell_renderer_text_new ();
649 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (top_right_tree_view), -1,
650 NULL, cell, "text", 0, NULL);
651 cell = gtk_cell_renderer_toggle_new ();
652 g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, top_right_tree_view, NULL, FALSE, FALSE);
653 column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
654 gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
655 gtk_tree_view_append_column (GTK_TREE_VIEW (top_right_tree_view), column);
657 gtk_container_add (GTK_CONTAINER (swindow), top_right_tree_view);
658 gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
660 swindow = gtk_scrolled_window_new (NULL, NULL);
661 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
662 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (bottom_right_tree_view), FALSE);
663 cell = gtk_cell_renderer_text_new ();
664 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (bottom_right_tree_view), -1,
665 NULL, cell, "text", 0, NULL);
666 cell = gtk_cell_renderer_toggle_new ();
667 g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, bottom_right_tree_view, NULL, FALSE, FALSE);
668 column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
669 gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
670 gtk_tree_view_append_column (GTK_TREE_VIEW (bottom_right_tree_view), column);
671 gtk_container_add (GTK_CONTAINER (swindow), bottom_right_tree_view);
672 gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
676 gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (left_tree_view),
679 G_N_ELEMENTS (row_targets),
682 gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (left_tree_view),
684 G_N_ELEMENTS (row_targets),
688 gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (top_right_tree_view),
691 G_N_ELEMENTS (row_targets),
694 gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (top_right_tree_view),
696 G_N_ELEMENTS (row_targets),
700 gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (bottom_right_tree_view),
703 G_N_ELEMENTS (row_targets),
706 gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (bottom_right_tree_view),
708 G_N_ELEMENTS (row_targets),
713 gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0);
715 hbox = gtk_hbox_new (FALSE, 8);
716 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
717 button = gtk_button_new_with_mnemonic ("_Add new Column");
718 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_clicked), left_tree_model);
719 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
721 gtk_widget_show_all (window);