/* This is -*- C -*- */
/* $Id: guppi-object.c,v 1.2 2001/11/21 03:38:41 trow Exp $ */

/*
 * guppi-object.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-root-group-state.h>
#include <guppi-root-group-view.h>
#include <guppi-root-group-item.h>
#include <guppi-group-view-layout.h>
#include <guppi-memory.h>
#include "guppi-object.h"

#include "guppi-object-pie.h"
#include "guppi-object-barchart.h"
#include "guppi-object-scatter.h"
#include "guppi-object-title.h"


struct _GuppiObjectPrivate {
  double hsize, vsize;
  GuppiElementView *view;
};

static GtkObjectClass *parent_class = NULL;

static void
guppi_object_finalize (GtkObject *obj)
{
  GuppiObject *gobj = GUPPI_OBJECT (obj);
  GuppiObjectPrivate *p = gobj->priv;

  guppi_finalized (obj);

  guppi_unref0 (p->view);

  guppi_free (p);
  gobj->priv = NULL;

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

static void
guppi_object_class_init (GuppiObjectClass *klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;

  parent_class = gtk_type_class (GTK_TYPE_OBJECT);

  object_class->finalize = guppi_object_finalize;
}

static void
guppi_object_init (GuppiObject *obj)
{
  obj->priv = guppi_new0 (GuppiObjectPrivate, 1);
}

GtkType guppi_object_get_type (void)
{
  static GtkType guppi_object_type = 0;
  if (!guppi_object_type) {
    static const GtkTypeInfo guppi_object_info = {
      "GuppiObject",
      sizeof (GuppiObject),
      sizeof (GuppiObjectClass),
      (GtkClassInitFunc) guppi_object_class_init,
      (GtkObjectInitFunc) guppi_object_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_object_type = gtk_type_unique (GTK_TYPE_OBJECT, &guppi_object_info);
  }
  return guppi_object_type;
}

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

static GuppiObject *
typename2object (const gchar *type)
{
  GtkType obj_type = 0;

  g_return_val_if_fail (type, NULL);

  /* build up obj. */
  /* We'll obviously do something more clever later. */

  if (g_strcasecmp (type, "pie") == 0)
    obj_type = GUPPI_TYPE_OBJECT_PIE;
  else if (g_strcasecmp (type, "title") == 0)
    obj_type = GUPPI_TYPE_OBJECT_TITLE;
  else if (g_strcasecmp (type, "scatter") == 0)
    obj_type = GUPPI_TYPE_OBJECT_SCATTER;
  else if (g_strcasecmp (type, "barchart") == 0)
    obj_type = GUPPI_TYPE_OBJECT_BARCHART;

  return obj_type ? GUPPI_OBJECT (guppi_type_new (obj_type)) : NULL;
}

static void
object_build (GuppiObject *obj, double hsize, double vsize)
{
  GuppiObjectClass *klass;
  GuppiObjectPrivate *p;

  g_return_if_fail (obj);
  g_return_if_fail (hsize >= 0);
  g_return_if_fail (vsize >= 0);

  klass = GUPPI_OBJECT_CLASS (GTK_OBJECT (obj)->klass);
  if (klass->build == NULL) {
    g_warning ("Unable to build guppi-object.");
    return;
  }

  p = obj->priv;

  p->hsize = hsize;
  p->vsize = vsize;

  /* We want to own whatever gets created here, rather than any
     GuppiRootGroupView that it gets inserted into later. */
  p->view = klass->build (obj, hsize, vsize);
  guppi_ref (p->view);
  guppi_sink (p->view);
}
    

GuppiObject *
guppi_object_new (const gchar *type,
		  double hsize, double vsize,
		  const gchar *first_arg_name, ...)
{
  GuppiObject *obj;
  GSList *arg_list;
  GSList *info_list;
  gchar *error;
  va_list var_args;

  g_return_val_if_fail (type != NULL, NULL);
  g_return_val_if_fail (hsize >= 0, NULL);
  g_return_val_if_fail (vsize >= 0, NULL);

  obj = typename2object (type);

  if (obj == NULL) {
    g_warning ("Unknown guppi-object type: \"%s\"", type);
    return NULL;
  }

  /* Process the args */
  va_start (var_args, first_arg_name);
  error = gtk_object_args_collect (GTK_OBJECT_TYPE (obj),
				   &arg_list,
				   &info_list, first_arg_name, var_args);
  va_end (var_args);

  if (error) {
    g_warning ("Error processing guppi-object args: \"%s\"", error);
    return NULL;
  } else {
    GSList *slist_arg = arg_list;
    GSList *slist_info = info_list;

    while (slist_arg) {
      gtk_object_arg_set (GTK_OBJECT (obj), slist_arg->data,
			  slist_info->data);
      slist_arg = g_slist_next (slist_arg);
      slist_info = g_slist_next (slist_info);
    }
    gtk_args_collect_cleanup (arg_list, info_list);
  }

  object_build (obj, hsize, vsize);

  return obj;
}

GuppiObject *
guppi_object_newv (const gchar *type,
		   double hsize, double vsize,
		   guint N, GtkArg *args)
{
  GuppiObject *obj;

  g_return_val_if_fail (type != NULL, NULL);
  g_return_val_if_fail (hsize >= 0, NULL);
  g_return_val_if_fail (vsize >= 0, NULL);

  obj = typename2object (type);

  if (obj == NULL) {
    g_warning ("Unknown guppi-object type: \"%s\"", type);
    return NULL;
  }

  gtk_object_setv (GTK_OBJECT (obj), N, args);

  object_build (obj, hsize, vsize);

  return obj;
}

double
guppi_object_width (GuppiObject *obj)
{
  g_return_val_if_fail (obj && GUPPI_IS_OBJECT (obj), -1);

  return obj->priv->hsize;
}

double
guppi_object_height (GuppiObject *obj)
{
  g_return_val_if_fail (obj && GUPPI_IS_OBJECT (obj), -1);

  return obj->priv->vsize;
}

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

GtkWidget *
guppi_object_build_widget (GuppiObject *obj)
{
  GuppiElementView *view;
  GuppiElementState *root_state;
  GuppiElementView *root_view;
  GuppiCanvasItem *root_item;
  GnomeCanvas *canv;
  GtkWidget *wrapper;
  GuppiObjectClass *klass;

  g_return_val_if_fail (obj != NULL, NULL);
  g_return_val_if_fail (GUPPI_IS_OBJECT (obj), NULL);

  view = obj->priv->view;

  if (view == NULL) {
    g_warning ("Unable to build guppi-object widget: object uninitialized.");
    return NULL;
  }

  if (!GUPPI_IS_ELEMENT_VIEW (view)) {
    g_warning ("guppi-object has been corrupted.");
    return NULL;
  }

  root_state = guppi_root_group_state_new ();
  root_view = guppi_element_state_make_view (root_state);
  guppi_unref0 (root_state);

  guppi_group_view_layout_fill (GUPPI_GROUP_VIEW (root_view), view, 0, 0, 0, 0);

  canv = guppi_root_group_view_make_canvas (GUPPI_ROOT_GROUP_VIEW (root_view), &root_item);
  
  guppi_unref0 (root_view);

  guppi_root_group_item_set_resize_semantics (GUPPI_ROOT_GROUP_ITEM (root_item),
					      ROOT_GROUP_RESIZE_FILL_SPACE);
  
  klass = GUPPI_OBJECT_CLASS (GTK_OBJECT (obj)->klass);

  if (klass->item_init)
    klass->item_init (obj, (GnomeCanvasItem *) root_item);

  if (klass->widget_init)
    klass->widget_init (obj, GTK_WIDGET (canv));

  wrapper = gtk_hbox_new (FALSE, 0);
  gtk_box_pack_start (GTK_BOX (wrapper), GTK_WIDGET (canv), TRUE, TRUE, 0);
  gtk_widget_show (GTK_WIDGET (canv));

  /* Add a reference to the GuppiObject that goes away when the widget
     is destroyed. */
  guppi_ref (obj);
  gtk_signal_connect_object (GTK_OBJECT (wrapper),
			     "destroy",
			     GTK_SIGNAL_FUNC (guppi_unref_fn),
			     GTK_OBJECT (obj));

  return wrapper;
}

void
guppi_object_print (GuppiObject *obj, GnomePrintContext *pc)
{
  GuppiElementView *view;

  g_return_if_fail (obj != NULL);
  g_return_if_fail (GUPPI_IS_OBJECT (obj));

  g_return_if_fail (pc != NULL);
  g_return_if_fail (GNOME_IS_PRINT_CONTEXT (pc));

  view = obj->priv->view;

  if (view == NULL) {
    g_warning ("Uninitialized GuppiObject!");
    return;
  }

  if (!GUPPI_IS_ELEMENT_VIEW (view)) {
    g_warning ("guppi-object has been corrupted.");
    return;
  }

  guppi_element_view_print (view, pc);
}

gpointer
guppi_object_view (GuppiObject *obj)
{
  g_return_val_if_fail (obj != NULL && GUPPI_IS_OBJECT (obj), NULL);
  return obj->priv->view;
}

void
guppi_object_update(GuppiObject *obj)
{
  GuppiObjectClass *klass;
  
  g_return_if_fail (obj != NULL);
  g_return_if_fail (GUPPI_IS_OBJECT (obj));
  
  klass = GUPPI_OBJECT_CLASS (GTK_OBJECT (obj)->klass);
  
  if (klass->update) {
    (klass->update) (obj);
  } else {
    g_warning ("Update method not defined for a %s which is a GuppiObject descendant\n",
	      gtk_type_name (GTK_OBJECT_TYPE (GTK_OBJECT (obj))));
  }
}

/* $Id: guppi-object.c,v 1.2 2001/11/21 03:38:41 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1