mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-27 06:00:22 +00:00
386b63b85d
In 99.9% of all cases, these are just NULL, NULL. So just do away with these arguments, people can use the setters for the rare cases where they want the scrolled window to use a different adjustment.
920 lines
28 KiB
C
920 lines
28 KiB
C
/* testtreecolumns.c
|
|
* Copyright (C) 2001 Red Hat, Inc
|
|
* Author: Jonathan Blandford
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <gtk/gtk.h>
|
|
|
|
/*
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
* README README README README README README README README README README
|
|
*
|
|
* DO NOT!!! I REPEAT DO NOT! EVER LOOK AT THIS CODE AS AN EXAMPLE OF WHAT YOUR
|
|
* CODE SHOULD LOOK LIKE.
|
|
*
|
|
* IT IS VERY CONFUSING, AND IS MEANT TO TEST A LOT OF CODE IN THE TREE. WHILE
|
|
* IT IS ACTUALLY CORRECT CODE, IT IS NOT USEFUL.
|
|
*/
|
|
|
|
GtkWidget *left_tree_view;
|
|
GtkWidget *top_right_tree_view;
|
|
GtkWidget *bottom_right_tree_view;
|
|
GtkTreeModel *left_tree_model;
|
|
GtkTreeModel *top_right_tree_model;
|
|
GtkTreeModel *bottom_right_tree_model;
|
|
GtkWidget *sample_tree_view_top;
|
|
GtkWidget *sample_tree_view_bottom;
|
|
|
|
#define column_data "my_column_data"
|
|
|
|
static void move_row (GtkTreeModel *src,
|
|
GtkTreeIter *src_iter,
|
|
GtkTreeModel *dest,
|
|
GtkTreeIter *dest_iter);
|
|
|
|
/* Kids, don't try this at home. */
|
|
|
|
/* Small GtkTreeModel to model columns */
|
|
typedef struct _ViewColumnModel ViewColumnModel;
|
|
typedef struct _ViewColumnModelClass ViewColumnModelClass;
|
|
|
|
struct _ViewColumnModel
|
|
{
|
|
GtkListStore parent;
|
|
GtkTreeView *view;
|
|
GList *columns;
|
|
gint stamp;
|
|
};
|
|
|
|
struct _ViewColumnModelClass
|
|
{
|
|
GtkListStoreClass parent_class;
|
|
};
|
|
|
|
static void view_column_model_tree_model_init (GtkTreeModelIface *iface);
|
|
static void view_column_model_drag_source_init (GtkTreeDragSourceIface *iface);
|
|
static void view_column_model_drag_dest_init (GtkTreeDragDestIface *iface);
|
|
|
|
|
|
static GType view_column_model_get_type (void);
|
|
G_DEFINE_TYPE_WITH_CODE (ViewColumnModel, view_column_model, GTK_TYPE_LIST_STORE,
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, view_column_model_tree_model_init)
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE, view_column_model_drag_source_init)
|
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_DEST, view_column_model_drag_dest_init))
|
|
|
|
|
|
|
|
static void view_column_model_init (ViewColumnModel *model)
|
|
{
|
|
model->stamp = g_random_int ();
|
|
}
|
|
|
|
static gint
|
|
view_column_model_get_n_columns (GtkTreeModel *tree_model)
|
|
{
|
|
return 2;
|
|
}
|
|
|
|
static GType
|
|
view_column_model_get_column_type (GtkTreeModel *tree_model,
|
|
gint index)
|
|
{
|
|
switch (index)
|
|
{
|
|
case 0:
|
|
return G_TYPE_STRING;
|
|
case 1:
|
|
return GTK_TYPE_TREE_VIEW_COLUMN;
|
|
default:
|
|
return G_TYPE_INVALID;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_get_iter (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
GtkTreePath *path)
|
|
|
|
{
|
|
ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
|
|
GList *list;
|
|
gint i;
|
|
|
|
g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
|
|
|
|
i = gtk_tree_path_get_indices (path)[0];
|
|
list = g_list_nth (view_model->columns, i);
|
|
|
|
if (list == NULL)
|
|
return FALSE;
|
|
|
|
iter->stamp = view_model->stamp;
|
|
iter->user_data = list;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GtkTreePath *
|
|
view_column_model_get_path (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
|
|
GtkTreePath *retval;
|
|
GList *list;
|
|
gint i = 0;
|
|
|
|
g_return_val_if_fail (iter->stamp == view_model->stamp, NULL);
|
|
|
|
for (list = view_model->columns; list; list = list->next)
|
|
{
|
|
if (list == (GList *)iter->user_data)
|
|
break;
|
|
i++;
|
|
}
|
|
if (list == NULL)
|
|
return NULL;
|
|
|
|
retval = gtk_tree_path_new ();
|
|
gtk_tree_path_append_index (retval, i);
|
|
return retval;
|
|
}
|
|
|
|
static void
|
|
view_column_model_get_value (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
gint column,
|
|
GValue *value)
|
|
{
|
|
#ifndef G_DISABLE_CHECKS
|
|
ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
|
|
|
|
g_return_if_fail (column < 2);
|
|
g_return_if_fail (view_model->stamp == iter->stamp);
|
|
g_return_if_fail (iter->user_data != NULL);
|
|
#endif
|
|
|
|
if (column == 0)
|
|
{
|
|
g_value_init (value, G_TYPE_STRING);
|
|
g_value_set_string (value, gtk_tree_view_column_get_title (GTK_TREE_VIEW_COLUMN (((GList *)iter->user_data)->data)));
|
|
}
|
|
else
|
|
{
|
|
g_value_init (value, GTK_TYPE_TREE_VIEW_COLUMN);
|
|
g_value_set_object (value, ((GList *)iter->user_data)->data);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_iter_next (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
#ifndef G_DISABLE_CHECKS
|
|
ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
|
|
|
|
g_return_val_if_fail (view_model->stamp == iter->stamp, FALSE);
|
|
g_return_val_if_fail (iter->user_data != NULL, FALSE);
|
|
#endif
|
|
|
|
iter->user_data = ((GList *)iter->user_data)->next;
|
|
return iter->user_data != NULL;
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_iter_children (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
GtkTreeIter *parent)
|
|
{
|
|
ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
|
|
|
|
/* this is a list, nodes have no children */
|
|
if (parent)
|
|
return FALSE;
|
|
|
|
/* but if parent == NULL we return the list itself as children of the
|
|
* "root"
|
|
*/
|
|
|
|
if (view_model->columns)
|
|
{
|
|
iter->stamp = view_model->stamp;
|
|
iter->user_data = view_model->columns;
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_iter_has_child (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static gint
|
|
view_column_model_iter_n_children (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter)
|
|
{
|
|
return g_list_length (((ViewColumnModel *)tree_model)->columns);
|
|
}
|
|
|
|
static gint
|
|
view_column_model_iter_nth_child (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
GtkTreeIter *parent,
|
|
gint n)
|
|
{
|
|
ViewColumnModel *view_model = (ViewColumnModel *)tree_model;
|
|
|
|
if (parent)
|
|
return FALSE;
|
|
|
|
iter->stamp = view_model->stamp;
|
|
iter->user_data = g_list_nth ((GList *)view_model->columns, n);
|
|
|
|
return (iter->user_data != NULL);
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_iter_parent (GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
GtkTreeIter *child)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
view_column_model_tree_model_init (GtkTreeModelIface *iface)
|
|
{
|
|
iface->get_n_columns = view_column_model_get_n_columns;
|
|
iface->get_column_type = view_column_model_get_column_type;
|
|
iface->get_iter = view_column_model_get_iter;
|
|
iface->get_path = view_column_model_get_path;
|
|
iface->get_value = view_column_model_get_value;
|
|
iface->iter_next = view_column_model_iter_next;
|
|
iface->iter_children = view_column_model_iter_children;
|
|
iface->iter_has_child = view_column_model_iter_has_child;
|
|
iface->iter_n_children = view_column_model_iter_n_children;
|
|
iface->iter_nth_child = view_column_model_iter_nth_child;
|
|
iface->iter_parent = view_column_model_iter_parent;
|
|
}
|
|
|
|
static GdkContentProvider *
|
|
view_column_model_drag_data_get (GtkTreeDragSource *drag_source,
|
|
GtkTreePath *path)
|
|
{
|
|
return gtk_tree_create_row_drag_content (GTK_TREE_MODEL (drag_source), path);
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_drag_data_delete (GtkTreeDragSource *drag_source,
|
|
GtkTreePath *path)
|
|
{
|
|
/* Nothing -- we handle moves on the dest side */
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_row_drop_possible (GtkTreeDragDest *drag_dest,
|
|
GtkTreePath *dest_path,
|
|
const GValue *value)
|
|
{
|
|
GtkTreeModel *src_model;
|
|
|
|
if (gtk_tree_get_row_drag_data (value,
|
|
&src_model,
|
|
NULL))
|
|
{
|
|
if (src_model == left_tree_model ||
|
|
src_model == top_right_tree_model ||
|
|
src_model == bottom_right_tree_model)
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
view_column_model_drag_data_received (GtkTreeDragDest *drag_dest,
|
|
GtkTreePath *dest,
|
|
const GValue *value)
|
|
{
|
|
GtkTreeModel *src_model;
|
|
GtkTreePath *src_path = NULL;
|
|
gboolean retval = FALSE;
|
|
|
|
if (gtk_tree_get_row_drag_data (value,
|
|
&src_model,
|
|
&src_path))
|
|
{
|
|
GtkTreeIter src_iter;
|
|
GtkTreeIter dest_iter;
|
|
gboolean have_dest;
|
|
|
|
/* We are a little lazy here, and assume if we can't convert dest
|
|
* to an iter, we need to append. See gtkliststore.c for a more
|
|
* careful handling of this.
|
|
*/
|
|
have_dest = gtk_tree_model_get_iter (GTK_TREE_MODEL (drag_dest), &dest_iter, dest);
|
|
|
|
if (gtk_tree_model_get_iter (src_model, &src_iter, src_path))
|
|
{
|
|
if (src_model == left_tree_model ||
|
|
src_model == top_right_tree_model ||
|
|
src_model == bottom_right_tree_model)
|
|
{
|
|
move_row (src_model, &src_iter, GTK_TREE_MODEL (drag_dest),
|
|
have_dest ? &dest_iter : NULL);
|
|
retval = TRUE;
|
|
}
|
|
}
|
|
|
|
gtk_tree_path_free (src_path);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void
|
|
view_column_model_drag_source_init (GtkTreeDragSourceIface *iface)
|
|
{
|
|
iface->drag_data_get = view_column_model_drag_data_get;
|
|
iface->drag_data_delete = view_column_model_drag_data_delete;
|
|
}
|
|
|
|
static void
|
|
view_column_model_drag_dest_init (GtkTreeDragDestIface *iface)
|
|
{
|
|
iface->drag_data_received = view_column_model_drag_data_received;
|
|
iface->row_drop_possible = view_column_model_row_drop_possible;
|
|
}
|
|
|
|
static void
|
|
view_column_model_class_init (ViewColumnModelClass *klass)
|
|
{
|
|
}
|
|
|
|
static void
|
|
update_columns (GtkTreeView *view, ViewColumnModel *view_model)
|
|
{
|
|
GList *old_columns = view_model->columns;
|
|
gint old_length, length;
|
|
GList *a, *b;
|
|
|
|
view_model->columns = gtk_tree_view_get_columns (view_model->view);
|
|
|
|
/* As the view tells us one change at a time, we can do this hack. */
|
|
length = g_list_length (view_model->columns);
|
|
old_length = g_list_length (old_columns);
|
|
if (length != old_length)
|
|
{
|
|
GtkTreePath *path;
|
|
gint i = 0;
|
|
|
|
/* where are they different */
|
|
for (a = old_columns, b = view_model->columns; a && b; a = a->next, b = b->next)
|
|
{
|
|
if (a->data != b->data)
|
|
break;
|
|
i++;
|
|
}
|
|
path = gtk_tree_path_new ();
|
|
gtk_tree_path_append_index (path, i);
|
|
if (length < old_length)
|
|
{
|
|
view_model->stamp++;
|
|
gtk_tree_model_row_deleted (GTK_TREE_MODEL (view_model), path);
|
|
}
|
|
else
|
|
{
|
|
GtkTreeIter iter;
|
|
iter.stamp = view_model->stamp;
|
|
iter.user_data = b;
|
|
gtk_tree_model_row_inserted (GTK_TREE_MODEL (view_model), path, &iter);
|
|
}
|
|
gtk_tree_path_free (path);
|
|
}
|
|
else
|
|
{
|
|
gint i;
|
|
gint m = 0, n = 1;
|
|
gint *new_order;
|
|
GtkTreePath *path;
|
|
|
|
new_order = g_new (int, length);
|
|
a = old_columns; b = view_model->columns;
|
|
|
|
while (a->data == b->data)
|
|
{
|
|
a = a->next;
|
|
b = b->next;
|
|
if (a == NULL)
|
|
return;
|
|
m++;
|
|
}
|
|
|
|
if (a->next->data == b->data)
|
|
{
|
|
b = b->next;
|
|
while (b->data != a->data)
|
|
{
|
|
b = b->next;
|
|
n++;
|
|
}
|
|
for (i = 0; i < m; i++)
|
|
new_order[i] = i;
|
|
for (i = m; i < m+n; i++)
|
|
new_order[i] = i+1;
|
|
new_order[i] = m;
|
|
for (i = m + n +1; i < length; i++)
|
|
new_order[i] = i;
|
|
}
|
|
else
|
|
{
|
|
a = a->next;
|
|
while (a->data != b->data)
|
|
{
|
|
a = a->next;
|
|
n++;
|
|
}
|
|
for (i = 0; i < m; i++)
|
|
new_order[i] = i;
|
|
new_order[m] = m+n;
|
|
for (i = m+1; i < m + n+ 1; i++)
|
|
new_order[i] = i - 1;
|
|
for (i = m + n + 1; i < length; i++)
|
|
new_order[i] = i;
|
|
}
|
|
|
|
path = gtk_tree_path_new ();
|
|
gtk_tree_model_rows_reordered (GTK_TREE_MODEL (view_model),
|
|
path,
|
|
NULL,
|
|
new_order);
|
|
gtk_tree_path_free (path);
|
|
g_free (new_order);
|
|
}
|
|
if (old_columns)
|
|
g_list_free (old_columns);
|
|
}
|
|
|
|
static GtkTreeModel *
|
|
view_column_model_new (GtkTreeView *view)
|
|
{
|
|
GtkTreeModel *retval;
|
|
|
|
retval = g_object_new (view_column_model_get_type (), NULL);
|
|
((ViewColumnModel *)retval)->view = view;
|
|
((ViewColumnModel *)retval)->columns = gtk_tree_view_get_columns (view);
|
|
|
|
g_signal_connect (view, "columns_changed", G_CALLBACK (update_columns), retval);
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* Back to sanity.
|
|
*/
|
|
|
|
static void
|
|
add_clicked (GtkWidget *button, gpointer data)
|
|
{
|
|
static gint i = 0;
|
|
|
|
GtkTreeIter iter;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeSelection *selection;
|
|
GtkCellRenderer *cell;
|
|
gchar *label = g_strdup_printf ("Column %d", i);
|
|
|
|
cell = gtk_cell_renderer_text_new ();
|
|
column = gtk_tree_view_column_new_with_attributes (label, cell, "text", 0, NULL);
|
|
g_object_set_data_full (G_OBJECT (column), column_data, label, g_free);
|
|
gtk_tree_view_column_set_reorderable (column, TRUE);
|
|
gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
|
|
gtk_tree_view_column_set_resizable (column, TRUE);
|
|
gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
|
|
gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
|
|
i++;
|
|
|
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
|
|
gtk_tree_selection_select_iter (selection, &iter);
|
|
}
|
|
|
|
static void
|
|
get_visible (GtkTreeViewColumn *tree_column,
|
|
GtkCellRenderer *cell,
|
|
GtkTreeModel *tree_model,
|
|
GtkTreeIter *iter,
|
|
gpointer data)
|
|
{
|
|
GtkTreeViewColumn *column;
|
|
|
|
gtk_tree_model_get (tree_model, iter, 1, &column, -1);
|
|
if (column)
|
|
{
|
|
gtk_cell_renderer_toggle_set_active (GTK_CELL_RENDERER_TOGGLE (cell),
|
|
gtk_tree_view_column_get_visible (column));
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_visible (GtkCellRendererToggle *cell,
|
|
gchar *path_str,
|
|
gpointer data)
|
|
{
|
|
GtkTreeView *tree_view = (GtkTreeView *) data;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeModel *model;
|
|
GtkTreeIter iter;
|
|
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
|
|
|
|
model = gtk_tree_view_get_model (tree_view);
|
|
|
|
gtk_tree_model_get_iter (model, &iter, path);
|
|
gtk_tree_model_get (model, &iter, 1, &column, -1);
|
|
|
|
if (column)
|
|
{
|
|
gtk_tree_view_column_set_visible (column, ! gtk_tree_view_column_get_visible (column));
|
|
gtk_tree_model_row_changed (model, path, &iter);
|
|
}
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
static void
|
|
move_to_left (GtkTreeModel *src,
|
|
GtkTreeIter *src_iter,
|
|
GtkTreeIter *dest_iter)
|
|
{
|
|
GtkTreeIter iter;
|
|
GtkTreeViewColumn *column;
|
|
GtkTreeSelection *selection;
|
|
gchar *label;
|
|
|
|
gtk_tree_model_get (src, src_iter, 0, &label, 1, &column, -1);
|
|
|
|
if (src == top_right_tree_model)
|
|
gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_top), column);
|
|
else
|
|
gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
|
|
|
|
/* gtk_list_store_remove (GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data))), &iter);*/
|
|
|
|
/* Put it back on the left */
|
|
if (dest_iter)
|
|
gtk_list_store_insert_before (GTK_LIST_STORE (left_tree_model),
|
|
&iter, dest_iter);
|
|
else
|
|
gtk_list_store_append (GTK_LIST_STORE (left_tree_model), &iter);
|
|
|
|
gtk_list_store_set (GTK_LIST_STORE (left_tree_model), &iter, 0, label, 1, column, -1);
|
|
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
|
|
gtk_tree_selection_select_iter (selection, &iter);
|
|
|
|
g_free (label);
|
|
}
|
|
|
|
static void
|
|
move_to_right (GtkTreeIter *src_iter,
|
|
GtkTreeModel *dest,
|
|
GtkTreeIter *dest_iter)
|
|
{
|
|
gchar *label;
|
|
GtkTreeViewColumn *column;
|
|
gint before = -1;
|
|
|
|
gtk_tree_model_get (GTK_TREE_MODEL (left_tree_model),
|
|
src_iter, 0, &label, 1, &column, -1);
|
|
gtk_list_store_remove (GTK_LIST_STORE (left_tree_model), src_iter);
|
|
|
|
if (dest_iter)
|
|
{
|
|
GtkTreePath *path = gtk_tree_model_get_path (dest, dest_iter);
|
|
before = (gtk_tree_path_get_indices (path))[0];
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
if (dest == top_right_tree_model)
|
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_top), column, before);
|
|
else
|
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_bottom), column, before);
|
|
|
|
g_free (label);
|
|
}
|
|
|
|
static void
|
|
move_up_or_down (GtkTreeModel *src,
|
|
GtkTreeIter *src_iter,
|
|
GtkTreeModel *dest,
|
|
GtkTreeIter *dest_iter)
|
|
{
|
|
GtkTreeViewColumn *column;
|
|
gchar *label;
|
|
gint before = -1;
|
|
|
|
gtk_tree_model_get (src, src_iter, 0, &label, 1, &column, -1);
|
|
|
|
if (dest_iter)
|
|
{
|
|
GtkTreePath *path = gtk_tree_model_get_path (dest, dest_iter);
|
|
before = (gtk_tree_path_get_indices (path))[0];
|
|
gtk_tree_path_free (path);
|
|
}
|
|
|
|
if (src == top_right_tree_model)
|
|
gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_top), column);
|
|
else
|
|
gtk_tree_view_remove_column (GTK_TREE_VIEW (sample_tree_view_bottom), column);
|
|
|
|
if (dest == top_right_tree_model)
|
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_top), column, before);
|
|
else
|
|
gtk_tree_view_insert_column (GTK_TREE_VIEW (sample_tree_view_bottom), column, before);
|
|
|
|
g_free (label);
|
|
}
|
|
|
|
static void
|
|
move_row (GtkTreeModel *src,
|
|
GtkTreeIter *src_iter,
|
|
GtkTreeModel *dest,
|
|
GtkTreeIter *dest_iter)
|
|
{
|
|
if (src == left_tree_model)
|
|
move_to_right (src_iter, dest, dest_iter);
|
|
else if (dest == left_tree_model)
|
|
move_to_left (src, src_iter, dest_iter);
|
|
else
|
|
move_up_or_down (src, src_iter, dest, dest_iter);
|
|
}
|
|
|
|
static void
|
|
add_left_clicked (GtkWidget *button,
|
|
gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (data));
|
|
|
|
gtk_tree_selection_get_selected (selection, NULL, &iter);
|
|
|
|
move_to_left (gtk_tree_view_get_model (GTK_TREE_VIEW (data)), &iter, NULL);
|
|
}
|
|
|
|
static void
|
|
add_right_clicked (GtkWidget *button, gpointer data)
|
|
{
|
|
GtkTreeIter iter;
|
|
|
|
GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view));
|
|
|
|
gtk_tree_selection_get_selected (selection, NULL, &iter);
|
|
|
|
move_to_right (&iter, gtk_tree_view_get_model (GTK_TREE_VIEW (data)), NULL);
|
|
}
|
|
|
|
static void
|
|
selection_changed (GtkTreeSelection *selection, GtkWidget *button)
|
|
{
|
|
if (gtk_tree_selection_get_selected (selection, NULL, NULL))
|
|
gtk_widget_set_sensitive (button, TRUE);
|
|
else
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
}
|
|
|
|
static void
|
|
quit_cb (GtkWidget *widget,
|
|
gpointer data)
|
|
{
|
|
gboolean *done = data;
|
|
|
|
*done = TRUE;
|
|
|
|
g_main_context_wakeup (NULL);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
GtkWidget *window;
|
|
GtkWidget *hbox, *vbox;
|
|
GtkWidget *vbox2, *bbox;
|
|
GtkWidget *button;
|
|
GtkTreeViewColumn *column;
|
|
GtkCellRenderer *cell;
|
|
GtkWidget *swindow;
|
|
GtkTreeModel *sample_model;
|
|
GdkContentFormats *targets;
|
|
gint i;
|
|
gboolean done = FALSE;
|
|
|
|
gtk_init ();
|
|
|
|
/* First initialize all the models for signal purposes */
|
|
left_tree_model = (GtkTreeModel *) gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_POINTER);
|
|
sample_model = (GtkTreeModel *) gtk_list_store_new (1, G_TYPE_STRING);
|
|
sample_tree_view_top = gtk_tree_view_new_with_model (sample_model);
|
|
sample_tree_view_bottom = gtk_tree_view_new_with_model (sample_model);
|
|
top_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_top));
|
|
bottom_right_tree_model = (GtkTreeModel *) view_column_model_new (GTK_TREE_VIEW (sample_tree_view_bottom));
|
|
top_right_tree_view = gtk_tree_view_new_with_model (top_right_tree_model);
|
|
bottom_right_tree_view = gtk_tree_view_new_with_model (bottom_right_tree_model);
|
|
|
|
for (i = 0; i < 10; i++)
|
|
{
|
|
GtkTreeIter iter;
|
|
gchar *string = g_strdup_printf ("%d", i);
|
|
gtk_list_store_append (GTK_LIST_STORE (sample_model), &iter);
|
|
gtk_list_store_set (GTK_LIST_STORE (sample_model), &iter, 0, string, -1);
|
|
g_free (string);
|
|
}
|
|
|
|
/* Set up the test windows. */
|
|
window = gtk_window_new ();
|
|
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
|
|
gtk_window_set_title (GTK_WINDOW (window), "Top Window");
|
|
swindow = gtk_scrolled_window_new ();
|
|
gtk_window_set_child (GTK_WINDOW (window), swindow);
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (swindow), sample_tree_view_top);
|
|
gtk_widget_show (window);
|
|
|
|
window = gtk_window_new ();
|
|
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
|
|
gtk_window_set_title (GTK_WINDOW (window), "Bottom Window");
|
|
swindow = gtk_scrolled_window_new ();
|
|
gtk_window_set_child (GTK_WINDOW (window), swindow);
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (swindow), sample_tree_view_bottom);
|
|
gtk_widget_show (window);
|
|
|
|
/* Set up the main window */
|
|
window = gtk_window_new ();
|
|
g_signal_connect (window, "destroy", G_CALLBACK (quit_cb), &done);
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 500, 300);
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
|
gtk_window_set_child (GTK_WINDOW (window), vbox);
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
|
gtk_box_append (GTK_BOX (vbox), hbox);
|
|
|
|
/* Left Pane */
|
|
cell = gtk_cell_renderer_text_new ();
|
|
|
|
swindow = gtk_scrolled_window_new ();
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
left_tree_view = gtk_tree_view_new_with_model (left_tree_model);
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (swindow), left_tree_view);
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (left_tree_view), -1,
|
|
"Unattached Columns", cell, "text", 0, NULL);
|
|
cell = gtk_cell_renderer_toggle_new ();
|
|
g_signal_connect (cell, "toggled", G_CALLBACK (set_visible), left_tree_view);
|
|
column = gtk_tree_view_column_new_with_attributes ("Visible", cell, NULL);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (left_tree_view), column);
|
|
|
|
gtk_tree_view_column_set_cell_data_func (column, cell, get_visible, NULL, NULL);
|
|
gtk_box_append (GTK_BOX (hbox), swindow);
|
|
|
|
/* Middle Pane */
|
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
|
gtk_box_append (GTK_BOX (hbox), vbox2);
|
|
|
|
bbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_box_append (GTK_BOX (vbox2), bbox);
|
|
|
|
button = gtk_button_new_with_mnemonic ("<< (_Q)");
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
g_signal_connect (button, "clicked", G_CALLBACK (add_left_clicked), top_right_tree_view);
|
|
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (top_right_tree_view)),
|
|
"changed", G_CALLBACK (selection_changed), button);
|
|
gtk_box_append (GTK_BOX (bbox), button);
|
|
|
|
button = gtk_button_new_with_mnemonic (">> (_W)");
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
g_signal_connect (button, "clicked", G_CALLBACK (add_right_clicked), top_right_tree_view);
|
|
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view)),
|
|
"changed", G_CALLBACK (selection_changed), button);
|
|
gtk_box_append (GTK_BOX (bbox), button);
|
|
|
|
bbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
|
gtk_box_append (GTK_BOX (vbox2), bbox);
|
|
|
|
button = gtk_button_new_with_mnemonic ("<< (_E)");
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
g_signal_connect (button, "clicked", G_CALLBACK (add_left_clicked), bottom_right_tree_view);
|
|
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (bottom_right_tree_view)),
|
|
"changed", G_CALLBACK (selection_changed), button);
|
|
gtk_box_append (GTK_BOX (bbox), button);
|
|
|
|
button = gtk_button_new_with_mnemonic (">> (_R)");
|
|
gtk_widget_set_sensitive (button, FALSE);
|
|
g_signal_connect (button, "clicked", G_CALLBACK (add_right_clicked), bottom_right_tree_view);
|
|
g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (left_tree_view)),
|
|
"changed", G_CALLBACK (selection_changed), button);
|
|
gtk_box_append (GTK_BOX (bbox), button);
|
|
|
|
|
|
/* Right Pane */
|
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
|
gtk_box_append (GTK_BOX (hbox), vbox2);
|
|
|
|
swindow = gtk_scrolled_window_new ();
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (top_right_tree_view), FALSE);
|
|
cell = gtk_cell_renderer_text_new ();
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (top_right_tree_view), -1,
|
|
NULL, cell, "text", 0, NULL);
|
|
cell = gtk_cell_renderer_toggle_new ();
|
|
g_signal_connect (cell, "toggled", G_CALLBACK (set_visible), top_right_tree_view);
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
|
|
gtk_tree_view_column_set_cell_data_func (column, cell, get_visible, NULL, NULL);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (top_right_tree_view), column);
|
|
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (swindow), top_right_tree_view);
|
|
gtk_box_append (GTK_BOX (vbox2), swindow);
|
|
|
|
swindow = gtk_scrolled_window_new ();
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (bottom_right_tree_view), FALSE);
|
|
cell = gtk_cell_renderer_text_new ();
|
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (bottom_right_tree_view), -1,
|
|
NULL, cell, "text", 0, NULL);
|
|
cell = gtk_cell_renderer_toggle_new ();
|
|
g_signal_connect (cell, "toggled", G_CALLBACK (set_visible), bottom_right_tree_view);
|
|
column = gtk_tree_view_column_new_with_attributes (NULL, cell, NULL);
|
|
gtk_tree_view_column_set_cell_data_func (column, cell, get_visible, NULL, NULL);
|
|
gtk_tree_view_append_column (GTK_TREE_VIEW (bottom_right_tree_view), column);
|
|
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (swindow), bottom_right_tree_view);
|
|
gtk_box_append (GTK_BOX (vbox2), swindow);
|
|
|
|
|
|
/* Drag and Drop */
|
|
targets = gdk_content_formats_new_for_gtype (GTK_TYPE_TREE_ROW_DATA);
|
|
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (left_tree_view),
|
|
GDK_BUTTON1_MASK,
|
|
targets,
|
|
GDK_ACTION_MOVE);
|
|
gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (left_tree_view),
|
|
targets,
|
|
GDK_ACTION_MOVE);
|
|
|
|
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (top_right_tree_view),
|
|
GDK_BUTTON1_MASK,
|
|
targets,
|
|
GDK_ACTION_MOVE);
|
|
gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (top_right_tree_view),
|
|
targets,
|
|
GDK_ACTION_MOVE);
|
|
|
|
gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (bottom_right_tree_view),
|
|
GDK_BUTTON1_MASK,
|
|
targets,
|
|
GDK_ACTION_MOVE);
|
|
gtk_tree_view_enable_model_drag_dest (GTK_TREE_VIEW (bottom_right_tree_view),
|
|
targets,
|
|
GDK_ACTION_MOVE);
|
|
gdk_content_formats_unref (targets);
|
|
|
|
gtk_box_append (GTK_BOX (vbox), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
|
gtk_box_append (GTK_BOX (vbox), hbox);
|
|
button = gtk_button_new_with_mnemonic ("_Add new Column");
|
|
g_signal_connect (button, "clicked", G_CALLBACK (add_clicked), left_tree_model);
|
|
gtk_box_append (GTK_BOX (hbox), button);
|
|
|
|
gtk_widget_show (window);
|
|
|
|
while (!done)
|
|
g_main_context_iteration (NULL, TRUE);
|
|
|
|
return 0;
|
|
}
|