/* This is -*- C -*- */
/* $Id: guppi-data.c,v 1.44 2001/11/19 05:40:40 trow Exp $ */
/*
* guppi-data.c
*
* Copyright (C) 2000 EMC Capital Management, Inc.
* Copyright (C) 2001 The Free Software Foundation
*
* 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 "guppi-data.h"
#include <string.h>
#include <zlib.h>
/* #include <gnome.h> */
#include <gtk/gtksignal.h>
#include <gtk/gtkentry.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkvbox.h>
#include <gtk/gtkhseparator.h>
#include <gtk/gtkvseparator.h>
#include <gtk/gtkfilesel.h>
#include <gtk/gtkmenuitem.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>
#include <libgnomeui/gnome-dialog.h>
#include <libgnomeui/gnome-stock.h>
#include <gnome-xml/xmlmemory.h>
#include <guppi-useful.h>
#include <guppi-dialogs.h>
#include "guppi-data-plug-in.h"
#if 0
#include "guppi-data-tree.h"
#include "guppi-data-transform.h"
#endif
static GtkObjectClass *parent_class = NULL;
enum {
ARG_0
};
enum {
CHANGED,
CHANGED_LABEL,
CHANGED_SUBDATA,
LAST_SIGNAL
};
static guint data_signals[LAST_SIGNAL] = { 0 };
static void
process_pending_op (GuppiData *data)
{
GList *op_list;
GuppiDataOp *op;
g_return_if_fail (data != NULL && GUPPI_IS_DATA (data));
op_list = (GList *) data->pending_ops;
g_return_if_fail (op_list != NULL);
op = (GuppiDataOp *) op_list->data;
g_return_if_fail (op != NULL);
if (op->op)
op->op (data, op);
data->pending_ops = g_list_remove_link (op_list, op_list);
g_list_free_1 (op_list);
}
static void
changed (GuppiData *data)
{
process_pending_op (data);
}
static void
changed_label (GuppiData *data)
{
/* no op */
}
static void
changed_subdata (GuppiData *data)
{
process_pending_op (data);
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
GuppiData *
guppi_data_new (const gchar *type)
{
GuppiPlugIn *pi;
GuppiData *data;
GuppiDataClass *klass;
GtkType t;
g_return_val_if_fail (type && *type, NULL);
t = gtk_type_from_name (type);
if (t) {
if (gtk_type_is_a (t, GUPPI_TYPE_DATA)) {
data = (GuppiData *) guppi_type_new (t);
} else {
g_warning ("Type '%s' is-not-a GuppiData", type);
return NULL;
}
} else {
pi = guppi_plug_in_lookup ("data_impl", type);
if (pi == NULL) {
g_warning("Plug-in data_impl::%s not found", type);
return NULL;
}
g_return_val_if_fail (GUPPI_IS_DATA_PLUG_IN (pi), NULL);
data = guppi_data_plug_in_create_data (GUPPI_DATA_PLUG_IN (pi));
if (data == NULL) {
g_warning ("%s's constructor returned NULL", type);
return NULL;
}
}
g_return_val_if_fail (GUPPI_IS_DATA (data), NULL);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
if (!klass->class_validated && klass->validate_class != NULL) {
klass->class_validated = klass->validate_class (klass);
if (! klass->class_validated)
g_warning ("Class '%s' is not fully specified.\n", gtk_type_name (GTK_OBJECT_CLASS (klass)->type));
klass->class_validated = TRUE; /* only complain once */
}
if (!klass->is_leaf_type) {
g_warning ("Constructed non-leaf type '%s'", type);
guppi_unref (data);
return NULL;
}
if (klass->plug_in_code == NULL) {
klass->plug_in_code = guppi_strdup (type);
guppi_permanent_alloc (klass->plug_in_code);
}
return data;
}
/**
* guppi_data_unique_id
* @data: A #GuppiData object.
*
* Returns a unique identifier associated with @data.
*/
guppi_uniq_t
guppi_data_unique_id (GuppiData *data)
{
g_return_val_if_fail (data && GUPPI_IS_DATA (data), 0);
return data->id;
}
/**
* guppi_data_get_label
* @data: A #GuppiData object.
*
* Returns the label associated with @data.
*/
const gchar *
guppi_data_get_label (GuppiData *data)
{
g_return_val_if_fail (GUPPI_IS_DATA (data), NULL);
return data->label;
}
/**
* guppi_data_set_label
* @data: A #GuppiData object.
* @label: A descriptive label.
*
* Associates the label @label with @data.
*/
void
guppi_data_set_label (GuppiData *data, const gchar *label)
{
g_return_if_fail (GUPPI_IS_DATA (data));
g_return_if_fail (label != NULL);
if (data->label && strcmp (label, data->label)) {
guppi_free (data->label);
data->label = guppi_strdup (label);
gtk_signal_emit (GTK_OBJECT (data), data_signals[CHANGED_LABEL]);
}
}
/**
* guppi_data_is_read_only
* @data: A #GuppiData object.
*
* Returns %TRUE is @data is a read-only object. If an object is read-only,
* all potentially state-altering operations are illegal.
*/
gboolean
guppi_data_is_read_only (GuppiData *data)
{
GuppiDataClass *klass;
g_return_val_if_fail (GUPPI_IS_DATA (data), FALSE);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
return data->read_only || klass->read_only;
}
/**
* guppi_data_can_change
* @data: A #GuppiData object.
*
* Returns %TRUE is @data is not a read-only object. This is the opposite
* of guppi_data_can_change().
*/
gboolean
guppi_data_can_change (GuppiData *data)
{
return !guppi_data_is_read_only (data);
}
/**
* guppi_data_add_pending_op
* @data: A #GuppiData object.
* @op: A chunk of black magic.
*
* You should only call this function if you really know what you are doing.
*/
void
guppi_data_add_pending_op (GuppiData *data, GuppiDataOp *op)
{
GList *op_list;
g_return_if_fail (data != NULL && GUPPI_IS_DATA (data));
g_return_if_fail (op != NULL);
op_list = (GList *) data->pending_ops;
data->pending_ops = g_list_prepend (op_list, op);
}
/**
* guppi_data_changed
* @data: A #GuppiData object.
*
* To force @data to emit a "changed" signal, don't call
* this function. Call guppi_data_touch() instead.
*
* If you ignore this advice, bad things will probably happen.
*/
void
guppi_data_changed (GuppiData *data)
{
g_return_if_fail (data != NULL && GUPPI_IS_DATA (data));
g_assert (guppi_data_can_change (data));
g_assert (data->pending_ops != NULL);
gtk_signal_emit (GTK_OBJECT (data), data_signals[CHANGED]);
}
static void
op_nop (GuppiData *d, GuppiDataOp *op)
{
}
/**
* guppi_data_touch
* @data: A #GuppiData object.
*
* Force @data to emit a "changed" signal.
*/
void
guppi_data_touch (GuppiData *data)
{
GuppiDataOp op;
g_return_if_fail (data != NULL && GUPPI_IS_DATA (data));
op.op = op_nop;
guppi_data_add_pending_op (data, &op);
gtk_signal_emit (GTK_OBJECT (data), data_signals[CHANGED]);
}
/**
* guppi_data_touch_subdata
* @data: A #GuppiData object.
*
* Force @data to emit a "changed_subdata" signal.
*/
void
guppi_data_touch_subdata (GuppiData *data)
{
g_return_if_fail (data && GUPPI_IS_DATA (data));
gtk_signal_emit (GTK_OBJECT (data), data_signals[CHANGED_SUBDATA]);
}
/**
* guppi_data_copy
* @data: A #GuppiData object.
*
* Returns a copy of @data.
*/
GuppiData *
guppi_data_copy (GuppiData *data)
{
GuppiDataClass *klass;
GuppiData *copy;
g_return_val_if_fail (GUPPI_IS_DATA (data), NULL);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
g_return_val_if_fail (klass->copy != NULL, NULL);
copy = klass->copy (data);
copy->read_only = data->read_only;
copy->label = guppi_strdup_printf (_("Copy of %s"), guppi_data_get_label (data));
return copy;
}
/**
* guppi_data_get_size_in_bytes
* @data: A #GuppiData object.
*
* Returns the total quantity of memory being used by @data, in bytes.
* For some data interfaces and implementations, this is only an estimate,
* not an exact figure.
*/
gint
guppi_data_get_size_in_bytes (GuppiData *data)
{
GuppiDataClass *klass;
g_return_val_if_fail (GUPPI_IS_DATA (data), -1);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
return klass->get_size_in_bytes ? klass->get_size_in_bytes (data) : -1;
}
/**
* guppi_data_get_size_info
* @data: A #GuppiData object.
*
* Returns a short, human-readable description of @data.
* The exact nature of the description depends on the
* @data's type.
*/
gchar *
guppi_data_get_size_info (GuppiData *data)
{
GuppiDataClass *klass;
g_return_val_if_fail (GUPPI_IS_DATA (data), NULL);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
return klass->get_size_info ? klass->get_size_info (data) : NULL;
}
/**************************************************************************/
/**
* guppi_data_export_xml
* @data: A #GuppiData object.
* @doc: The #GuppiXMLDocument that will contain the exported XML.
*
* Build an XML tree describing @data.
* Returns: the top node of the constructed XML.
*/
xmlNodePtr
guppi_data_export_xml (GuppiData *data, GuppiXMLDocument *doc)
{
GuppiDataClass *klass;
xmlNodePtr data_node = NULL;
g_return_val_if_fail (data && GUPPI_IS_DATA (data), NULL);
g_return_val_if_fail (doc, NULL);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
data_node = xmlNewNode (doc->ns, "Data");
xmlNewProp (data_node, "Type", klass->plug_in_code);
if (data->label)
xmlNewTextChild (data_node, doc->ns, "Label", data->label);
if (klass->export_xml)
klass->export_xml (data, doc, data_node);
return data_node;
}
/**
* guppi_data_import_xml
* @doc: An XML document.
* @node: The top node of a description of some data from @doc.
*
* Scan the XML tree contained in @node and use it to construct a #GuppiData object.
* If the XML is malformed or any other errors occur in processing, %NULL is returned.
*
* Returns: the #GuppiData object constructed from the XML in @node.
*/
GuppiData *
guppi_data_import_xml (GuppiXMLDocument *doc, xmlNodePtr node)
{
gchar *type_name;
GuppiDataClass *klass;
GuppiData *data = NULL;
gboolean loaded_label = FALSE;
g_return_val_if_fail (doc != NULL, NULL);
g_return_val_if_fail (node != NULL, NULL);
if (strcmp (node->name, "Data"))
return NULL;
/* Construct base object from type and impl information */
type_name = xmlGetProp (node, "Type");
if (type_name == NULL) {
g_message ("Missing data Type property");
return NULL;
}
data = guppi_data_new (type_name);
if (data == NULL) {
g_message ("Unknown type \"%s\"", type_name);
xmlFree (type_name);
return NULL;
}
xmlFree (type_name);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
node = node->xmlChildrenNode;
while (node != NULL) {
if (!loaded_label && !strcmp (node->name, "Label")) {
/* We do this song & dance to avoid g_free vs. xmlFree problems. */
gchar *tmp = xmlNodeGetContent (node->xmlChildrenNode);
guppi_free (data->label);
data->label = g_strdup (tmp);
xmlFree (tmp);
loaded_label = TRUE;
} else if (klass->import_xml) {
/* If we fail, fail silently. */
klass->import_xml (data, doc, node);
}
node = node->next;
}
return data;
}
/**
* guppi_data_spew_xml
* @data: A #GuppiData object.
*
* Build an XML tree describing @data and write it out to the console.
* (This can be useful for debugging purposes.)
*/
void
guppi_data_spew_xml (GuppiData *data)
{
GuppiXMLDocument *doc;
g_return_if_fail (data && GUPPI_IS_DATA (data));
doc = guppi_xml_document_new ();
guppi_xml_document_set_root (doc, guppi_data_export_xml (data, doc));
guppi_xml_document_spew (doc);
guppi_xml_document_free (doc);
}
/* Subdata handling */
/**
* guppi_data_has_subdata
* @data: A #GuppiData object.
*
* Returns: %TRUE is @data contains any embedded subdata objects.
*/
gboolean
guppi_data_has_subdata (GuppiData *data)
{
g_return_val_if_fail (data && GUPPI_IS_DATA (data), FALSE);
return guppi_data_subdata_count (data) != 0;
}
static void
count_subdata_fn (GuppiData *d, gpointer user_data)
{
++*(gint *)user_data;
}
/**
* guppi_data_subdata_count
* @data: A #GuppiData object.
*
* Returns: the number of embedded subdata objects in @data.
*/
gint
guppi_data_subdata_count (GuppiData *data)
{
gint count = 0;
g_return_val_if_fail (data && GUPPI_IS_DATA (data), 0);
guppi_data_foreach_subdata (data, count_subdata_fn, &count);
return count;
}
/**
* guppi_data_foreach_subdata
* @data: A #GuppiData object.
* @fn: A function.
* @user_data:
*
* Iterate over @data's embedded subdata objects, applying the function @fn
* to each. For every call, @user_data is passed to @fn as its second argument.
*/
void
guppi_data_foreach_subdata (GuppiData *data, GuppiDataFn fn, gpointer closure)
{
GuppiDataClass *klass;
g_return_if_fail (GUPPI_IS_DATA (data));
g_return_if_fail (fn != NULL);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
/* If foreach_subdata isn't defined in the implementation class,
we assume that that type can never have subdata, and the
guppi_data_foreach_subdata () call is just a NOP. */
if (klass->foreach_subdata)
klass->foreach_subdata (data, fn, closure);
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/*** Data Menu Items ***/
/**
* guppi_data_build_menu
* @data: A #GuppiData object.
* @menu: A menu.
* @data_tree:
*
* Add menu items to @menu that correspond to data-type-specific operations
* on @data.
*/
void
guppi_data_build_menu (GuppiData *data, GtkMenu *menu, gpointer data_tree)
{
GuppiDataClass *klass;
g_return_if_fail (data && GUPPI_IS_DATA (data));
g_return_if_fail (menu && GTK_IS_MENU (menu));
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
if (klass->build_menu)
klass->build_menu (data, menu, data_tree);
}
/*
* Implement a well-behaved "rename data" dialog.
*/
struct rename_info {
GuppiData *data;
gchar *original_label;
GtkWidget *entry;
};
static void
rename_info_free (struct rename_info *ri)
{
gtk_signal_disconnect_by_data (GTK_OBJECT (ri->data), ri->entry);
guppi_unref (ri->data);
guppi_free (ri->original_label);
guppi_free (ri);
}
static void
rename_clicked_cb (GtkWidget *w, gint num, gpointer user_data)
{
struct rename_info *ri = (struct rename_info *)user_data;
if (num == 0) { /* OK */
/* We don't need to do anything in this case. */
} else if (num == 1) { /* Cancel */
guppi_data_set_label (ri->data, ri->original_label);
} else {
g_assert_not_reached ();
}
rename_info_free (ri);
gtk_widget_destroy (w);
}
static void
rename_close_cb (GtkWidget *w, gpointer user_data)
{
struct rename_info *ri = (struct rename_info *)user_data;
/* Revert to our original label */
guppi_data_set_label (ri->data, ri->original_label);
rename_info_free (ri);
}
static void
rename_edit_cb (GtkWidget *w, gpointer user_data)
{
struct rename_info *ri = (struct rename_info *)user_data;
gchar *s;
s = gtk_editable_get_chars (GTK_EDITABLE (w), 0, -1);
guppi_outside_alloc (s);
guppi_data_set_label (ri->data, s);
guppi_free (s);
}
static void
rename_changed_cb (GuppiData *data, const gchar* label, gpointer user_data)
{
GtkEntry *entry = GTK_ENTRY (user_data);
gchar *s;
s = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
if (strcmp (s, label))
gtk_entry_set_text (entry, label);
}
static void
rename_cb (GtkWidget *w, GuppiData *data)
{
GtkWidget *dialog;
GtkWidget *entry;
struct rename_info *ri;
ri = guppi_new0 (struct rename_info, 1);
ri->data = data;
guppi_ref (ri->data);
ri->original_label = guppi_strdup (guppi_data_get_label (data));
dialog = gnome_dialog_new (_("Edit Data Label"),
GNOME_STOCK_BUTTON_OK,
GNOME_STOCK_BUTTON_CANCEL,
NULL);
ri->entry = entry = gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY (entry), ri->original_label);
gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),
entry, TRUE, TRUE, 2);
gtk_signal_connect (GTK_OBJECT (entry),
"changed",
GTK_SIGNAL_FUNC (rename_edit_cb),
ri);
gtk_signal_connect (GTK_OBJECT (dialog),
"clicked",
GTK_SIGNAL_FUNC (rename_clicked_cb),
ri);
gtk_signal_connect (GTK_OBJECT (dialog),
"close",
GTK_SIGNAL_FUNC (rename_close_cb),
ri);
gtk_signal_connect (GTK_OBJECT (data),
"changed_label",
GTK_SIGNAL_FUNC (rename_changed_cb),
entry);
gtk_widget_show_all (dialog);
}
static void
data_info_cb (GtkWidget *w, GuppiData *data)
{
GtkWidget *win;
GtkWidget *box;
GtkWidget *info;
GtkWidget *close_button;
win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (win), "Data Information");
info = guppi_data_info_display (data);
if (info == NULL)
info = gtk_label_new (_("No information available."));
box = gtk_vbox_new (FALSE, 2);
gtk_box_pack_start (GTK_BOX (box), info, TRUE, TRUE, 2);
gtk_box_pack_start (GTK_BOX (box), gtk_hseparator_new (),
FALSE, TRUE, 3);
close_button = gnome_stock_button (GNOME_STOCK_BUTTON_CLOSE);
gtk_box_pack_start (GTK_BOX (box), close_button, FALSE, FALSE, 2);
gtk_container_add (GTK_CONTAINER (win), box);
gtk_signal_connect_object (GTK_OBJECT (close_button),
"clicked",
GTK_SIGNAL_FUNC (gtk_widget_destroy),
GTK_OBJECT (win));
gtk_widget_show_all (win);
}
struct save_info {
GtkFileSelection *fs;
GuppiData *data;
};
static void
save_info_free (struct save_info *si)
{
gtk_widget_destroy (GTK_WIDGET (si->fs));
guppi_unref (si->data);
guppi_free (si);
}
static void
save_ok_cb (GtkWidget *w, gpointer user_data)
{
struct save_info *si = (struct save_info *)user_data;
GuppiXMLDocument *doc;
gchar *filename;
filename = gtk_file_selection_get_filename (si->fs);
doc = guppi_xml_document_new ();
guppi_xml_document_set_root (doc, guppi_data_export_xml (si->data, doc));
guppi_xml_document_write_file (doc, filename);
guppi_xml_document_free (doc);
save_info_free (si);
}
static void
save_cancel_cb (GtkWidget *w, gpointer user_data)
{
struct save_info *si = (struct save_info *)user_data;
save_info_free (si);
}
static gboolean
save_delete_event_cb (GtkWidget *w, GdkEvent *ev, gpointer user_data)
{
struct save_info *si = (struct save_info *)user_data;
save_info_free (si);
return TRUE;
}
static void
data_save_cb (GtkWidget *w, GuppiData *data)
{
GtkWidget *fs;
gchar *s;
gchar *tmp;
gchar *filename;
struct save_info *si;
s = guppi_strdup_printf (_("Save \"%s\""), guppi_data_get_label (data));
fs = gtk_file_selection_new (s);
guppi_free (s);
si = guppi_new0 (struct save_info, 1);
si->fs = GTK_FILE_SELECTION (fs);
si->data = data;
guppi_ref (data);
tmp = guppi_string_canonize_filename (guppi_data_get_label (data));
filename = guppi_strdup_printf ("%s.gpi", tmp);
guppi_free (tmp);
gtk_file_selection_set_filename (si->fs, filename);
guppi_free (filename);
gtk_signal_connect (GTK_OBJECT (si->fs->ok_button),
"clicked",
GTK_SIGNAL_FUNC (save_ok_cb),
si);
gtk_signal_connect (GTK_OBJECT (si->fs->cancel_button),
"clicked",
GTK_SIGNAL_FUNC (save_cancel_cb),
si);
gtk_signal_connect (GTK_OBJECT (fs),
"delete_event",
GTK_SIGNAL_FUNC (save_delete_event_cb),
si);
gtk_widget_show_all (fs);
}
#if 0
static void
data_delete_cb (GtkWidget *w, GuppiData *data)
{
GuppiDataTree *tree;
tree = GUPPI_DATA_TREE (gtk_object_get_data (GTK_OBJECT (w), "tree"));
guppi_data_tree_remove (tree, data);
}
static void
data_copy_cb (GtkWidget *w, GuppiData *data)
{
GuppiData *copy;
GuppiDataTree *tree;
copy = guppi_data_copy (data);
if (copy == NULL) {
guppi_warning_dialog ("Can't copy \"%s\"", guppi_data_get_label (data));
} else {
tree = GUPPI_DATA_TREE (gtk_object_get_data (GTK_OBJECT (w), "tree"));
guppi_data_tree_add (tree, copy);
}
}
static void
data_transform_cb (GtkWidget *w, GuppiData *data)
{
GuppiDataTransform *xform;
GuppiDataTree *tree;
GuppiData *result;
xform =
GUPPI_DATA_TRANSFORM (gtk_object_get_data (GTK_OBJECT (w), "xform"));
tree = GUPPI_DATA_TREE (gtk_object_get_data (GTK_OBJECT (w), "tree"));
result = guppi_data_transform_process (xform, data);
if (result)
guppi_data_tree_add_beside (tree, data, result);
}
#endif
static void
build_menu (GuppiData *data, GtkMenu *menu, gpointer data_tree)
{
GtkWidget *mi;
GuppiDataClass *klass;
GList *xforms;
GList *iter;
g_return_if_fail (data && GUPPI_IS_DATA (data));
g_return_if_fail (menu && GTK_IS_MENU (menu));
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
/* Need to hook up signals... */
if (klass->info_display) {
mi = gtk_menu_item_new_with_label (_("Information"));
gtk_menu_append (menu, mi);
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (data_info_cb),
data);
gtk_widget_show (mi);
}
mi = gtk_menu_item_new_with_label (_("Rename"));
gtk_menu_append (menu, mi);
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (rename_cb),
data);
gtk_widget_show (mi);
#if 0
mi = gtk_menu_item_new_with_label (_("Save"));
gtk_menu_append (menu, mi);
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (data_save_cb),
data);
gtk_widget_show (mi);
mi = gtk_menu_item_new_with_label (_("Delete"));
gtk_object_set_data (GTK_OBJECT (mi), "tree", data_tree);
gtk_menu_append (menu, mi);
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (data_delete_cb),
data);
gtk_widget_show (mi);
mi = gtk_menu_item_new_with_label (_("Copy"));
gtk_object_set_data (GTK_OBJECT (mi), "tree", data_tree);
gtk_menu_append (menu, mi);
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (data_copy_cb),
data);
gtk_widget_show (mi);
#endif
#if 0
xforms = iter = guppi_data_transforms_find_supported (data);
if (xforms) {
GtkMenu *xmenu = GTK_MENU (gtk_menu_new ());
while (iter) {
GuppiDataTransform *xform = GUPPI_DATA_TRANSFORM (iter->data);
mi = gtk_menu_item_new_with_label (xform->name);
gtk_object_set_data (GTK_OBJECT (mi), "xform", xform);
gtk_object_set_data (GTK_OBJECT (mi), "tree", data_tree);
gtk_signal_connect (GTK_OBJECT (mi),
"activate",
GTK_SIGNAL_FUNC (data_transform_cb),
data);
gtk_menu_append (xmenu, mi);
gtk_widget_show (mi);
iter = g_list_next (iter);
}
g_list_free (xforms);
mi = gtk_menu_item_new_with_label (_("Copy & Transform"));
gtk_menu_item_set_submenu (GTK_MENU_ITEM (mi), GTK_WIDGET (xmenu));
gtk_widget_show (GTK_WIDGET (xmenu));
gtk_menu_append (menu, mi);
gtk_widget_show (mi);
}
#endif
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
/**
* guppi_data_info_display
* @data: A #GuppiData object.
*
* Returns: a widget containing useful human-readable information about
* #data.
*/
GtkWidget *
guppi_data_info_display (GuppiData *data)
{
GuppiDataClass *klass;
GtkWidget *w = NULL;
GtkWidget *frame;
GtkWidget *box = NULL;
g_return_val_if_fail (data && GUPPI_IS_DATA (data), NULL);
klass = GUPPI_DATA_CLASS (GTK_OBJECT (data)->klass);
if (klass->info_display)
w = klass->info_display (data);
if (w == NULL)
return NULL;
frame = gtk_frame_new (guppi_data_get_label (data));
box = gtk_vbox_new (FALSE, 2);
gtk_container_add (GTK_CONTAINER (frame), box);
if (w)
gtk_box_pack_start (GTK_BOX (box), w, TRUE, TRUE, 0);
return frame;
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static void
guppi_data_finalize (GtkObject *obj)
{
GuppiData *gd = GUPPI_DATA (obj);
guppi_finalized (obj);
/* We should never die with pending operations! */
g_assert (gd->pending_ops == NULL);
guppi_free0 (gd->label);
if (parent_class->finalize)
parent_class->finalize (obj);
}
static gboolean
validate_class (GuppiDataClass *klass)
{
gboolean ok = TRUE;
if (klass->copy == NULL) {
g_warning ("Method GuppiData::copy not defined.");
ok = FALSE;
}
if (klass->get_size_in_bytes == NULL) {
g_warning ("Method GuppiData::get_size_in_bytes not defined.");
ok = FALSE;
}
if (klass->get_size_info == NULL) {
g_warning ("Method GuppiData::get_size_info not defined.");
ok = FALSE;
}
return ok;
}
/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */
static void
guppi_data_class_init (GuppiDataClass *klass)
{
GtkObjectClass *object_class = (GtkObjectClass *) klass;
parent_class = gtk_type_class (GTK_TYPE_OBJECT);
klass->changed = changed;
klass->changed_label = changed_label;
klass->changed_subdata = changed_subdata;
klass->build_menu = build_menu;
klass->validate_class = validate_class;
data_signals[CHANGED] =
gtk_signal_new ("changed",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (GuppiDataClass, changed),
gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
data_signals[CHANGED_LABEL] =
gtk_signal_new ("changed_label",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (GuppiDataClass, changed_label),
gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
data_signals[CHANGED_SUBDATA] =
gtk_signal_new ("changed_subdata",
GTK_RUN_LAST,
object_class->type,
GTK_SIGNAL_OFFSET (GuppiDataClass, changed_subdata),
gtk_marshal_NONE__NONE,
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class, data_signals, LAST_SIGNAL);
object_class->finalize = guppi_data_finalize;
}
static void
guppi_data_init (GuppiData *gd)
{
gd->id = guppi_unique_id ();
gd->label = guppi_strdup (_("Unlabled"));
gd->read_only = FALSE;
}
GtkType
guppi_data_get_type (void)
{
static GtkType guppi_data_type = 0;
if (!guppi_data_type) {
static const GtkTypeInfo guppi_data_info = {
"GuppiData",
sizeof (GuppiData),
sizeof (GuppiDataClass),
(GtkClassInitFunc) guppi_data_class_init,
(GtkObjectInitFunc) guppi_data_init,
NULL, NULL, (GtkClassInitFunc) NULL
};
guppi_data_type = gtk_type_unique (GTK_TYPE_OBJECT, &guppi_data_info);
}
return guppi_data_type;
}
/* $Id: guppi-data.c,v 1.44 2001/11/19 05:40:40 trow Exp $ */
syntax highlighted by Code2HTML, v. 0.9.1