/* This is -*- C -*- */
/* vim: set sw=2: */
/* $Id: guppi-config-model.c,v 1.2 2001/11/26 20:00:18 trow Exp $ */

/*
 * guppi-config-model.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-memory.h>
#include <guppi-paths.h>
#include <guppi-attribute-widget.h>
#include "guppi-config-model.h"

static GtkObjectClass *parent_class = NULL;

enum {
  LAST_SIGNAL
};

static guint guppi_config_model_signals[LAST_SIGNAL] = { 0 };

struct _GuppiConfigModelPrivate {
  GList *items;
};

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

typedef struct _ConfigItem ConfigItem;
struct _ConfigItem {
  gchar *major_label;
  gchar *minor_label;
  GuppiConfigType type;
  GuppiAttributeBag *bag;
  GuppiConfigFn config_fn;
  gpointer config_closure;
  GtkDestroyNotify config_closure_destructor;
};

static ConfigItem *
config_item_new (void)
{
  return guppi_new0 (ConfigItem, 1);
}

static void
config_item_free (ConfigItem *ci)
{
  if (ci == NULL)
    return;

  guppi_free (ci->major_label);
  guppi_free (ci->minor_label);
  guppi_unref (ci->bag);
  if (ci->config_closure_destructor)
    ci->config_closure_destructor (ci->config_closure);

  guppi_free (ci);
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

static void
guppi_config_model_finalize (GtkObject *obj)
{
  GuppiConfigModel *x = GUPPI_CONFIG_MODEL(obj);

  g_list_foreach (x->priv->items, (GFunc) config_item_free, NULL);
  g_list_free (x->priv->items);

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

  guppi_finalized (obj);

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

static void
guppi_config_model_class_init (GuppiConfigModelClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *)klass;

  parent_class = gtk_type_class (GTK_TYPE_OBJECT);

  object_class->finalize = guppi_config_model_finalize;

#if 0
  /* Signal definition template */
  guppi_config_model_signals[CHANGED] =
    gtk_signal_new ("changed",
                    GTK_RUN_FIRST,
                    object_class->type,
                    GTK_SIGNAL_OFFSET (GuppiConfigModelClass, changed),
                    gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0);
#endif

  gtk_object_class_add_signals (object_class, guppi_config_model_signals,
                                LAST_SIGNAL);
}

static void
guppi_config_model_init (GuppiConfigModel *obj)
{
  obj->priv = g_new0 (GuppiConfigModelPrivate, 1);

}

GtkType
guppi_config_model_get_type (void)
{
  static GtkType guppi_config_model_type = 0;
  if (!guppi_config_model_type) {
    static const GtkTypeInfo guppi_config_model_info = {
      "GuppiConfigModel",
      sizeof (GuppiConfigModel),
      sizeof (GuppiConfigModelClass),
      (GtkClassInitFunc)guppi_config_model_class_init,
      (GtkObjectInitFunc)guppi_config_model_init,
      NULL, NULL, (GtkClassInitFunc)NULL
    };
    guppi_config_model_type = gtk_type_unique (GTK_TYPE_OBJECT, &guppi_config_model_info);
  }
  return guppi_config_model_type;
}

GuppiConfigModel *
guppi_config_model_new (void)
{
  return GUPPI_CONFIG_MODEL (guppi_type_new (guppi_config_model_get_type ()));
}

void
guppi_config_model_add (GuppiConfigModel *model,
			const gchar *major_label, const gchar *minor_label,
			GuppiConfigType type,
			GuppiAttributeBag *bag,
			GuppiConfigFn config_fn, gpointer config_closure,
			GtkDestroyNotify config_closure_destructor)
{
  ConfigItem *ci;

  g_return_if_fail (GUPPI_IS_CONFIG_MODEL (model));
  g_return_if_fail (major_label != NULL && minor_label != NULL);
  g_return_if_fail (bag == NULL || GUPPI_IS_ATTRIBUTE_BAG (bag));

  ci              = config_item_new ();
  ci->major_label = guppi_strdup (major_label);
  ci->minor_label = guppi_strdup (minor_label);
  ci->bag         = bag;
  ci->type        = type;
  ci->config_fn   = config_fn;
  
  ci->config_closure            = config_closure;
  ci->config_closure_destructor = config_closure_destructor;

  guppi_ref (ci->bag);

  model->priv->items = g_list_append (model->priv->items, ci);
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

typedef struct _GladeInfo GladeInfo;
struct _GladeInfo {
  gchar             *filename;
  gchar             *root;
  void             (*glade_init) (GladeXML *, gpointer);
  gpointer           glade_init_closure;
  GtkDestroyNotify   glade_init_closure_destroy;
};

static void
glade_info_free (GladeInfo *info)
{
  guppi_free (info->filename);
  guppi_free (info->root);
  if (info->glade_init_closure_destroy)
    info->glade_init_closure_destroy (info->glade_init_closure);
  guppi_free (info);
}

static GtkWidget *
glade_info_cb (gpointer closure)
{
  GladeInfo *info = closure;
  GladeXML *glade;
  GtkWidget *w;

  glade = glade_xml_new (guppi_glade_path (info->filename), info->root);
  if (glade == NULL)
    return NULL;

  if (info->glade_init)
    info->glade_init (glade, info->glade_init_closure);

  w = glade_xml_get_widget (glade, info->root);
  gtk_object_unref (GTK_OBJECT (glade));

  return w;
  
}

void
guppi_config_model_add_glade_file (GuppiConfigModel *model,
				   const gchar *major_label, const gchar *minor_label,
				   GuppiConfigType type, GuppiAttributeBag *bag,
				   const gchar *filename, const gchar *root,
				   void (*glade_init) (GladeXML *, gpointer),
				   gpointer glade_init_closure,
				   GtkDestroyNotify glade_init_closure_destroy)
{
  GladeInfo *info;

  g_return_if_fail (GUPPI_IS_CONFIG_MODEL (model));
  g_return_if_fail (major_label != NULL && minor_label != NULL);
  g_return_if_fail (bag == NULL || GUPPI_IS_ATTRIBUTE_BAG (bag));

  info = guppi_new0 (GladeInfo, 1);

  info->filename                   = guppi_strdup (filename);
  info->root                       = guppi_strdup (root);
  info->glade_init                 = glade_init;
  info->glade_init_closure         = glade_init_closure;
  info->glade_init_closure_destroy = glade_init_closure_destroy;

  guppi_config_model_add (model, major_label, minor_label, type, bag,
			  glade_info_cb, info,
			  (GtkDestroyNotify) glade_info_free);
}

/* ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** */

void
guppi_config_model_combine (GuppiConfigModel *dest,
			    const gchar *major_label_override,
			    GuppiConfigModel *src)
{
  GList *iter;

  g_return_if_fail (GUPPI_IS_CONFIG_MODEL (dest));
  if (src == NULL)
    return;
  g_return_if_fail (GUPPI_IS_CONFIG_MODEL (src));

  for (iter = src->priv->items; iter != NULL; iter = g_list_next (iter)) {
    ConfigItem *ci = iter->data;
    if (major_label_override) {
      guppi_free (ci->major_label);
      ci->major_label = guppi_strdup (major_label_override);
    }
    dest->priv->items = g_list_append (dest->priv->items, ci);
  }
  g_list_free (src->priv->items);
  src->priv->items = NULL;
}

void
guppi_config_model_foreach (GuppiConfigModel *model,
			    GuppiConfigIteratorFn iter_fn,
			    gpointer closure)
{
  GList *iter;

  g_return_if_fail (GUPPI_IS_CONFIG_MODEL (model));
  g_return_if_fail (iter_fn != NULL);

  for (iter = model->priv->items; iter != NULL; iter = g_list_next (iter)) {
    ConfigItem *ci = iter->data;
    GtkWidget *w = NULL;
    if (ci->config_fn)
      w = ci->config_fn (ci->config_closure);
    if (w && ci->bag)
      guppi_attribute_widget_recursively_attach_bag (w, ci->bag);
    iter_fn (ci->major_label, ci->minor_label, ci->type, w, closure);
  }
}


syntax highlighted by Code2HTML, v. 0.9.1