/* This is -*- C -*- */
/* vim: set sw=2: */
/* $Id: guppi-attribute-widget.c,v 1.1 2001/11/16 17:12:57 trow Exp $ */

/*
 * guppi-attribute-widget.c
 *
 * Copyright (C) 2001 The Free Software Foundation
 *
 * Developed by Jon Trowbridge <trow@gnu.org>
 *
 * 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-attribute-widget.h"

#include <gtk/gtksignal.h>
#include <guppi-memory.h>

static GtkObjectClass *parent_class = NULL;

enum {
  BAG_TO_WIDGET,
  LAST_SIGNAL
};

static guint guppi_attribute_widget_signals[LAST_SIGNAL] = { 0 };

struct _GuppiAttributeWidgetPrivate {
  gchar *key;
  GuppiAttributeFlavor flavor;
  gint set_lock;
  GuppiAttributeBag *bag;
  guint bag_changed_tag;
};

static void
guppi_attribute_widget_destroy (GtkObject *obj)
{
  if (parent_class->destroy)
    parent_class->destroy (obj);
}

static void
guppi_attribute_widget_finalize (GtkObject *obj)
{
  GuppiAttributeWidget *x = GUPPI_ATTRIBUTE_WIDGET(obj);

  guppi_free  (x->priv->key);

  if (x->priv->bag_changed_tag && x->priv->bag) {
    gtk_signal_disconnect (GTK_OBJECT (x->priv->bag), x->priv->bag_changed_tag);
  }
    
  guppi_unref (x->priv->bag);

  g_free (x->priv);
  x->priv = NULL;

  guppi_finalized (obj);

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

static void
guppi_attribute_widget_class_init (GuppiAttributeWidgetClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *)klass;

  parent_class = gtk_type_class (GTK_TYPE_TABLE);

  object_class->destroy = guppi_attribute_widget_destroy;
  object_class->finalize = guppi_attribute_widget_finalize;

  guppi_attribute_widget_signals[BAG_TO_WIDGET] =
    gtk_signal_new ("bag_to_widget",
		    GTK_RUN_FIRST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GuppiAttributeWidgetClass, bag_to_widget),
		    gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);

  gtk_object_class_add_signals (object_class, guppi_attribute_widget_signals, LAST_SIGNAL);

}

static void
guppi_attribute_widget_init (GuppiAttributeWidget *obj)
{
  GuppiAttributeWidgetPrivate *p = g_new0 (GuppiAttributeWidgetPrivate, 1);
  obj->priv = p;

}

GtkType
guppi_attribute_widget_get_type (void)
{
  static GtkType guppi_attribute_widget_type = 0;
  if (!guppi_attribute_widget_type) {
    static const GtkTypeInfo guppi_attribute_widget_info = {
      "GuppiAttributeWidget",
      sizeof (GuppiAttributeWidget),
      sizeof (GuppiAttributeWidgetClass),
      (GtkClassInitFunc)guppi_attribute_widget_class_init,
      (GtkObjectInitFunc)guppi_attribute_widget_init,
      NULL, NULL, (GtkClassInitFunc)NULL
    };
    guppi_attribute_widget_type = gtk_type_unique (GTK_TYPE_TABLE, &guppi_attribute_widget_info);
  }
  return guppi_attribute_widget_type;
}

static void
emit_bag_to_widget (GuppiAttributeWidget *gaw)
{
  gtk_signal_emit (GTK_OBJECT (gaw), guppi_attribute_widget_signals[BAG_TO_WIDGET]);
}

GtkWidget *
guppi_attribute_widget_new (GuppiAttributeFlavor flavor, const gchar *key)
{
  GtkWidget *w;
  g_return_val_if_fail (key && *key, NULL);

  w = GTK_WIDGET (guppi_type_new (guppi_attribute_widget_get_type ()));
  guppi_attribute_widget_construct (GUPPI_ATTRIBUTE_WIDGET (w), flavor, key);

  return w;
}

void
guppi_attribute_widget_construct (GuppiAttributeWidget *gaw, GuppiAttributeFlavor flavor, const gchar *key)
{
  g_return_if_fail (GUPPI_IS_ATTRIBUTE_WIDGET (gaw));
  g_return_if_fail (key != NULL);
  g_return_if_fail (gaw->priv->key == NULL);

  gaw->priv->key = guppi_strdup (key);
  gaw->priv->flavor = flavor;
}

static void
bag_changed_cb (GuppiAttributeBag *bag, const gchar *key, gpointer closure)
{
  GuppiAttributeWidget *gaw = GUPPI_ATTRIBUTE_WIDGET (closure);
  g_assert (gaw != NULL);

  if (gaw->priv->set_lock > 0)
    return;

  if (strcmp (key, gaw->priv->key))
    return;

  emit_bag_to_widget (gaw);
}

void
guppi_attribute_widget_attach_bag (GuppiAttributeWidget *gaw, GuppiAttributeBag *bag)
{
  GuppiAttributeFlavor bag_flavor;

  g_return_if_fail (GUPPI_IS_ATTRIBUTE_WIDGET (gaw));
  g_return_if_fail (GUPPI_IS_ATTRIBUTE_BAG (bag));
  g_return_if_fail (gaw->priv->bag == NULL);

  if (! guppi_attribute_bag_contains (bag, gaw->priv->key)) {
    g_warning ("Bag does not contain key '%s'", gaw->priv->key);
    return;
  }

  bag_flavor = guppi_attribute_bag_get_flavor (bag, gaw->priv->key);
  if (bag_flavor != gaw->priv->flavor) {
    g_message ("%d %d", bag_flavor, gaw->priv->flavor);
    g_warning ("Flavor mismatch on key '%s'", gaw->priv->key);
    return;
  }

  gaw->priv->bag = bag;
  guppi_ref (bag);

  gaw->priv->bag_changed_tag = gtk_signal_connect (GTK_OBJECT (bag),
						   "changed",
						   GTK_SIGNAL_FUNC (bag_changed_cb),
						   gaw);

  emit_bag_to_widget (gaw);
}

void
guppi_attribute_widget_recursively_attach_bag (GtkWidget *w, GuppiAttributeBag *bag)
{
  g_return_if_fail (GTK_IS_WIDGET (w));
  g_return_if_fail (GUPPI_IS_ATTRIBUTE_BAG (bag));

  if (GUPPI_IS_ATTRIBUTE_WIDGET (w)) {
    guppi_attribute_widget_attach_bag (GUPPI_ATTRIBUTE_WIDGET (w), bag);
  } else if (GTK_IS_CONTAINER (w)) {
    gtk_container_foreach (GTK_CONTAINER (w),
			   (GtkCallback) guppi_attribute_widget_recursively_attach_bag,
			   bag);
  }
}

void
guppi_attribute_widget_bag_get (GuppiAttributeWidget *gaw, const gchar *subkey, gpointer dest)
{
  gchar *key = NULL;

  g_return_if_fail (GUPPI_IS_ATTRIBUTE_WIDGET (gaw));
  g_return_if_fail (dest != NULL);

  if (gaw->priv->bag == NULL) {
    g_warning ("Getting without a bag.");
    return;
  }

  if (subkey && *subkey) {
    key = guppi_strdup_printf ("%s::%s", gaw->priv->key, subkey);
  }

  guppi_attribute_bag_get1 (gaw->priv->bag, key ? key : gaw->priv->key, dest);

  guppi_free (key);
}

void
guppi_attribute_widget_bag_set (GuppiAttributeWidget *gaw, const gchar *subkey, ...)
{
  gchar *key = NULL;
  va_list varargs;

  g_return_if_fail (GUPPI_IS_ATTRIBUTE_WIDGET (gaw));

  if (gaw->priv->bag == NULL) {
    g_warning ("Setting without a bag.");
    return;
  }

  if (subkey && *subkey) {
    key = guppi_strdup_printf ("%s::%s", gaw->priv->key, subkey);
  }

  va_start (varargs, subkey);
  ++gaw->priv->set_lock;
  guppi_attribute_bag_vset1 (gaw->priv->bag, key ? key : gaw->priv->key, &varargs);
  --gaw->priv->set_lock;
  va_end (varargs);

  guppi_free (key);
}



syntax highlighted by Code2HTML, v. 0.9.1