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_init (ViewColumnModel *model)
39 model->stamp = g_random_int ();
43 view_column_model_get_n_columns (GtkTreeModel *tree_model)
49 view_column_model_get_column_type (GtkTreeModel *tree_model,
57 return GTK_TYPE_TREE_VIEW_COLUMN;
59 return G_TYPE_INVALID;
64 view_column_model_get_iter (GtkTreeModel *tree_model,
69 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
73 g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
75 i = gtk_tree_path_get_indices (path)[0];
76 list = g_list_nth (view_model->columns, i);
81 iter->stamp = view_model->stamp;
82 iter->user_data = list;
88 view_column_model_get_path (GtkTreeModel *tree_model,
91 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
96 g_return_val_if_fail (iter->stamp == view_model->stamp, NULL);
98 for (list = view_model->columns; list; list = list->next)
100 if (list == (GList *)iter->user_data)
107 retval = gtk_tree_path_new ();
108 gtk_tree_path_append_index (retval, i);
113 view_column_model_get_value (GtkTreeModel *tree_model,
118 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
120 g_return_if_fail (column < 2);
121 g_return_if_fail (view_model->stamp == iter->stamp);
122 g_return_if_fail (iter->user_data != NULL);
126 g_value_init (value, G_TYPE_STRING);
127 g_value_set_string (value, gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (((GList *)iter->user_data)->data)));
131 g_value_init (value, GTK_TYPE_TREE_VIEW_COLUMN);
132 g_value_set_object (value, ((GList *)iter->user_data)->data);
137 view_column_model_iter_next (GtkTreeModel *tree_model,
140 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
142 g_return_val_if_fail (view_model->stamp == iter->stamp, FALSE);
143 g_return_val_if_fail (iter->user_data != NULL, FALSE);
145 iter->user_data = ((GList *)iter->user_data)->next;
146 return iter->user_data != NULL;
150 view_column_model_iter_children (GtkTreeModel *tree_model,
154 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
156 /* this is a list, nodes have no children */
160 /* but if parent == NULL we return the list itself as children of the
164 if (view_model->columns)
166 iter->stamp = view_model->stamp;
167 iter->user_data = view_model->columns;
175 view_column_model_iter_has_child (GtkTreeModel *tree_model,
182 view_column_model_iter_n_children (GtkTreeModel *tree_model,
185 return g_list_length (((ViewColumnModel *)tree_model)->columns);
189 view_column_model_iter_nth_child (GtkTreeModel *tree_model,
194 ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
199 iter->stamp = view_model->stamp;
200 iter->user_data = g_list_nth ((GList *)view_model->columns, n);
202 return (iter->user_data != NULL);
206 view_column_model_iter_parent (GtkTreeModel *tree_model,
214 view_column_model_tree_model_init (GtkTreeModelIface *iface)
216 iface->get_n_columns = view_column_model_get_n_columns;
217 iface->get_column_type = view_column_model_get_column_type;
218 iface->get_iter = view_column_model_get_iter;
219 iface->get_path = view_column_model_get_path;
220 iface->get_value = view_column_model_get_value;
221 iface->iter_next = view_column_model_iter_next;
222 iface->iter_children = view_column_model_iter_children;
223 iface->iter_has_child = view_column_model_iter_has_child;
224 iface->iter_n_children = view_column_model_iter_n_children;
225 iface->iter_nth_child = view_column_model_iter_nth_child;
226 iface->iter_parent = view_column_model_iter_parent;
231 view_column_model_get_type (void)
233 static GType view_column_model_type = 0;
235 if (!view_column_model_type)
237 static const GTypeInfo view_column_model_info =
239 sizeof (GtkListStoreClass),
240 NULL, /* base_init */
241 NULL, /* base_finalize */
242 NULL, /* class_init */
243 NULL, /* class_finalize */
244 NULL, /* class_data */
245 sizeof (GtkListStore),
247 (GInstanceInitFunc) view_column_model_init,
250 static const GInterfaceInfo tree_model_info =
252 (GInterfaceInitFunc) view_column_model_tree_model_init,
257 view_column_model_type = g_type_register_static (G_TYPE_OBJECT, "ViewModelColumn", &view_column_model_info, 0);
258 g_type_add_interface_static (view_column_model_type,
263 return view_column_model_type;
267 update_columns (GtkTreeView *view, ViewColumnModel *view_model)
269 GList *old_columns = view_model->columns;
270 gint old_length, length;
273 view_model->columns = gtk_tree_view_get_columns (view_model->view);
275 /* As the view tells us one change at a time, we can do this hack. */
276 length = g_list_length (view_model->columns);
277 old_length = g_list_length (old_columns);
278 if (length != old_length)
283 /* where are they different */
284 for (a = old_columns, b = view_model->columns; a && b; a = a->next, b = b->next)
286 if (a->data != b->data)
290 path = gtk_tree_path_new ();
291 gtk_tree_path_append_index (path, i);
292 if (length < old_length)
295 gtk_tree_model_deleted (GTK_TREE_MODEL (view_model), path);
300 iter.stamp = view_model->stamp;
302 gtk_tree_model_inserted (GTK_TREE_MODEL (view_model), path, &iter);
304 gtk_tree_path_free (path);
313 new_order = g_new (int, length);
314 a = old_columns; b = view_model->columns;
316 while (a->data == b->data)
325 if (a->next->data == b->data)
328 while (b->data != a->data)
333 for (i = 0; i < m; i++)
335 for (i = m; i < m+n; i++)
338 for (i = m + n +1; i < length; i++)
344 while (a->data != b->data)
349 for (i = 0; i < m; i++)
352 for (i = m+1; i < m + n+ 1; i++)
353 new_order[i] = i - 1;
354 for (i = m + n + 1; i < length; i++)
358 path = gtk_tree_path_new ();
359 gtk_tree_model_reordered (GTK_TREE_MODEL (view_model),
363 gtk_tree_path_free (path);
367 g_list_free (old_columns);
370 static GtkTreeModel *
371 view_column_model_new (GtkTreeView *view)
373 GtkTreeModel *retval;
375 retval = GTK_TREE_MODEL (g_object_new (view_column_model_get_type (), NULL));
376 ((ViewColumnModel *)retval)->view = view;
377 ((ViewColumnModel *)retval)->columns = gtk_tree_view_get_columns (view);
379 gtk_signal_connect (GTK_OBJECT (view), "columns_changed", GTK_SIGNAL_FUNC (update_columns), retval);
388 add_clicked (GtkWidget *button, gpointer data)
393 GtkTreeViewColumn *column;
394 GtkTreeSelection *selection;
395 GtkCellRenderer *cell;
396 gchar *label = g_strdup_printf ("Column %d", i);
398 cell = gtk_cell_renderer_text_new ();
399 column = gtk_tree_view_column_new_with_attributes (label, cell, "text", 0, NULL);
400 g_object_set_data_full (G_OBJECT (column), column_data, label, g_free);
401 gtk_tree_view_column_set_reorderable (column, TRUE);
402 gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_RESIZEABLE);
403 gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
404 gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
407 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
408 gtk_tree_selection_select_iter (selection, &iter);
412 get_visible (GtkTreeViewColumn *tree_column,
413 GtkCellRenderer *cell,
414 GtkTreeModel *tree_model,
418 GtkTreeViewColumn *column;
420 gtk_tree_model_get (tree_model, iter, 1, &column, -1);
423 gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (cell),
429 set_visible (GtkCellRendererToggle *cell,
433 GtkTreeView *tree_view = (GtkTreeView *) data;
434 GtkTreeViewColumn *column;
437 GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
439 model = gtk_tree_view_get_model (tree_view);
441 gtk_tree_model_get_iter (model, &iter, path);
442 gtk_tree_model_get (model, &iter, 1, &column, -1);
446 gtk_tree_view_column_set_visible (column, ! gtk_tree_view_column_get_visible (column));
447 gtk_tree_model_range_changed (model, path, &iter, path, &iter);
449 gtk_tree_path_free (path);
453 add_left_clicked (GtkWidget *button,
458 GtkTreeViewColumn *column;
460 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data));
462 gtk_tree_selection_get_selected (selection, NULL, &iter);
463 gtk_tree_model_get (gtk_tree_view_get_model (GTK_TREE_VIEW (data)),
464 &iter, 0, &label, 1, &column, -1);
466 if (GTK_WIDGET (data) == top_right_tree_view)
467 gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_top), column);
469 gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
471 /* gtk_list_store_remove (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data))), &iter);*/
473 /* Put it back on the left */
474 gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
475 gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
476 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
477 gtk_tree_selection_select_iter (selection, &iter);
483 add_right_clicked (GtkWidget *button, gpointer data)
487 GtkTreeViewColumn *column;
489 GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
491 gtk_tree_selection_get_selected (selection, NULL, &iter);
492 gtk_tree_model_get (GTK_TREE_MODEL (left_tree_model),
493 &iter, 0, &label, 1, &column, -1);
494 gtk_list_store_remove (GTK_LIST_STORE (left_tree_model), &iter);
496 if (GTK_WIDGET (data) == top_right_tree_view)
497 gtk_tree_view_append_column (GTK_TREE_VIEW (sample_tree_view_top), column);
499 gtk_tree_view_append_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
504 selection_changed (GtkTreeSelection *selection, GtkWidget *button)
506 if (gtk_tree_selection_get_selected (selection, NULL, NULL))
507 gtk_widget_set_sensitive (button, TRUE);
509 gtk_widget_set_sensitive (button, FALSE);
512 static GtkTargetEntry row_targets[] = {
513 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP, 0}
517 main (int argc, char *argv[])
520 GtkWidget *hbox, *vbox;
521 GtkWidget *vbox2, *bbox;
523 GtkTreeViewColumn *column;
524 GtkCellRenderer *cell;
526 GtkTreeModel *sample_model;
529 gtk_init (&argc, &argv);
531 /* First initialize all the models for signal purposes */
532 left_tree_model = (GtkTreeModel *) gtk_list_store_new_with_types (2, G_TYPE_STRING, GTK_TYPE_POINTER);
533 sample_model = (GtkTreeModel *) gtk_list_store_new_with_types (1, G_TYPE_STRING);
534 sample_tree_view_top = gtk_tree_view_new_with_model (sample_model);
535 sample_tree_view_bottom = gtk_tree_view_new_with_model (sample_model);
536 top_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_top));
537 bottom_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_bottom));
538 top_right_tree_view = gtk_tree_view_new_with_model (top_right_tree_model);
539 bottom_right_tree_view = gtk_tree_view_new_with_model (bottom_right_tree_model);
541 for (i = 0; i < 10; i++)
544 gchar *string = g_strdup_printf ("%d", i);
545 gtk_list_store_append (GTK_LIST_STORE (sample_model), &iter);
546 gtk_list_store_set (GTK_LIST_STORE (sample_model), &iter, 0, string, -1);
550 /* Set up the test windows. */
551 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
552 gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
553 gtk_window_set_title (GTK_WINDOW (window), "Top Window");
554 swindow = gtk_scrolled_window_new (NULL, NULL);
555 gtk_container_add (GTK_CONTAINER (window), swindow);
556 gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_top);
557 gtk_widget_show_all (window);
559 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
560 gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
561 gtk_window_set_title (GTK_WINDOW (window), "Bottom Window");
562 swindow = gtk_scrolled_window_new (NULL, NULL);
563 gtk_container_add (GTK_CONTAINER (window), swindow);
564 gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_bottom);
565 gtk_widget_show_all (window);
567 /* Set up the main window */
568 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
569 gtk_window_set_default_size (GTK_WINDOW (window), 500, 300);
570 vbox = gtk_vbox_new (FALSE, 8);
571 gtk_container_set_border_width (GTK_CONTAINER (vbox), 8);
572 gtk_container_add (GTK_CONTAINER (window), vbox);
574 hbox = gtk_hbox_new (FALSE, 8);
575 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
578 cell = gtk_cell_renderer_text_new ();
580 swindow = gtk_scrolled_window_new (NULL, NULL);
581 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
582 left_tree_view = gtk_tree_view_new_with_model (left_tree_model);
583 gtk_container_add (GTK_CONTAINER (swindow), left_tree_view);
584 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (left_tree_view), -1,
585 "Unattached Columns", cell, "text", 0, NULL);
586 cell = gtk_cell_renderer_toggle_new ();
587 g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, left_tree_view, NULL, FALSE, FALSE);
588 column = gtk_tree_view_column_new_with_attributes ("Visible", cell, NULL);
589 gtk_tree_view_append_column (GTK_TREE_VIEW (left_tree_view), column);
590 g_object_unref (G_OBJECT (column));
591 gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
592 gtk_box_pack_start (GTK_BOX (hbox), swindow, TRUE, TRUE, 0);
595 vbox2 = gtk_vbox_new (FALSE, 8);
596 gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
598 bbox = gtk_vbutton_box_new ();
599 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
600 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), 0, 0);
601 gtk_box_pack_start (GTK_BOX (vbox2), bbox, TRUE, TRUE, 0);
603 button = gtk_button_new_with_label ("<<");
604 gtk_widget_set_sensitive (button, FALSE);
605 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_left_clicked), top_right_tree_view);
606 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (top_right_tree_view))),
607 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
608 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
610 button = gtk_button_new_with_label (">>");
611 gtk_widget_set_sensitive (button, FALSE);
612 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_right_clicked), top_right_tree_view);
613 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view))),
614 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
615 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
617 bbox = gtk_vbutton_box_new ();
618 gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
619 gtk_button_box_set_child_size (GTK_BUTTON_BOX (bbox), 0, 0);
620 gtk_box_pack_start (GTK_BOX (vbox2), bbox, TRUE, TRUE, 0);
622 button = gtk_button_new_with_label ("<<");
623 gtk_widget_set_sensitive (button, FALSE);
624 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_left_clicked), bottom_right_tree_view);
625 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (bottom_right_tree_view))),
626 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
627 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
629 button = gtk_button_new_with_label (">>");
630 gtk_widget_set_sensitive (button, FALSE);
631 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_right_clicked), bottom_right_tree_view);
632 gtk_signal_connect (GTK_OBJECT (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view))),
633 "selection-changed", GTK_SIGNAL_FUNC (selection_changed), button);
634 gtk_box_pack_start (GTK_BOX (bbox), button, FALSE, FALSE, 0);
638 vbox2 = gtk_vbox_new (FALSE, 8);
639 gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
641 swindow = gtk_scrolled_window_new (NULL, NULL);
642 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
643 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (top_right_tree_view), FALSE);
644 cell = gtk_cell_renderer_text_new ();
645 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (top_right_tree_view), -1,
646 NULL, cell, "text", 0, NULL);
647 cell = gtk_cell_renderer_toggle_new ();
648 g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, top_right_tree_view, NULL, FALSE, FALSE);
649 column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
650 gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
651 gtk_tree_view_append_column (GTK_TREE_VIEW (top_right_tree_view), column);
653 gtk_container_add (GTK_CONTAINER (swindow), top_right_tree_view);
654 gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
656 swindow = gtk_scrolled_window_new (NULL, NULL);
657 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
658 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (bottom_right_tree_view), FALSE);
659 cell = gtk_cell_renderer_text_new ();
660 gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (bottom_right_tree_view), -1,
661 NULL, cell, "text", 0, NULL);
662 cell = gtk_cell_renderer_toggle_new ();
663 g_signal_connect_data (G_OBJECT (cell), "toggled", (GCallback) set_visible, bottom_right_tree_view, NULL, FALSE, FALSE);
664 column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
665 gtk_tree_view_column_set_cell_data_func (column, get_visible, NULL, NULL);
666 gtk_tree_view_append_column (GTK_TREE_VIEW (bottom_right_tree_view), column);
667 gtk_container_add (GTK_CONTAINER (swindow), bottom_right_tree_view);
668 gtk_box_pack_start (GTK_BOX (vbox2), swindow, TRUE, TRUE, 0);
672 gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (left_tree_view),
675 G_N_ELEMENTS (row_targets),
678 gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (left_tree_view),
680 G_N_ELEMENTS (row_targets),
684 gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (top_right_tree_view),
687 G_N_ELEMENTS (row_targets),
690 gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (top_right_tree_view),
692 G_N_ELEMENTS (row_targets),
696 gtk_tree_view_set_rows_drag_source (GTK_TREE_VIEW (bottom_right_tree_view),
699 G_N_ELEMENTS (row_targets),
702 gtk_tree_view_set_rows_drag_dest (GTK_TREE_VIEW (bottom_right_tree_view),
704 G_N_ELEMENTS (row_targets),
709 gtk_box_pack_start (GTK_BOX (vbox), gtk_hseparator_new (), FALSE, FALSE, 0);
711 hbox = gtk_hbox_new (FALSE, 8);
712 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
713 button = gtk_button_new_with_mnemonic ("_Add new Column");
714 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (add_clicked), left_tree_model);
715 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
717 gtk_widget_show_all (window);