/* -*- 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 #include "guppi-gnumeric-vector.h" #include "guppi-gnumeric-graph.h" #include "GNOME_Gnumeric_Graph.h" #include #include #include #include #include #include #include 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; }