/* This is -*- C -*- */ /* vim: set sw=2: */ /* * guppi-date-series.c * * Copyright (C) 2000 EMC Capital Management, Inc. * Copyright (C) 2001 The Free Software Foundation * * Developed by Jon Trowbridge * * 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-date-series.h" #include #include #include #include #include #include static GtkObjectClass *parent_class = NULL; static void guppi_date_series_finalize (GtkObject *obj) { if (parent_class->finalize) parent_class->finalize (obj); } static xmlNodePtr export_xml_element (GuppiDateIndexed *dind, const GDate *dt, GuppiXMLDocument *doc) { double x; x = guppi_date_series_get (GUPPI_DATE_SERIES (dind), (GDate *)dt); return guppi_xml_new_text_nodef (doc, "scalar", "%g", x); } static gboolean import_xml_element (GuppiDateIndexed *dind, const GDate *dt, GuppiXMLDocument *doc, xmlNodePtr node) { gchar *s; if (strcmp (node->name, "scalar")) { g_warning ("improper element type \"%s\"", node->name); return FALSE; } s = xmlNodeListGetString (doc->doc, node->xmlChildrenNode, 1); guppi_date_series_set (GUPPI_DATE_SERIES (dind), (GDate *) dt, atof (s)); free (s); return TRUE; } static void guppi_date_series_class_init (GuppiDateSeriesClass *klass) { GtkObjectClass *object_class = (GtkObjectClass *)klass; GuppiDateIndexedClass *dind_class = GUPPI_DATE_INDEXED_CLASS (klass); parent_class = gtk_type_class (GUPPI_TYPE_DATE_INDEXED); object_class->finalize = guppi_date_series_finalize; dind_class->export_xml_element = export_xml_element; dind_class->import_xml_element = import_xml_element; } static void guppi_date_series_init (GuppiDateSeries *obj) { } GtkType guppi_date_series_get_type (void) { static GtkType guppi_date_series_type = 0; if (!guppi_date_series_type) { static const GtkTypeInfo guppi_date_series_info = { "GuppiDateSeries", sizeof (GuppiDateSeries), sizeof (GuppiDateSeriesClass), (GtkClassInitFunc)guppi_date_series_class_init, (GtkObjectInitFunc)guppi_date_series_init, NULL, NULL, (GtkClassInitFunc)NULL }; guppi_date_series_type = gtk_type_unique (GUPPI_TYPE_DATE_INDEXED, &guppi_date_series_info); } return guppi_date_series_type; } double guppi_date_series_get (GuppiDateSeries *ser, const GDate *dt) { GuppiDateSeriesClass *klass; g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0); g_return_val_if_fail (dt && g_date_valid ((GDate *)dt), 0); klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass); g_assert (klass->get); return klass->get (ser, dt); } void guppi_date_series_set (GuppiDateSeries *ser, const GDate *dt, double x) { GuppiDateSeriesClass *klass; g_return_if_fail (GUPPI_IS_DATE_SERIES (ser)); g_return_if_fail (guppi_data_can_change (GUPPI_DATA (ser))); g_return_if_fail (dt && g_date_valid ((GDate *) dt)); klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass); g_assert (klass->set); klass->set (ser, dt, x); } void guppi_date_series_unset (GuppiDateSeries *ser, const GDate *dt) { GuppiDateSeriesClass *klass; g_return_if_fail (GUPPI_IS_DATE_SERIES (ser)); g_return_if_fail (guppi_data_can_change (GUPPI_DATA (ser))); g_return_if_fail (dt && g_date_valid ((GDate *) dt)); klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass); g_assert (klass->unset); klass->unset (ser, dt); } gint guppi_date_series_get_many (GuppiDateSeries *ser, const GDate *base_date, gint count, double *buffer) { GuppiDateSeriesClass *klass; gint retval; GDate dt; gint j; g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0); g_return_val_if_fail (base_date && g_date_valid ((GDate *) base_date), 0); if (count == 0) return 0; g_return_val_if_fail (buffer, 0); klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass); if (klass->get_many && klass->get_many (ser, base_date, count, buffer, &retval)) return retval; dt = *base_date; j = 0; while (count && g_date_valid (&dt) && guppi_date_indexed_in_bounds (GUPPI_DATE_INDEXED (ser), &dt)) { if (guppi_date_indexed_valid (GUPPI_DATE_INDEXED (ser), &dt)) { buffer[j] = guppi_date_series_get (ser, &dt); ++j; if (count > 0) --count; else ++count; } if (count > 0) g_date_add_days (&dt, 1); else g_date_subtract_days (&dt, 1); } return j; } gint guppi_date_series_get_range (GuppiDateSeries *ser, const GDate *start_date, const GDate *end_date, double *buffer, gint bufsize) { g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0); g_return_val_if_fail (start_date && g_date_valid ((GDate *) start_date), 0); g_return_val_if_fail (end_date && g_date_valid ((GDate *) end_date), 0); if (bufsize == 0) return 0; g_return_val_if_fail (buffer, 0); return guppi_date_series_get_range_timecoded (ser, start_date, end_date, NULL, buffer, bufsize); } gint guppi_date_series_get_range_timecoded (GuppiDateSeries *ser, const GDate *start_date, const GDate *end_date, double *timecode, double *buffer, gint bufsize) { GuppiDateSeriesClass *klass; gint retval; GDate sd, ed, dt; gint j; g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0); g_return_val_if_fail (start_date && g_date_valid ((GDate *) start_date), 0); g_return_val_if_fail (end_date && g_date_valid ((GDate *) end_date), 0); if (bufsize == 0) return 0; g_return_val_if_fail (buffer || timecode, 0); sd = *start_date; ed = *end_date; guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &sd); guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &ed); if (g_date_gt (&sd, &ed)) { dt = sd; sd = ed; ed = sd; } klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass); /* Try to use an implementation-supplied method. */ if (klass->get_range && klass->get_range (ser, &sd, &ed, timecode, buffer, bufsize, &retval)) return retval; dt = sd; j = 0; if (!guppi_date_indexed_valid (GUPPI_DATE_INDEXED (ser), &dt)) guppi_date_indexed_incr (GUPPI_DATE_INDEXED (ser), &dt); while (g_date_lteq (&dt, &ed) && j < bufsize) { if (timecode) timecode[j] = g_date_julian (&dt); if (buffer) buffer[j] = guppi_date_series_get (ser, &dt); ++j; guppi_date_indexed_incr (GUPPI_DATE_INDEXED (ser), &dt); } return j; } gboolean guppi_date_series_get_bounds (GuppiDateSeries *ser, const GDate *start_date, const GDate *end_date, double *min, double *max) { GuppiDateSeriesClass *klass; gboolean retval; GDate sd, ed; double *buffer; gint i, N; double m, M; g_return_val_if_fail (GUPPI_IS_DATE_SERIES (ser), 0); g_return_val_if_fail (start_date && g_date_valid ((GDate *) start_date), 0); g_return_val_if_fail (end_date && g_date_valid ((GDate *) end_date), 0); klass = GUPPI_DATE_SERIES_CLASS (GTK_OBJECT (ser)->klass); sd = *start_date; ed = *end_date; guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &sd); guppi_date_indexed_clamp (GUPPI_DATE_INDEXED (ser), &ed); if (g_date_gt (&sd, &ed)) { GDate dt = sd; sd = ed; ed = dt; } /* Try to use an implementation-supplied method. */ if (klass->get_bounds && klass->get_bounds (ser, &sd, &ed, min, max, &retval)) return retval; N = (gint)g_date_julian (&ed) - (gint)g_date_julian (&ed) + 1; buffer = guppi_new (double, N); N = guppi_date_series_get_range (ser, start_date, end_date, buffer, N); if (N == 0) return FALSE; m = M = buffer[0]; for (i=1; i M) M = x; } if (min) *min = m; if (max) *max = M; guppi_free (buffer); return TRUE; }