aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Miika Turkia <miika.turkia@gmail.com>2013-03-24 10:00:25 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2013-03-24 06:37:56 -0700
commit12d5ab4ce31756999fc34a56c50f54dc585d8bbb (patch)
treed3d262c988ca6e5d6eb9436ae51032bb9bc47480
parentca0ecc234adc8948e093f47feaf622435849f48a (diff)
downloadsubsurface-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.c95
-rw-r--r--divelist.h1
-rw-r--r--gtk-gui.c2
-rw-r--r--xslt/uddf-export.xslt191
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
diff --git a/gtk-gui.c b/gtk-gui.c
index c5b9a8071..82e9a3141 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -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>