mirror of
https://github.com/subsurface/subsurface.git
synced 2025-01-19 14:25:27 +00:00
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>
This commit is contained in:
parent
ca0ecc234a
commit
12d5ab4ce3
4 changed files with 289 additions and 0 deletions
95
divelist.c
95
divelist.c
|
@ -2102,6 +2102,92 @@ static void export_selected_dives_cb(GtkWidget *menuitem, GtkTreePath *path)
|
||||||
}
|
}
|
||||||
#endif
|
#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)
|
static void merge_dive_index(int i, struct dive *a)
|
||||||
{
|
{
|
||||||
struct dive *b = get_dive(i+1);
|
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 deleteplurallabel[] = N_("Delete dives");
|
||||||
char deletesinglelabel[] = N_("Delete dive");
|
char deletesinglelabel[] = N_("Delete dive");
|
||||||
char *deletelabel;
|
char *deletelabel;
|
||||||
|
#if defined(XSLT)
|
||||||
|
char exportuddflabel[] = N_("Export dive(s) to UDDF");
|
||||||
|
#endif
|
||||||
#if defined(LIBZIP) && defined(XSLT)
|
#if defined(LIBZIP) && defined(XSLT)
|
||||||
char exportlabel[] = N_("Export dive(s)");
|
char exportlabel[] = N_("Export dive(s)");
|
||||||
#endif
|
#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);
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
#endif
|
#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);
|
menuitem = gtk_menu_item_new_with_label(editlabel);
|
||||||
g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL);
|
g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL);
|
||||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
|
|
@ -15,4 +15,5 @@ extern void select_next_dive(void);
|
||||||
extern void select_prev_dive(void);
|
extern void select_prev_dive(void);
|
||||||
extern void show_and_select_dive(struct dive *dive);
|
extern void show_and_select_dive(struct dive *dive);
|
||||||
extern double init_decompression(struct dive * dive);
|
extern double init_decompression(struct dive * dive);
|
||||||
|
extern void export_all_dives_uddf_cb();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1509,6 +1509,7 @@ static GtkActionEntry menu_items[] = {
|
||||||
{ "CloseFile", GTK_STOCK_CLOSE, N_("Close"), NULL, NULL, G_CALLBACK(file_close) },
|
{ "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) },
|
{ "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) },
|
{ "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) },
|
{ "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) },
|
{ "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) },
|
{ "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\" /> \
|
<menuitem name=\"Close\" action=\"CloseFile\" /> \
|
||||||
<separator name=\"Separator1\"/> \
|
<separator name=\"Separator1\"/> \
|
||||||
<menuitem name=\"Import XML File\" action=\"ImportFile\" /> \
|
<menuitem name=\"Import XML File\" action=\"ImportFile\" /> \
|
||||||
|
<menuitem name=\"Export to UDDF File\" action=\"ExportUDDF\" /> \
|
||||||
<separator name=\"Separator2\"/> \
|
<separator name=\"Separator2\"/> \
|
||||||
<menuitem name=\"Print\" action=\"Print\" /> \
|
<menuitem name=\"Print\" action=\"Print\" /> \
|
||||||
<separator name=\"Separator3\"/> \
|
<separator name=\"Separator3\"/> \
|
||||||
|
|
191
xslt/uddf-export.xslt
Normal file
191
xslt/uddf-export.xslt
Normal file
|
@ -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>
|
Loading…
Add table
Reference in a new issue