Moved chart loading into ag_chart_load_from_file(), where it was intended to be
This commit is contained in:
		
							
								
								
									
										179
									
								
								src/ag-app.c
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								src/ag-app.c
									
									
									
									
									
								
							| @@ -1,20 +1,10 @@ | ||||
| #include <glib/gi18n.h> | ||||
| #include <libxml/parser.h> | ||||
| #include <libxml/xpath.h> | ||||
| #include <errno.h> | ||||
|  | ||||
| #include "ag-app.h" | ||||
| #include "ag-window.h" | ||||
| #include "ag-chart.h" | ||||
| #include "config.h" | ||||
| #include "astrognome.h" | ||||
|  | ||||
| typedef enum { | ||||
|     XML_CONVERT_STRING, | ||||
|     XML_CONVERT_DOUBLE, | ||||
|     XML_CONVERT_INT | ||||
| } XmlConvertType; | ||||
|  | ||||
| struct _AgAppPrivate { | ||||
| }; | ||||
|  | ||||
| @@ -114,182 +104,17 @@ quit_cb(GSimpleAction *action, GVariant *parameter, gpointer user_data) | ||||
|     } | ||||
| } | ||||
|  | ||||
| GVariant * | ||||
| get_by_xpath(xmlXPathContextPtr ctx, const gchar *xpath, XmlConvertType type) | ||||
| { | ||||
|     xmlXPathObjectPtr xpathObj; | ||||
|     const gchar *text; | ||||
|     char *endptr; | ||||
|     GVariant *ret = NULL; | ||||
|     gdouble d; | ||||
|     gint i; | ||||
|  | ||||
|     if ((xpathObj = xmlXPathEvalExpression((const xmlChar *)xpath, ctx)) == NULL) { | ||||
|         // TODO: Warn with a popup or similar way | ||||
|         g_warning("Could not initialize XPath"); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (xpathObj->nodesetval == NULL) { | ||||
|         // TODO: Warn with a popup or similar way | ||||
|         g_warning("Required element not found. This is not a valid save file!"); | ||||
|         xmlXPathFreeObject(xpathObj); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (xpathObj->nodesetval->nodeNr > 1) { | ||||
|         // TODO: Warn with a popup or similar way | ||||
|         g_warning("Too many elements. This is not a valid save file!"); | ||||
|         xmlXPathFreeObject(xpathObj); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     text = (const gchar *)xpathObj->nodesetval->nodeTab[0]->content; | ||||
|  | ||||
|     switch (type) { | ||||
|         case XML_CONVERT_STRING: | ||||
|             ret = g_variant_new_string(text); | ||||
|  | ||||
|             break; | ||||
|  | ||||
|         case XML_CONVERT_DOUBLE: | ||||
|             d = g_ascii_strtod(text, &endptr); | ||||
|  | ||||
|             if ((*endptr != 0) || (errno != 0)) { | ||||
|                 ret = NULL; | ||||
|             } else { | ||||
|                 ret = g_variant_new_double(d); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|  | ||||
|         case XML_CONVERT_INT: | ||||
|             i = strtol(text, &endptr, 10); | ||||
|  | ||||
|             if ((*endptr != 0) || (errno != 0)) { | ||||
|                 ret = NULL; | ||||
|             } else { | ||||
|                 ret = g_variant_new_int32(i); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     xmlXPathFreeObject(xpathObj); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static void | ||||
| ag_app_open_chart(AgApp *app, GFile *file) | ||||
| { | ||||
|     GError *err = NULL; | ||||
|     gchar *uri, | ||||
|           *xml; | ||||
|     guint length; | ||||
|     xmlDocPtr doc; | ||||
|     xmlXPathContextPtr xpathCtx; | ||||
|     GVariant *chart_name, | ||||
|              *country, | ||||
|              *city, | ||||
|              *longitude, | ||||
|              *latitude, | ||||
|              *altitude, | ||||
|              *year, | ||||
|              *month, | ||||
|              *day, | ||||
|              *hour, | ||||
|              *minute, | ||||
|              *second, | ||||
|              *timezone; | ||||
|     GtkWidget *window; | ||||
|     AgChart *chart; | ||||
|     GsweTimestamp *timestamp; | ||||
|  | ||||
|     uri = g_file_get_uri(file); | ||||
|  | ||||
|     if (!g_file_load_contents(file, NULL, &xml, &length, NULL, &err)) { | ||||
|         // TODO: Warn with a popup or similar way | ||||
|         g_warning("Could not open file '%s': %s", uri, err->message); | ||||
|         g_clear_error(&err); | ||||
|         g_free(uri); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if ((doc = xmlReadMemory(xml, length, "chart.xml", NULL, 0)) == NULL) { | ||||
|         // TODO: Warn with a popup or similar way | ||||
|         g_warning("Saved chart is corrupt (or not a saved chart at all)"); | ||||
|         g_free(xml); | ||||
|         g_free(uri); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if ((xpathCtx = xmlXPathNewContext(doc)) == NULL) { | ||||
|         // TODO: Warn with a popup or similar way | ||||
|         g_warning("Could not initialize XPath"); | ||||
|         xmlFreeDoc(doc); | ||||
|         g_free(xml); | ||||
|         g_free(uri); | ||||
|  | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     chart_name = get_by_xpath(xpathCtx, "/chartinfo/data/name/text()", XML_CONVERT_STRING); | ||||
|     country = get_by_xpath(xpathCtx, "/chartinfo/data/place/country/text()", XML_CONVERT_STRING); | ||||
|     city = get_by_xpath(xpathCtx, "/chartinfo/data/place/city/text()", XML_CONVERT_STRING); | ||||
|     longitude = get_by_xpath(xpathCtx, "/chartinfo/data/place/longitude/text()", XML_CONVERT_DOUBLE); | ||||
|     latitude = get_by_xpath(xpathCtx, "/chartinfo/data/place/latitude/text()", XML_CONVERT_DOUBLE); | ||||
|     altitude = get_by_xpath(xpathCtx, "/chartinfo/data/place/altitude/text()", XML_CONVERT_DOUBLE); | ||||
|     year = get_by_xpath(xpathCtx, "/chartinfo/data/time/year/text()", XML_CONVERT_INT); | ||||
|     month = get_by_xpath(xpathCtx, "/chartinfo/data/time/month/text()", XML_CONVERT_INT); | ||||
|     day = get_by_xpath(xpathCtx, "/chartinfo/data/time/day/text()", XML_CONVERT_INT); | ||||
|     hour = get_by_xpath(xpathCtx, "/chartinfo/data/time/hour/text()", XML_CONVERT_INT); | ||||
|     minute = get_by_xpath(xpathCtx, "/chartinfo/data/time/minute/text()", XML_CONVERT_INT); | ||||
|     second = get_by_xpath(xpathCtx, "/chartinfo/data/time/second/text()", XML_CONVERT_INT); | ||||
|     timezone = get_by_xpath(xpathCtx, "/chartinfo/data/time/timezone/text()", XML_CONVERT_DOUBLE); | ||||
|     GError *err = NULL; | ||||
|  | ||||
|     chart = ag_chart_load_from_file(file, &err); | ||||
|     window = ag_app_create_window(app); | ||||
|     timestamp = gswe_timestamp_new_from_gregorian_full( | ||||
|             g_variant_get_int32(year), | ||||
|             g_variant_get_int32(month), | ||||
|             g_variant_get_int32(day), | ||||
|             g_variant_get_int32(hour), | ||||
|             g_variant_get_int32(minute), | ||||
|             g_variant_get_int32(second), | ||||
|             0, | ||||
|             g_variant_get_double(timezone) | ||||
|         ); | ||||
|     // TODO: Make house system configurable (and saveable) | ||||
|     chart = ag_chart_new_full(timestamp, g_variant_get_double(longitude), g_variant_get_double(latitude), g_variant_get_double(altitude), GSWE_HOUSE_SYSTEM_PLACIDUS); | ||||
|     ag_chart_set_name(chart, g_variant_get_string(chart_name, NULL)); | ||||
|     ag_chart_set_country(chart, g_variant_get_string(country, NULL)); | ||||
|     ag_chart_set_city(chart, g_variant_get_string(city, NULL)); | ||||
|     ag_window_set_chart(AG_WINDOW(window), chart); | ||||
|     ag_window_update_from_chart(AG_WINDOW(window)); | ||||
|  | ||||
|     g_variant_unref(chart_name); | ||||
|     g_variant_unref(country); | ||||
|     g_variant_unref(city); | ||||
|     g_variant_unref(longitude); | ||||
|     g_variant_unref(latitude); | ||||
|     g_variant_unref(altitude); | ||||
|     g_variant_unref(year); | ||||
|     g_variant_unref(month); | ||||
|     g_variant_unref(day); | ||||
|     g_variant_unref(hour); | ||||
|     g_variant_unref(minute); | ||||
|     g_variant_unref(second); | ||||
|  | ||||
|     g_free(xml); | ||||
|     g_free(uri); | ||||
|     xmlXPathFreeContext(xpathCtx); | ||||
|     xmlFreeDoc(doc); | ||||
| } | ||||
|  | ||||
| static void | ||||
|   | ||||
							
								
								
									
										183
									
								
								src/ag-chart.c
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								src/ag-chart.c
									
									
									
									
									
								
							| @@ -1,3 +1,7 @@ | ||||
| #include <errno.h> | ||||
| #include <gio/gio.h> | ||||
| #include <libxml/parser.h> | ||||
| #include <libxml/xpath.h> | ||||
| #include <swe-glib.h> | ||||
|  | ||||
| #include "ag-chart.h" | ||||
| @@ -16,6 +20,12 @@ enum { | ||||
|     PROP_CITY | ||||
| }; | ||||
|  | ||||
| typedef enum { | ||||
|     XML_CONVERT_STRING, | ||||
|     XML_CONVERT_DOUBLE, | ||||
|     XML_CONVERT_INT | ||||
| } XmlConvertType; | ||||
|  | ||||
| G_DEFINE_QUARK(ag-chart-error-quark, ag_chart_error); | ||||
|  | ||||
| G_DEFINE_TYPE(AgChart, ag_chart, GSWE_TYPE_MOMENT); | ||||
| @@ -188,3 +198,176 @@ ag_chart_get_city(AgChart *chart) | ||||
|     return g_strdup(chart->priv->city); | ||||
| } | ||||
|  | ||||
| static GVariant * | ||||
| get_by_xpath(xmlXPathContextPtr xpath_context, const gchar *uri, const gchar *xpath, XmlConvertType type, GError **err) | ||||
| { | ||||
|     xmlXPathObjectPtr xpathObj; | ||||
|     const gchar *text; | ||||
|     char *endptr; | ||||
|     GVariant *ret = NULL; | ||||
|     gdouble d; | ||||
|     gint i; | ||||
|  | ||||
|     if ((xpathObj = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_context)) == NULL) { | ||||
|         g_set_error(err, AG_CHART_ERROR, AG_CHART_ERROR_LIBXML, "File '%s' could not be parsed due to internal XML error.", uri); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (xpathObj->nodesetval == NULL) { | ||||
|         g_set_error(err, AG_CHART_ERROR, AG_CHART_ERROR_CORRUPT_FILE, "File '%s' doesn't look like a valid saved chart.", uri); | ||||
|         xmlXPathFreeObject(xpathObj); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if (xpathObj->nodesetval->nodeNr > 1) { | ||||
|         g_set_error(err, AG_CHART_ERROR, AG_CHART_ERROR_CORRUPT_FILE, "File '%s' doesn't look like a valid saved chart.", uri); | ||||
|         xmlXPathFreeObject(xpathObj); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     text = (const gchar *)xpathObj->nodesetval->nodeTab[0]->content; | ||||
|  | ||||
|     switch (type) { | ||||
|         case XML_CONVERT_STRING: | ||||
|             ret = g_variant_new_string(text); | ||||
|  | ||||
|             break; | ||||
|  | ||||
|         case XML_CONVERT_DOUBLE: | ||||
|             d = g_ascii_strtod(text, &endptr); | ||||
|  | ||||
|             if ((*endptr != 0) || (errno != 0)) { | ||||
|                 g_set_error(err, AG_CHART_ERROR, AG_CHART_ERROR_CORRUPT_FILE, "File '%s' doesn't look like a valid saved chart.", uri); | ||||
|                 ret = NULL; | ||||
|             } else { | ||||
|                 ret = g_variant_new_double(d); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|  | ||||
|         case XML_CONVERT_INT: | ||||
|             i = strtol(text, &endptr, 10); | ||||
|  | ||||
|             if ((*endptr != 0) || (errno != 0)) { | ||||
|                 g_set_error(err, AG_CHART_ERROR, AG_CHART_ERROR_CORRUPT_FILE, "File '%s' doesn't look like a valid saved chart.", uri); | ||||
|                 ret = NULL; | ||||
|             } else { | ||||
|                 ret = g_variant_new_int32(i); | ||||
|             } | ||||
|  | ||||
|             break; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     xmlXPathFreeObject(xpathObj); | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| AgChart * | ||||
| ag_chart_load_from_file(GFile *file, GError **err) | ||||
| { | ||||
|     AgChart *chart = NULL; | ||||
|     gchar *uri, | ||||
|           *xml = NULL; | ||||
|     guint length; | ||||
|     xmlDocPtr doc; | ||||
|     xmlXPathContextPtr xpath_context; | ||||
|     GVariant *chart_name, | ||||
|              *country, | ||||
|              *city, | ||||
|              *longitude, | ||||
|              *latitude, | ||||
|              *altitude, | ||||
|              *year, | ||||
|              *month, | ||||
|              *day, | ||||
|              *hour, | ||||
|              *minute, | ||||
|              *second, | ||||
|              *timezone; | ||||
|     GsweTimestamp *timestamp; | ||||
|  | ||||
|     uri = g_file_get_uri(file); | ||||
|  | ||||
|     if (!g_file_load_contents(file, NULL, &xml, &length, NULL, err)) { | ||||
|         g_free(uri); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if ((doc = xmlReadMemory(xml, length, "chart.xml", NULL, 0)) == NULL) { | ||||
|         g_set_error(err, AG_CHART_ERROR, AG_CHART_ERROR_CORRUPT_FILE, "File '%s' can not be read. Maybe it is corrupt, or not a save file at all", uri); | ||||
|         g_free(xml); | ||||
|         g_free(uri); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     if ((xpath_context = xmlXPathNewContext(doc)) == NULL) { | ||||
|         g_set_error(err, AG_CHART_ERROR, AG_CHART_ERROR_LIBXML, "File '%s' could not be loaded due to internal LibXML error", uri); | ||||
|         xmlFreeDoc(doc); | ||||
|         g_free(xml); | ||||
|         g_free(uri); | ||||
|  | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     chart_name = get_by_xpath(xpath_context, uri, "/chartinfo/data/name/text()", XML_CONVERT_STRING, err); | ||||
|     country = get_by_xpath(xpath_context, uri, "/chartinfo/data/place/country/text()", XML_CONVERT_STRING, err); | ||||
|     city = get_by_xpath(xpath_context, uri, "/chartinfo/data/place/city/text()", XML_CONVERT_STRING, err); | ||||
|     longitude = get_by_xpath(xpath_context, uri, "/chartinfo/data/place/longitude/text()", XML_CONVERT_DOUBLE, err); | ||||
|     latitude = get_by_xpath(xpath_context, uri, "/chartinfo/data/place/latitude/text()", XML_CONVERT_DOUBLE, err); | ||||
|     altitude = get_by_xpath(xpath_context, uri, "/chartinfo/data/place/altitude/text()", XML_CONVERT_DOUBLE, err); | ||||
|     year = get_by_xpath(xpath_context, uri, "/chartinfo/data/time/year/text()", XML_CONVERT_INT, err); | ||||
|     month = get_by_xpath(xpath_context, uri, "/chartinfo/data/time/month/text()", XML_CONVERT_INT, err); | ||||
|     day = get_by_xpath(xpath_context, uri, "/chartinfo/data/time/day/text()", XML_CONVERT_INT, err); | ||||
|     hour = get_by_xpath(xpath_context, uri, "/chartinfo/data/time/hour/text()", XML_CONVERT_INT, err); | ||||
|     minute = get_by_xpath(xpath_context, uri, "/chartinfo/data/time/minute/text()", XML_CONVERT_INT, err); | ||||
|     second = get_by_xpath(xpath_context, uri, "/chartinfo/data/time/second/text()", XML_CONVERT_INT, err); | ||||
|     timezone = get_by_xpath(xpath_context, uri, "/chartinfo/data/time/timezone/text()", XML_CONVERT_DOUBLE, err); | ||||
|  | ||||
|     timestamp = gswe_timestamp_new_from_gregorian_full( | ||||
|             g_variant_get_int32(year), | ||||
|             g_variant_get_int32(month), | ||||
|             g_variant_get_int32(day), | ||||
|             g_variant_get_int32(hour), | ||||
|             g_variant_get_int32(minute), | ||||
|             g_variant_get_int32(second), | ||||
|             0, | ||||
|             g_variant_get_double(timezone) | ||||
|         ); | ||||
|     g_variant_unref(year); | ||||
|     g_variant_unref(month); | ||||
|     g_variant_unref(day); | ||||
|     g_variant_unref(hour); | ||||
|     g_variant_unref(minute); | ||||
|     g_variant_unref(second); | ||||
|     g_variant_unref(timezone); | ||||
|  | ||||
|     // TODO: Make house system configurable (and saveable) | ||||
|     chart = ag_chart_new_full(timestamp, g_variant_get_double(longitude), g_variant_get_double(latitude), g_variant_get_double(altitude), GSWE_HOUSE_SYSTEM_PLACIDUS); | ||||
|     g_variant_unref(longitude); | ||||
|     g_variant_unref(latitude); | ||||
|     g_variant_unref(altitude); | ||||
|  | ||||
|     ag_chart_set_name(chart, g_variant_get_string(chart_name, NULL)); | ||||
|     g_variant_unref(chart_name); | ||||
|  | ||||
|     ag_chart_set_country(chart, g_variant_get_string(country, NULL)); | ||||
|     g_variant_unref(country); | ||||
|  | ||||
|     ag_chart_set_city(chart, g_variant_get_string(city, NULL)); | ||||
|     g_variant_unref(city); | ||||
|  | ||||
|     g_free(xml); | ||||
|     g_free(uri); | ||||
|     xmlXPathFreeContext(xpath_context); | ||||
|     xmlFreeDoc(doc); | ||||
|  | ||||
|     return chart; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -33,8 +33,8 @@ struct _AgChartClass { | ||||
|  | ||||
| GType ag_chart_get_type(void) G_GNUC_CONST; | ||||
| AgChart *ag_chart_new_full(GsweTimestamp *timestamp, gdouble longitude, gdouble latitude, gdouble altitude, GsweHouseSystem house_system); | ||||
| AgChart *ag_chart_load_from_file(GFile *file, GError **err); | ||||
|  | ||||
| void ag_chart_load_from_file(const gchar *path, GError **err); | ||||
| void ag_chart_save_to_file(const gchar *path, GError **err); | ||||
|  | ||||
| void ag_chart_set_name(AgChart *chart, const gchar *name); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user