diff options
author | Miika Turkia <miika.turkia@gmail.com> | 2013-03-24 10:00:25 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2013-03-24 06:37:56 -0700 |
commit | 12d5ab4ce31756999fc34a56c50f54dc585d8bbb (patch) | |
tree | d3d262c988ca6e5d6eb9436ae51032bb9bc47480 | |
parent | ca0ecc234adc8948e093f47feaf622435849f48a (diff) | |
download | subsurface-12d5ab4ce31756999fc34a56c50f54dc585d8bbb.tar.gz |
Export dives to UDDF file
This patch implements exporting dives from Subsurface to UDDF format.
Events and cylinder info are the most remarkable things still missing
from the export.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r-- | divelist.c | 95 | ||||
-rw-r--r-- | divelist.h | 1 | ||||
-rw-r--r-- | gtk-gui.c | 2 | ||||
-rw-r--r-- | xslt/uddf-export.xslt | 191 |
4 files changed, 289 insertions, 0 deletions
diff --git a/divelist.c b/divelist.c index c25ee6271..198e2d643 100644 --- a/divelist.c +++ b/divelist.c @@ -2102,6 +2102,92 @@ static void export_selected_dives_cb(GtkWidget *menuitem, GtkTreePath *path) } #endif +#if defined(XSLT) +static void export_dives_uddf(const gboolean selected) +{ + FILE *f; + char *filename = NULL; + size_t streamsize; + char *membuf; + xmlDoc *doc; + xsltStylesheetPtr xslt = NULL; + xmlDoc *transformed; + GtkWidget *dialog; + + dialog = gtk_file_chooser_dialog_new(_("Export As UDDF File"), + GTK_WINDOW(main_window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, + NULL); + gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); + } + gtk_widget_destroy(dialog); + + if (!filename) + return; + + /* Save XML to file and convert it into a memory buffer */ + save_dives_logic(filename, selected); + f = fopen(filename, "r"); + fseek(f, 0, SEEK_END); + streamsize = ftell(f); + rewind(f); + + membuf = malloc(streamsize + 1); + if (!membuf || !fread(membuf, streamsize, 1, f)) { + fprintf(stderr, "Failed to read memory buffer\n"); + return; + } + membuf[streamsize] = 0; + fclose(f); + g_unlink(filename); + + /* + * Parse the memory buffer into XML document and + * transform it to UDDF format, finally dumping + * the XML into a character buffer. + */ + doc = xmlReadMemory(membuf, strlen(membuf), "divelog", NULL, 0); + if (!doc) { + fprintf(stderr, "Failed to read XML memory\n"); + return; + } + free((void *)membuf); + + /* Convert to UDDF format */ + xslt = get_stylesheet("uddf-export.xslt"); + if (!xslt) { + fprintf(stderr, "Failed to open UDDF conversion stylesheet\n"); + return; + } + transformed = xsltApplyStylesheet(xslt, doc, NULL); + xsltFreeStylesheet(xslt); + xmlFreeDoc(doc); + + /* Write the transformed XML to file */ + f = g_fopen(filename, "w"); + xmlDocFormatDump(f, transformed, 1); + xmlFreeDoc(transformed); + + fclose(f); + g_free(filename); +} + +static void export_selected_dives_uddf_cb(GtkWidget *menuitem, GtkTreePath *path) +{ + export_dives_uddf(TRUE); +} + +void export_all_dives_uddf_cb() +{ + export_dives_uddf(FALSE); +} +#endif + static void merge_dive_index(int i, struct dive *a) { struct dive *b = get_dive(i+1); @@ -2171,6 +2257,9 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int char deleteplurallabel[] = N_("Delete dives"); char deletesinglelabel[] = N_("Delete dive"); char *deletelabel; +#if defined(XSLT) + char exportuddflabel[] = N_("Export dive(s) to UDDF"); +#endif #if defined(LIBZIP) && defined(XSLT) char exportlabel[] = N_("Export dive(s)"); #endif @@ -2247,6 +2336,12 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); #endif +#if defined(XSLT) + menuitem = gtk_menu_item_new_with_label(exportuddflabel); + g_signal_connect(menuitem, "activate", G_CALLBACK(export_selected_dives_uddf_cb), path); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); +#endif + menuitem = gtk_menu_item_new_with_label(editlabel); g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); diff --git a/divelist.h b/divelist.h index 47f79e278..856318e2d 100644 --- a/divelist.h +++ b/divelist.h @@ -15,4 +15,5 @@ extern void select_next_dive(void); extern void select_prev_dive(void); extern void show_and_select_dive(struct dive *dive); extern double init_decompression(struct dive * dive); +extern void export_all_dives_uddf_cb(); #endif @@ -1509,6 +1509,7 @@ static GtkActionEntry menu_items[] = { { "CloseFile", GTK_STOCK_CLOSE, N_("Close"), NULL, NULL, G_CALLBACK(file_close) }, { "Print", GTK_STOCK_PRINT, N_("Print..."), CTRLCHAR "P", NULL, G_CALLBACK(do_print) }, { "ImportFile", NULL, N_("Import File(s)..."), CTRLCHAR "I", NULL, G_CALLBACK(import_files) }, + { "ExportUDDF", NULL, N_("Export UDDF..."), NULL, NULL, G_CALLBACK(export_all_dives_uddf_cb) }, { "DownloadLog", NULL, N_("Download From Dive Computer..."), CTRLCHAR "D", NULL, G_CALLBACK(download_dialog) }, { "DownloadWeb", GTK_STOCK_CONNECT, N_("Download From Web Service..."), NULL, NULL, G_CALLBACK(webservice_download_dialog) }, { "AddDive", GTK_STOCK_ADD, N_("Add Dive..."), NULL, NULL, G_CALLBACK(add_dive_cb) }, @@ -1550,6 +1551,7 @@ static const gchar* ui_string = " \ <menuitem name=\"Close\" action=\"CloseFile\" /> \ <separator name=\"Separator1\"/> \ <menuitem name=\"Import XML File\" action=\"ImportFile\" /> \ + <menuitem name=\"Export to UDDF File\" action=\"ExportUDDF\" /> \ <separator name=\"Separator2\"/> \ <menuitem name=\"Print\" action=\"Print\" /> \ <separator name=\"Separator3\"/> \ diff --git a/xslt/uddf-export.xslt b/xslt/uddf-export.xslt new file mode 100644 index 000000000..107234ebf --- /dev/null +++ b/xslt/uddf-export.xslt @@ -0,0 +1,191 @@ +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:import href="commonTemplates.xsl"/> + <xsl:strip-space elements="*"/> + <xsl:output method="xml" encoding="utf-8" indent="yes"/> + + <xsl:template match="/divelog/dives"> + <uddf version="3.2.0"> + <generator> + <manufacturer id="subsurface"> + <name>Subsurface Team</name> + <contact>http://subsurface.hohndel.org/</contact> + </manufacturer> + <version> + <xsl:value-of select="/divelog/@version"/> + </version> + <xsl:if test="/divelog/generator/@date != ''"> + <datetime> + <xsl:value-of select="concat(/divelog/generator/@date, 'T', /divelog/generator/@time)"/> + </datetime> + </xsl:if> + </generator> + + <diver> + <owner id="1"> + <equipment> + <xsl:for-each select="/divelog/settings/divecomputerid"> + <divecomputer id="{./@deviceid}"> + <name> + <xsl:choose> + <xsl:when test="./@nickname != ''"> + <xsl:value-of select="./@nickname"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="./@model"/> + </xsl:otherwise> + </xsl:choose> + </name> + <model> + <xsl:value-of select="./@model"/> + </model> + </divecomputer> + </xsl:for-each> + </equipment> + </owner> + </diver> + + <!-- Gas definitions is not yet working, so it is commented out + --> + <xsl:if test="'asdf' = ''"> + <gasdefinitions> + <xsl:for-each select="dive/cylinder"> + <mix id="{generate-id(.)}"> + <name> + <xsl:value-of select="concat(./@o2, '/', ./he)"/> + </name> + <o2> + <xsl:value-of select="./@o2"/> + </o2> + <he> + <xsl:value-of select="./@he"/> + </he> + </mix> + </xsl:for-each> + </gasdefinitions> + </xsl:if> + + + <profiledata> + <xsl:for-each select="trip"> + <repetitiongroup id="{generate-id(.)}"> + <xsl:apply-templates select="dive"/> + </repetitiongroup> + </xsl:for-each> + <xsl:for-each select="dive"> + <repetitiongroup id="{generate-id(.)}"> + <xsl:apply-templates select="."/> + </repetitiongroup> + </xsl:for-each> + </profiledata> + </uddf> + </xsl:template> + + <xsl:template match="dive"> + <dive id="{generate-id(.)}"> + + <informationbeforedive> + <xsl:if test="node()/temperature/@air != ''"> + <airtemperature> + <xsl:value-of select="format-number(substring-before(node()/temperature/@air, ' ') + 273.15, '0.00')"/> + </airtemperature> + </xsl:if> + <datetime> + <xsl:value-of select="concat(./@date, 'T', ./@time)"/> + </datetime> + <divenumber> + <xsl:value-of select="./@number"/> + </divenumber> + </informationbeforedive> + + <samples> + <xsl:for-each select="./divecomputer[1]/sample"> + <waypoint> + <depth> + <xsl:value-of select="substring-before(./@depth, ' ')"/> + </depth> + <divetime> + <xsl:call-template name="time2sec"> + <xsl:with-param name="time"> + <xsl:value-of select="./@time"/> + </xsl:with-param> + </xsl:call-template> + </divetime> + <xsl:if test="./@pressure != ''"> + <tankpressure> + <xsl:value-of select="substring-before(./@pressure, ' ')"/> + </tankpressure> + </xsl:if> + <xsl:if test="./@temp != ''"> + <temperature> + <xsl:value-of select="format-number(substring-before(./@temp, ' ') + 273.15, '0.00')"/> + </temperature> + </xsl:if> + </waypoint> + </xsl:for-each> + </samples> + + <tankdata> + <xsl:if test="./cylinder[1]/@size"> + <tankvolume> + <xsl:value-of select="substring-before(./cylinder[1]/@size, ' ')"/> + </tankvolume> + </xsl:if> + <xsl:if test="./cylinder[1]/@start"> + <tankpressurebegin> + <xsl:value-of select="substring-before(./cylinder[1]/@start, ' ')"/> + </tankpressurebegin> + </xsl:if> + <xsl:if test="./cylinder[1]/@end"> + <tankpressureend> + <xsl:value-of select="substring-before(./cylinder[1]/@end, ' ')"/> + </tankpressureend> + </xsl:if> + </tankdata> + + <informationafterdive> + <xsl:if test="node()/depth/@max != ''"> + <greatestdepth> + <xsl:value-of select="substring-before(node()/depth/@max, ' ')"/> + </greatestdepth> + </xsl:if> + <xsl:if test="node()/depth/@mean != ''"> + <averagedepth> + <xsl:value-of select="substring-before(node()/depth/@mean, ' ')"/> + </averagedepth> + </xsl:if> + <xsl:if test="./@duration != ''"> + <diveduration> + <xsl:call-template name="time2sec"> + <xsl:with-param name="time"> + <xsl:value-of select="./@duration"/> + </xsl:with-param> + </xsl:call-template> + </diveduration> + </xsl:if> + <xsl:if test="node()/temperature/@water != ''"> + <lowesttemperature> + <xsl:value-of select="format-number(substring-before(node()/temperature/@water, ' ') + 273.15, '0.00')"/> + </lowesttemperature> + </xsl:if> + <notes> + <para> + <xsl:value-of select="notes"/> + </para> + </notes> + <rating> + <ratingvalue> + <xsl:choose> + <xsl:when test="./@rating = 0"> + <xsl:value-of select="'1'"/> + </xsl:when> + <xsl:when test="./@rating != ''"> + <xsl:value-of select="./@rating * 2"/> + </xsl:when> + </xsl:choose> + </ratingvalue> + </rating> + </informationafterdive> + + </dive> + </xsl:template> +</xsl:stylesheet> |