mirror of
https://github.com/subsurface/subsurface.git
synced 2025-01-19 06:15:26 +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
|
||||
|
||||
#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);
|
||||
|
|
|
@ -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\"/> \
|
||||
|
|
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