forked from AuroraMiddleware/gtk
3f5178dc21
Instead of allowing people to pass a uint user-data, insist on them comparing mime types. The user data was a uint instead of a pointer anyway, so uniqueness could not be guaranteed and it caused more issues than it was worth. And that's ignoring the fact that it basically wasn't used.
906 lines
28 KiB
C
906 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_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)
|
|
{
|
|
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);
|
|
|
|
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)
|
|
{
|
|
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);
|
|
|
|
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 gboolean
|
|
view_column_model_drag_data_get (GtkTreeDragSource *drag_source,
|
|
GtkTreePath *path,
|
|
GtkSelectionData *selection_data)
|
|
{
|
|
if (gtk_tree_set_row_drag_data (selection_data,
|
|
GTK_TREE_MODEL (drag_source),
|
|
path))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
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,
|
|
GtkSelectionData *selection_data)
|
|
{
|
|
GtkTreeModel *src_model;
|
|
|
|
if (gtk_tree_get_row_drag_data (selection_data,
|
|
&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,
|
|
GtkSelectionData *selection_data)
|
|
{
|
|
GtkTreeModel *src_model;
|
|
GtkTreePath *src_path = NULL;
|
|
gboolean retval = FALSE;
|
|
|
|
if (gtk_tree_get_row_drag_data (selection_data,
|
|
&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)
|
|
{
|
|
}
|
|
|
|
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
|
|
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 GtkTargetEntry row_targets[] = {
|
|
{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_APP }
|
|
};
|
|
|
|
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;
|
|
GtkTargetList *targets;
|
|
gint i;
|
|
|
|
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 (GTK_WINDOW_TOPLEVEL);
|
|
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
|
|
gtk_window_set_title (GTK_WINDOW (window), "Top Window");
|
|
swindow = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_container_add (GTK_CONTAINER (window), swindow);
|
|
gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_top);
|
|
gtk_widget_show (window);
|
|
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 300, 300);
|
|
gtk_window_set_title (GTK_WINDOW (window), "Bottom Window");
|
|
swindow = gtk_scrolled_window_new (NULL, NULL);
|
|
gtk_container_add (GTK_CONTAINER (window), swindow);
|
|
gtk_container_add (GTK_CONTAINER (swindow), sample_tree_view_bottom);
|
|
gtk_widget_show (window);
|
|
|
|
/* Set up the main window */
|
|
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
|
|
gtk_window_set_default_size (GTK_WINDOW (window), 500, 300);
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
|
gtk_container_add (GTK_CONTAINER (window), vbox);
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
|
gtk_box_pack_start (GTK_BOX (vbox), hbox);
|
|
|
|
/* Left Pane */
|
|
cell = gtk_cell_renderer_text_new ();
|
|
|
|
swindow = gtk_scrolled_window_new (NULL, NULL);
|
|
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_container_add (GTK_CONTAINER (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_pack_start (GTK_BOX (hbox), swindow);
|
|
|
|
/* Middle Pane */
|
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2);
|
|
|
|
bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
|
|
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
|
|
gtk_box_pack_start (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_pack_start (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_pack_start (GTK_BOX (bbox), button);
|
|
|
|
bbox = gtk_button_box_new (GTK_ORIENTATION_VERTICAL);
|
|
gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
|
|
gtk_box_pack_start (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_pack_start (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_pack_start (GTK_BOX (bbox), button);
|
|
|
|
|
|
/* Right Pane */
|
|
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
|
|
gtk_box_pack_start (GTK_BOX (hbox), vbox2);
|
|
|
|
swindow = gtk_scrolled_window_new (NULL, NULL);
|
|
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_container_add (GTK_CONTAINER (swindow), top_right_tree_view);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), swindow);
|
|
|
|
swindow = gtk_scrolled_window_new (NULL, NULL);
|
|
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_container_add (GTK_CONTAINER (swindow), bottom_right_tree_view);
|
|
gtk_box_pack_start (GTK_BOX (vbox2), swindow);
|
|
|
|
|
|
/* Drag and Drop */
|
|
targets = gtk_target_list_new (row_targets, G_N_ELEMENTS (row_targets));
|
|
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);
|
|
gtk_target_list_unref (targets);
|
|
|
|
gtk_box_pack_start (GTK_BOX (vbox), gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
|
|
|
|
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 8);
|
|
gtk_box_pack_start (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_pack_start (GTK_BOX (hbox), button);
|
|
|
|
gtk_widget_show (window);
|
|
gtk_main ();
|
|
|
|
return 0;
|
|
}
|