/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* vim: set sw=8: */
/*
* guppi-gnumeric-vector.c: Handlers for sequence change notification.
*
* Copyright (C) 2000-2001 Jody Goldberg (jgoldberg@home.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-gnumeric-vector.h"
#include "guppi-gnumeric-graph.h"
#include "GNOME_Gnumeric_Graph.h"
#include <bonobo.h>
#include <gtk/gtkobject.h>
#include <guppi-seq-scalar.h>
#include <guppi-seq-scalar-core.h>
#include <guppi-seq-string.h>
#include <guppi-seq-string-core.h>
#include <guppi-useful.h>
struct _GupGnmVector {
GtkObject obj;
GNOME_Gnumeric_VectorType type;
GuppiSeqString *string_data;
GuppiSeqScalar *scalar_data;
long id;
gboolean initialized : 1;
gboolean activated : 1;
gboolean has_header : 1;
GSList *name_indicies;
CORBA_Object corba_obj; /* local CORBA object */
union {
POA_GNOME_Gnumeric_Scalar_Vector scalar;
POA_GNOME_Gnumeric_String_Vector string;
PortableServer_POA any;
} servant;
/* The remote server monitoring this series */
union {
GNOME_Gnumeric_Scalar_Vector scalar;
GNOME_Gnumeric_String_Vector string;
CORBA_Object any;
} subscriber;
};
typedef struct {
GtkObjectClass parent_class;
} GupGnmVectorClass;
#define GUP_GNM_VECTOR_CLASS(k) (GTK_CHECK_CLASS_CAST((k), GUP_GNM_VECTOR_TYPE, GupGnmVectorClass))
#define IS_GUP_GNM_VECTOR_CLASS(k) (GTK_CHECK_CLASS_TYPE ((k), GUP_GNM_VECTOR_TYPE))
#define SERVANT_TO_GUP_GNM_VECTOR(ptr) (GupGnmVector *)(((void *)ptr) - GTK_STRUCT_OFFSET(GupGnmVector, servant))
static GtkObjectClass *gup_gnm_vector_parent_class = NULL;
static POA_GNOME_Gnumeric_VectorSelection__vepv vector_selection_vepv;
static POA_GNOME_Gnumeric_Scalar_Vector__vepv scalar_vector_vepv;
static POA_GNOME_Gnumeric_String_Vector__vepv string_vector_vepv;
typedef struct {
GupGnmGraph *graph;
int indx;
} NameEntry;
void
gup_gnm_vector_mark_as_name (GupGnmVector *vector,
GupGnmGraph *graph, unsigned indx)
{
NameEntry *entry;
g_return_if_fail (IS_GUP_GNM_VECTOR (vector));
entry = guppi_new (NameEntry, 1);
entry->graph = graph;
entry->indx = indx;
vector->name_indicies = g_slist_prepend (vector->name_indicies, entry);
}
void
gup_gnm_vector_clear_names (GupGnmVector *vector,
GupGnmGraph *graph, unsigned indx)
{
GSList *ptr, *accum = NULL;
g_return_if_fail (IS_GUP_GNM_VECTOR (vector));
for (ptr = vector->name_indicies; ptr != NULL ; ptr = ptr->next) {
NameEntry *entry = ptr->data;
if ((graph == NULL || graph == entry->graph) &&
(indx < 0 || indx == entry->indx)) {
guppi_free (entry);
} else
accum = g_slist_prepend (accum, entry);
}
g_slist_free (vector->name_indicies);
vector->name_indicies = accum;
}
static void
gup_gnm_vector_update_names (GupGnmVector *vector, char const *name)
{
GSList *ptr = vector->name_indicies;
for (; ptr != NULL ; ptr = ptr->next) {
NameEntry const *entry = ptr->data;
gup_gnm_graph_store_series_name (entry->graph,
entry->indx,name);
}
}
static void
impl_vector_selection_selected (PortableServer_Servant servant,
const GNOME_Gnumeric_SeqPair * ranges,
CORBA_Environment * ev)
{
GupGnmVector *vector = SERVANT_TO_GUP_GNM_VECTOR (servant);
g_warning ("Guppi : VectorSelection::selected (%p) placeholder\n", vector);
}
static void
impl_scalar_vector_changed (PortableServer_Servant servant,
const CORBA_short start,
const GNOME_Gnumeric_Scalar_Seq *vals,
CORBA_Environment *ev)
{
GupGnmVector *vector = SERVANT_TO_GUP_GNM_VECTOR (servant);
ggd(1, printf ("Guppi : scalar changed %p\n", vector));
if (vector->scalar_data == NULL) {
vector->scalar_data = GUPPI_SEQ_SCALAR (guppi_seq_scalar_core_new ());
guppi_seq_scalar_append_many (vector->scalar_data,
vals->_buffer, sizeof(double), vals->_length);
} else
guppi_seq_scalar_set_many (vector->scalar_data, 0,
vals->_buffer, sizeof(double), vals->_length);
ggd(5, unsigned i; for (i = 0; i < vals->_length; i++)
printf ("scalar[%d] = %f\n", i, vals->_buffer[i]););
#if 0
/* TODO : What to do if someone uses a number as a name ?
* do we convert it to a string ? or just use the index as we do now.
*/
gup_gnm_vector_update_names (GupGnmVector *vector, char const *name)
#endif
}
static void
impl_string_vector_changed (PortableServer_Servant servant,
const CORBA_short start,
const GNOME_Gnumeric_String_Seq *vals,
CORBA_Environment *ev)
{
int i;
GupGnmVector *vector = SERVANT_TO_GUP_GNM_VECTOR (servant);
ggd(1, printf ("Guppi : string changed %p\n", vector));
/* TODO : Do we need a set_many */
i = vals->_length;
if (vector->string_data == NULL) {
vector->string_data = GUPPI_SEQ_STRING (guppi_seq_string_core_new ());
while (i-- > 0 )
guppi_seq_string_append (vector->string_data,
vals->_buffer[i]);
} else
while (i-- > 0 )
guppi_seq_string_set (vector->string_data,
i, vals->_buffer[i]);
gup_gnm_vector_update_names (vector, vals->_buffer[0]);
}
static void
gup_gnm_vector_corba_destroy (GupGnmVector *vector)
{
CORBA_Environment ev;
CORBA_exception_init (&ev);
if (vector->subscriber.any != CORBA_OBJECT_NIL) {
CORBA_Object_release(vector->subscriber.any, &ev);
if (ev._major != CORBA_NO_EXCEPTION) {
g_warning ("'%s' : while releasing a vector",
bonobo_exception_get_text (&ev));
}
}
if (vector->activated) {
PortableServer_ObjectId *oid;
PortableServer_POA poa = bonobo_poa ();
oid = PortableServer_POA_servant_to_id (poa,
&vector->servant.any, &ev);
PortableServer_POA_deactivate_object (poa, oid, &ev);
vector->activated = FALSE;
CORBA_free (oid);
g_return_if_fail (ev._major == CORBA_NO_EXCEPTION);
}
if (vector->initialized) {
switch (vector->type) {
case GNOME_Gnumeric_VECTOR_TYPE_SCALAR :
case GNOME_Gnumeric_VECTOR_TYPE_DATE :
POA_GNOME_Gnumeric_Scalar_Vector__fini (
&vector->servant.scalar, &ev);
break;
case GNOME_Gnumeric_VECTOR_TYPE_STRING :
POA_GNOME_Gnumeric_String_Vector__fini (
&vector->servant.string, &ev);
break;
default :
g_warning ("Should not be reached");
};
g_return_if_fail (ev._major == CORBA_NO_EXCEPTION);
}
CORBA_exception_free (&ev);
}
static void
gup_gnm_vector_destroy (GtkObject *obj)
{
GupGnmVector *vector = GUP_GNM_VECTOR (obj);
ggd(1, printf ("guppi : graph-vector destroy %p\n", obj));
if (vector->string_data != NULL) {
guppi_unref (GTK_OBJECT (vector->string_data));
vector->string_data = NULL;
}
if (vector->scalar_data != NULL) {
guppi_unref (GTK_OBJECT (vector->scalar_data));
vector->scalar_data = NULL;
}
gup_gnm_vector_clear_names (vector, NULL, -1);
gup_gnm_vector_corba_destroy (vector);
if (gup_gnm_vector_parent_class->destroy)
gup_gnm_vector_parent_class->destroy (obj);
}
static void
corba_implementation_classes_init (void)
{
static POA_GNOME_Gnumeric_VectorSelection__epv selection_epv;
static POA_GNOME_Gnumeric_Scalar_Vector__epv scalar_epv;
static POA_GNOME_Gnumeric_String_Vector__epv string_epv;
selection_epv.selected = &impl_vector_selection_selected;
vector_selection_vepv.GNOME_Gnumeric_VectorSelection_epv =
&selection_epv;
scalar_epv.changed = &impl_scalar_vector_changed;
scalar_vector_vepv.GNOME_Gnumeric_Scalar_Vector_epv =
&scalar_epv;
scalar_vector_vepv.GNOME_Gnumeric_VectorSelection_epv =
&selection_epv;
string_epv.changed = & impl_string_vector_changed;
string_vector_vepv.GNOME_Gnumeric_String_Vector_epv =
&string_epv;
string_vector_vepv.GNOME_Gnumeric_VectorSelection_epv =
&selection_epv;
}
static void
gup_gnm_vector_class_init (GtkObjectClass *object_class)
{
gup_gnm_vector_parent_class = gtk_type_class (gtk_object_get_type ());
object_class->destroy = &gup_gnm_vector_destroy;
corba_implementation_classes_init ();
}
static void
gup_gnm_vector_init (GtkObject *object)
{
GupGnmVector *vector = GUP_GNM_VECTOR (object);
vector->corba_obj = CORBA_OBJECT_NIL;
vector->subscriber.any = CORBA_OBJECT_NIL;
vector->activated = FALSE;
vector->initialized = FALSE;
vector->has_header = FALSE;
vector->name_indicies = NULL;
vector->string_data = NULL;
vector->scalar_data = NULL;
}
GtkType
gup_gnm_vector_get_type (void)
{
static GtkType type = 0;
if (!type) {
GtkTypeInfo info = {
"GupGnmVector",
sizeof (GupGnmVector),
sizeof (GupGnmVectorClass),
(GtkClassInitFunc) gup_gnm_vector_class_init,
(GtkObjectInitFunc) gup_gnm_vector_init,
NULL, /* reserved 1 */
NULL, /* reserved 2 */
(GtkClassInitFunc) NULL
};
type = gtk_type_unique (gtk_object_get_type (), &info);
}
return type;
}
static GupGnmVector *
gup_gnm_vector_corba_init (GupGnmVector *vector)
{
CORBA_Environment ev;
CORBA_exception_init (&ev);
switch (vector->type) {
case GNOME_Gnumeric_VECTOR_TYPE_SCALAR :
case GNOME_Gnumeric_VECTOR_TYPE_DATE :
vector->servant.scalar.vepv = &scalar_vector_vepv;
POA_GNOME_Gnumeric_Scalar_Vector__init (
&vector->servant.scalar, &ev);
break;
case GNOME_Gnumeric_VECTOR_TYPE_STRING :
vector->servant.string.vepv = &string_vector_vepv;
POA_GNOME_Gnumeric_String_Vector__init (
&vector->servant.string, &ev);
break;
default :
g_assert_not_reached ();
};
if (ev._major == CORBA_NO_EXCEPTION) {
PortableServer_ObjectId *oid;
PortableServer_POA poa = bonobo_poa ();
vector->initialized = TRUE;
oid = PortableServer_POA_activate_object (poa,
&vector->servant.any, &ev);
vector->activated = (ev._major == CORBA_NO_EXCEPTION);
vector->corba_obj = PortableServer_POA_servant_to_reference (poa,
&vector->servant.any, &ev);
CORBA_free (oid);
} else {
g_warning ("'%s' : while creating a vector",
bonobo_exception_get_text (&ev));
gtk_object_unref (GTK_OBJECT (vector));
vector = NULL;
}
CORBA_exception_free (&ev);
return vector;
}
GupGnmVector *
gup_gnm_vector_new (GNOME_Gnumeric_VectorSelection subscriber,
GNOME_Gnumeric_VectorType type,
GNOME_Gnumeric_VectorID id)
{
GupGnmVector *vector = NULL;
CORBA_Environment ev;
CORBA_Object dup;
CORBA_exception_init (&ev);
dup = CORBA_Object_duplicate (subscriber, &ev);
if (ev._major == CORBA_NO_EXCEPTION) {
vector = guppi_type_new (gup_gnm_vector_get_type ());
vector->subscriber.any = dup;
vector->id = id;
vector->type = type;
ggd(2, printf ("Guppi : new vector (type = %d, id = %d) = %p\n", type, id, vector));
vector = gup_gnm_vector_corba_init (vector);
} else {
g_warning ("'%s' : while initializing vector %p",
bonobo_exception_get_text (&ev), vector);
}
CORBA_exception_free (&ev);
return vector;
}
/****************************************************************************/
GuppiSeqScalar *
gup_gnm_vector_get_scalar (GupGnmVector *vector)
{
g_return_val_if_fail (IS_GUP_GNM_VECTOR (vector), NULL);
if (vector->scalar_data == NULL) {
vector->scalar_data = GUPPI_SEQ_SCALAR (guppi_seq_scalar_core_new ());
if (vector->type != GNOME_Gnumeric_VECTOR_TYPE_STRING) {
GNOME_Gnumeric_Scalar_Seq *values;
CORBA_Environment ev;
CORBA_exception_init (&ev);
GNOME_Gnumeric_Scalar_Vector_value (vector->subscriber.scalar,
&values, &ev);
if (ev._major == CORBA_NO_EXCEPTION) {
ggd(1, printf ("Guppi : scalar load %p\n", vector));
ggd(5, unsigned i; for (i = 0; i < values->_length; i++)
printf ("scalar[%d] = %f\n", i, values->_buffer[i]););
guppi_seq_scalar_append_many (GUPPI_SEQ_SCALAR (vector->scalar_data),
values->_buffer, sizeof(double), values->_length);
CORBA_free (values);
} else {
guppi_unref0 (vector->scalar_data);
g_warning ("'%s' : while initializing vector with scalars %p",
bonobo_exception_get_text (&ev), vector);
}
CORBA_exception_free (&ev);
} else {
/* load the vector if necessary */
int i, n = guppi_seq_size (GUPPI_SEQ (gup_gnm_vector_get_string (vector)));
for (i = 0; i < n ; )
guppi_seq_scalar_append (GUPPI_SEQ_SCALAR (vector->scalar_data), ++i);
}
}
return vector->scalar_data;
}
/* One less that the Julian day number of 19000101. */
static int excel_date_origin = 0;
/*
* The serial number of 19000228. Excel allocates a serial number for
* the non-existing date 19000229.
*/
static const int excel_date_serial_19000228 = 59;
static void
excel_date_init (void)
{
/* Day 1 means 1st of January of 1900 */
GDate date;
g_date_set_dmy (&date, 1, 1, 1900);
excel_date_origin = g_date_julian (&date) - 1;
}
static gboolean
guppi_date_set_excel (GDate *dst, int serial)
{
if (excel_date_origin == 0)
excel_date_init ();
if (serial > excel_date_serial_19000228) {
if (serial == excel_date_serial_19000228 + 1)
g_warning ("Request for date 19000229.");
serial--;
}
serial += excel_date_origin;
if (! g_date_valid_julian (serial))
return FALSE;
g_date_set_julian (dst, serial);
return TRUE;
}
GuppiSeqString *
gup_gnm_vector_get_string (GupGnmVector *vector)
{
g_return_val_if_fail (IS_GUP_GNM_VECTOR (vector), NULL);
if (vector->string_data == NULL) {
vector->string_data = GUPPI_SEQ_STRING (guppi_seq_string_core_new ());
if (vector->type == GNOME_Gnumeric_VECTOR_TYPE_STRING) {
GNOME_Gnumeric_String_Seq *values;
CORBA_Environment ev;
int i;
CORBA_exception_init (&ev);
GNOME_Gnumeric_String_Vector_value (vector->subscriber.string,
&values, &ev);
if (ev._major == CORBA_NO_EXCEPTION) {
ggd(1, printf ("Guppi : string load %p\n", vector));
ggd(5, unsigned i; for (i = 0; i < values->_length; i++)
printf ("string[%d] = %s\n", i, values->_buffer[i]););
for (i = 0; i < values->_length; i++)
guppi_seq_string_append (vector->string_data,
values->_buffer [i]);
CORBA_free (values);
} else {
guppi_unref0 (vector->string_data);
g_warning ("'%s' : while initializing vector with strings %p",
bonobo_exception_get_text (&ev), vector);
}
CORBA_exception_free (&ev);
} else {
/* load the vector if necessary */
GuppiSeqScalar *scalars = gup_gnm_vector_get_scalar (vector);
int i, n = guppi_seq_size (GUPPI_SEQ (scalars));
gchar buf[32];
char *label;
double val;
GDate date;
for (i = 0; i < n ; i++) {
val = guppi_seq_scalar_get (scalars, i);
if (gup_gnm_vector_is_date (vector) &&
guppi_date_set_excel (&date, (int)floor (val + DBL_EPSILON))) {
g_date_strftime (buf, sizeof(buf), "%d %b %y", &date);
guppi_seq_string_append (vector->string_data, buf);
} else {
label = guppi_strdup_printf ("%g", val);
guppi_seq_string_append_nc (vector->string_data, label);
}
}
}
}
return vector->string_data;
}
CORBA_Object
gup_gnm_vector_servant_get (GupGnmVector *vector)
{
g_return_val_if_fail (IS_GUP_GNM_VECTOR (vector), CORBA_OBJECT_NIL);
return vector->corba_obj;
}
int
gup_gnm_vector_id_get (GupGnmVector const *vector)
{
g_return_val_if_fail (IS_GUP_GNM_VECTOR (vector), -1);
return vector->id;
}
gboolean
gup_gnm_vector_is_date (GupGnmVector const *vec)
{
g_return_val_if_fail (IS_GUP_GNM_VECTOR (vec), FALSE);
return vec->type == GNOME_Gnumeric_VECTOR_TYPE_DATE;
}
syntax highlighted by Code2HTML, v. 0.9.1