/* This is -*- C -*- */
/* $Id: guppi-data-tree-view.c,v 1.22 2001/09/27 05:07:29 trow Exp $ */
/*
* guppi-data-tree-view.c
*
* Copyright (C) 2000 EMC Capital Management, Inc.
*
* Developed by Jon Trowbridge <trow@gnu.org> and
* Havoc Pennington <hp@pobox.com>.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*/
#include <config.h>
#include <gtk/gtkclist.h>
#include <gtk/gtkctree.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtkhseparator.h>
#include <gtk/gtkselection.h>
#include <gtk/gtkdnd.h>
#include <gtk/gtkwindow.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <guppi-paths.h>
#include <guppi-convenient.h>
#if 0
#include <guppi-data-transform.h>
#endif
#include "guppi-data-tree-view.h"
static GtkObjectClass *parent_class = NULL;
static void
guppi_data_tree_view_destroy (GtkObject * obj)
{
GuppiDataTreeView *tv = GUPPI_DATA_TREE_VIEW (obj);
gtk_signal_disconnect_by_data (GTK_OBJECT (tv->tree), tv);
guppi_unref0 (tv->tree);
if (parent_class->destroy)
parent_class->destroy (obj);
}
static void
guppi_data_tree_view_finalize (GtkObject * obj)
{
guppi_finalized (obj);
if (parent_class->finalize)
parent_class->finalize (obj);
}
/**************************************************************************/
static GtkMenu *
build_data_popup (GuppiData * data, GuppiDataTreeView * tv,
GuppiDataTreeNode * node)
{
GtkMenu *menu = GTK_MENU (gtk_menu_new ());
GtkWidget *mi;
mi = gtk_menu_item_new_with_label (guppi_data_get_label (data));
gtk_menu_append (menu, mi);
gtk_widget_show (mi);
mi = gtk_menu_item_new ();
gtk_container_add (GTK_CONTAINER (mi), gtk_hseparator_new ());
gtk_menu_append (menu, mi);
gtk_widget_show_all (mi);
guppi_data_build_menu (data, menu, tv->tree);
return menu;
}
static GtkTargetEntry drag_target_table = { "guppi/data", 0, 0 };
/* Unselect the data object we are manipulating when the popup menu
disappears. */
static void
popup_destroy_cb (GtkWidget *menu, gpointer user_data)
{
GtkCTree *ctree;
GtkCTreeNode *ctree_node;
ctree = GTK_CTREE (user_data);
ctree_node = (GtkCTreeNode *)gtk_object_get_data (GTK_OBJECT (menu),
"ctree_node");
/* If our popup action deleted the element from the tree, it might
not still be there to unselect... */
if (!gtk_ctree_find (ctree, NULL, ctree_node))
return;
gtk_ctree_unselect (ctree, ctree_node);
gtk_ctree_node_set_selectable (ctree, ctree_node, FALSE);
}
static gint
button_press_event (GtkWidget * w, GdkEventButton * ev)
{
GuppiDataTreeView *tv;
GtkCTreeNode *ctree_node;
GuppiDataTreeNode *node;
gint row, col;
GList *lnode;
g_return_val_if_fail (w != NULL && GUPPI_IS_DATA_TREE_VIEW (w), FALSE);
g_return_val_if_fail (ev != NULL, FALSE);
tv = GUPPI_DATA_TREE_VIEW (w);
gtk_clist_get_selection_info (GTK_CLIST (w), ev->x, ev->y, &row, &col);
/*
* Let clicks on the tree expanders chain up to the CTree event handlers.
*/
if (gtk_ctree_is_hot_spot (GTK_CTREE (w), ev->x, ev->y)) {
if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
GTK_WIDGET_CLASS (parent_class)->button_press_event (w, ev);
return TRUE;
}
lnode = g_list_nth (GTK_CLIST (w)->row_list, row);
if (lnode == NULL || lnode->data == NULL)
return FALSE;
ctree_node = GTK_CTREE_NODE (lnode);
node = (GuppiDataTreeNode *) gtk_ctree_node_get_row_data (GTK_CTREE (w),
ctree_node);
g_return_val_if_fail (node != NULL, FALSE);
if (ev->button == 1) {
GtkTargetList *target_list;
gtk_ctree_node_set_selectable (GTK_CTREE (w), ctree_node, TRUE);
gtk_ctree_select (GTK_CTREE (w), ctree_node);
target_list = gtk_target_list_new (&drag_target_table, 1);
gtk_drag_begin (w, target_list, GDK_ACTION_COPY,
ev->button, (GdkEvent *) ev);
tv->pending_dragged_data = node->data;
tv->pending_dragged_node = ctree_node;
return TRUE;
} else if (ev->button == 3) {
GtkMenu *popup_menu = build_data_popup (node->data, tv, node);
gtk_widget_show (GTK_WIDGET (popup_menu));
gtk_menu_popup (popup_menu, NULL, NULL, NULL, NULL, ev->button, ev->time);
gtk_ctree_node_set_selectable (GTK_CTREE (w), ctree_node, TRUE);
gtk_ctree_select (GTK_CTREE (w), ctree_node);
gtk_object_set_data (GTK_OBJECT (popup_menu), "ctree_node", ctree_node);
/* Connect a callback to selection-done that will un-select the
particular ctree node when our popup menu goes away. */
gtk_signal_connect (GTK_OBJECT (popup_menu),
"selection-done",
GTK_SIGNAL_FUNC (popup_destroy_cb),
w);
return TRUE;
}
return FALSE;
}
static void
drag_end (GtkWidget * w, GdkDragContext * c)
{
GtkCTreeNode *ctree_node;
g_return_if_fail (w != NULL && GUPPI_IS_DATA_TREE_VIEW (w));
ctree_node = GUPPI_DATA_TREE_VIEW (w)->pending_dragged_node;
gtk_ctree_unselect (GTK_CTREE (w), ctree_node);
gtk_ctree_node_set_selectable (GTK_CTREE (w), ctree_node, FALSE);
}
static void
drag_data_get (GtkWidget * w, GdkDragContext * context,
GtkSelectionData * selection_data, guint info, guint time)
{
GuppiDataTreeView *tv;
g_return_if_fail (w != NULL && GUPPI_IS_DATA_TREE_VIEW (w));
tv = GUPPI_DATA_TREE_VIEW (w);
g_return_if_fail (tv->pending_dragged_data != NULL);
gtk_selection_data_set (selection_data,
gdk_atom_intern ("guppi/data", FALSE),
(sizeof (tv->pending_dragged_data) == 4 ? 32 : 64), /* ? */
(guchar *) & (tv->pending_dragged_data),
sizeof (tv->pending_dragged_data));
tv->pending_dragged_data = NULL;
}
static void
guppi_data_tree_view_class_init (GuppiDataTreeViewClass * klass)
{
GtkObjectClass *object_class = (GtkObjectClass *) klass;
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
parent_class = gtk_type_class (GTK_TYPE_CTREE);
object_class->destroy = guppi_data_tree_view_destroy;
object_class->finalize = guppi_data_tree_view_finalize;
widget_class->button_press_event = button_press_event;
widget_class->drag_data_get = drag_data_get;
widget_class->drag_end = drag_end;
}
static void
guppi_data_tree_view_init (GuppiDataTreeView * obj)
{
}
GtkType guppi_data_tree_view_get_type (void)
{
static GtkType guppi_data_tree_view_type = 0;
if (!guppi_data_tree_view_type) {
static const GtkTypeInfo guppi_data_tree_view_info = {
"GuppiDataTreeView",
sizeof (GuppiDataTreeView),
sizeof (GuppiDataTreeViewClass),
(GtkClassInitFunc) guppi_data_tree_view_class_init,
(GtkObjectInitFunc) guppi_data_tree_view_init,
NULL, NULL, (GtkClassInitFunc) NULL
};
guppi_data_tree_view_type = gtk_type_unique (GTK_TYPE_CTREE,
&guppi_data_tree_view_info);
}
return guppi_data_tree_view_type;
}
/**************************************************************************/
static GtkCTreeNode *
guppi_data_tree_view_build_node (GuppiDataTreeView * tv,
GtkCTreeNode * parent,
GuppiDataTreeNode * node)
{
static GdkPixmap *lock_pixmap = NULL;
static GdkBitmap *lock_bitmap = NULL;
gchar *text[5];
GtkCTreeNode *sib = NULL;
GtkCTreeNode *us;
gint mem;
float mem_val;
gchar buf[32];
gchar *sz_info;
if (lock_pixmap == NULL) {
gchar *path = guppi_find_pixmap ("lock.png");
GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file (path);
gdk_pixbuf_render_pixmap_and_mask (pixbuf,
&lock_pixmap, &lock_bitmap, 20);
guppi_free (path);
}
if (node->sibling_next)
sib = guppi_data_tree_view_build_node (tv, parent, node->sibling_next);
text[0] = (gchar *) guppi_data_get_label (node->data);
text[1] = " ";
/* text[2] = (gchar *) guppi_data_get_type_name (node->data); */
text[2] = "-TypeName-";
sz_info = guppi_data_get_size_info (node->data);
text[3] = sz_info;
mem = guppi_data_get_size_in_bytes (node->data);
if (mem > 0) {
if (mem < 1024)
g_snprintf (buf, 32, "%db", mem);
else {
mem_val = mem / 1024.0;
if (mem_val < 1024)
g_snprintf (buf, 32, "%0.2fk", mem_val);
else
g_snprintf (buf, 32, "%0.2fM", mem_val / 1024);
}
}
text[4] = mem > 0 ? buf : "?";
us = gtk_ctree_insert_node (GTK_CTREE (tv), parent, sib,
text, 6,
NULL,
NULL, NULL, NULL, node->child == NULL, TRUE);
if (guppi_data_is_read_only (node->data)) {
gtk_ctree_node_set_pixmap (GTK_CTREE (tv),
us, 1, lock_pixmap, lock_bitmap);
}
gtk_ctree_node_set_selectable (GTK_CTREE (tv), us, FALSE);
gtk_ctree_node_set_row_data (GTK_CTREE (tv), us, node);
if (node->child)
guppi_data_tree_view_build_node (tv, us, node->child);
g_free (sz_info);
return us;
}
static void
guppi_data_tree_view_build (GuppiDataTreeView * tv)
{
GuppiDataTreeNode *root;
g_return_if_fail (tv != NULL);
gtk_clist_freeze (GTK_CLIST (tv));
gtk_clist_clear (GTK_CLIST (tv));
root = tv->tree->root;
if (root)
guppi_data_tree_view_build_node (tv, NULL, root);
gtk_clist_thaw (GTK_CLIST (tv));
}
void
guppi_data_tree_view_construct (GuppiDataTreeView * tv, GuppiDataTree * tree)
{
static gchar *titles[5] = { NULL };
gint column_count = 5;
gint i;
if (titles[0] == NULL) {
titles[0] = _("Data");
titles[1] = "";
titles[2] = _("Type");
titles[3] = _("Size");
titles[4] = _("Mem");
}
g_return_if_fail (tv != NULL);
g_return_if_fail (tree != NULL);
g_return_if_fail (tv->tree == NULL);
tv->tree = tree;
guppi_ref (tv->tree);
gtk_signal_connect_object (GTK_OBJECT (tv->tree),
"changed",
GTK_SIGNAL_FUNC (guppi_data_tree_view_build),
GTK_OBJECT (tv));
gtk_ctree_construct (GTK_CTREE (tv), column_count, 0, titles);
for (i = 0; i < column_count; ++i)
gtk_clist_set_column_auto_resize (GTK_CLIST (tv), i, TRUE);
gtk_ctree_set_line_style (GTK_CTREE (tv), GTK_CTREE_LINES_DOTTED);
gtk_ctree_set_expander_style (GTK_CTREE (tv), GTK_CTREE_EXPANDER_TRIANGLE);
guppi_data_tree_view_build (tv);
}
GtkWidget *
guppi_data_tree_view_new (GuppiDataTree * tree)
{
GuppiDataTreeView *tv;
g_return_val_if_fail (tree != NULL, NULL);
tv = GUPPI_DATA_TREE_VIEW (guppi_type_new (guppi_data_tree_view_get_type ()));
guppi_data_tree_view_construct (tv, tree);
return GTK_WIDGET (tv);
}
/* For debugging */
void
guppi_data_tree_view_popup (GuppiDataTree * tree)
{
GtkWidget *w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget *tv = guppi_data_tree_view_new (tree);
gtk_container_add (GTK_CONTAINER (w), tv);
gtk_widget_show_all (w);
}
/* $Id: guppi-data-tree-view.c,v 1.22 2001/09/27 05:07:29 trow Exp $ */
syntax highlighted by Code2HTML, v. 0.9.1