diff options
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | core/dive.h | 2 | ||||
-rw-r--r-- | core/save-xml.c | 74 | ||||
-rw-r--r-- | desktop-widgets/divelogexportdialog.cpp | 11 | ||||
-rw-r--r-- | desktop-widgets/divelogexportdialog.ui | 284 |
5 files changed, 230 insertions, 142 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index b9e9ba1cb..5b803bc9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +- Desktop: Add export option for dive sites - Import: Initial support for importing Mares log software - Export option for profile data - Desktop: Splitting of individual dive computers into distinct dives diff --git a/core/dive.h b/core/dive.h index 6e4940452..7a6cf4099 100644 --- a/core/dive.h +++ b/core/dive.h @@ -481,6 +481,8 @@ extern int save_dives_logic(const char *filename, bool select_only, bool anonymi extern int save_dive(FILE *f, struct dive *dive, bool anonymize); extern int export_dives_xslt(const char *filename, const bool selected, const int units, const char *export_xslt, bool anonymize); +extern int save_dive_sites_logic(const char *filename, bool select_only, bool anonymize); + struct membuffer; extern void save_one_dive_to_mb(struct membuffer *b, struct dive *dive, bool anonymize); diff --git a/core/save-xml.c b/core/save-xml.c index 50a490c80..02cb2bf87 100644 --- a/core/save-xml.c +++ b/core/save-xml.c @@ -21,6 +21,7 @@ #include "strndup.h" #include "git-access.h" #include "qthelper.h" +#include "gettext.h" /* * We're outputting utf8 in xml. @@ -590,15 +591,16 @@ void save_dives_buffer(struct membuffer *b, const bool select_only, bool anonymi put_format(b, " <autogroup state='1' />\n"); put_format(b, "</settings>\n"); - /* save the dive sites - to make the output consistent let's sort the table, first */ - sort_dive_site_table(&dive_site_table); - purge_empty_dive_sites(&dive_site_table); + /* save the dive sites */ put_format(b, "<divesites>\n"); for (i = 0; i < dive_site_table.nr; i++) { struct dive_site *ds = get_dive_site(i, &dive_site_table); + /* Don't export empty dive sites */ + if (dive_site_is_empty(ds)) + continue; /* Only write used dive sites when exporting selected dives */ if (select_only && !is_dive_site_used(ds, true)) - continue; + continue; put_format(b, "<site uuid='%8x'", ds->uuid); show_utf8_blanked(b, ds->name, " name='", "'", 1, anonymize); @@ -734,7 +736,7 @@ int save_dives_logic(const char *filename, const bool select_only, bool anonymiz error = fclose(f); } if (error) - report_error("Save failed (%s)", strerror(errno)); + report_error(translate("gettextFromC", "Failed to save dives to %s (%s)"), filename, strerror(errno)); free_buffer(&buf); return error; @@ -798,3 +800,65 @@ int export_dives_xslt(const char *filename, const bool selected, const int units return res; } + +void save_dive_sites_buffer(struct membuffer *b, const bool select_only, bool anonymize) +{ + int i; + put_format(b, "<divesites program='subsurface' version='%d'>\n", DATAFORMAT_VERSION); + + /* save the dive sites */ + for (i = 0; i < dive_site_table.nr; i++) { + struct dive_site *ds = get_dive_site(i, &dive_site_table); + /* Don't export empty dive sites */ + if (dive_site_is_empty(ds)) + continue; + /* Only write used dive sites when exporting selected dives */ + if (select_only && !is_dive_site_used(ds, true)) + continue; + + put_format(b, "<site uuid='%8x'", ds->uuid); + show_utf8_blanked(b, ds->name, " name='", "'", 1, anonymize); + put_location(b, &ds->location, " gps='", "'"); + show_utf8_blanked(b, ds->description, " description='", "'", 1, anonymize); + put_format(b, ">\n"); + show_utf8_blanked(b, ds->notes, " <notes>", " </notes>\n", 0, anonymize); + if (ds->taxonomy.nr) { + for (int j = 0; j < ds->taxonomy.nr; j++) { + struct taxonomy *t = &ds->taxonomy.category[j]; + if (t->category != TC_NONE && t->value) { + put_format(b, " <geo cat='%d'", t->category); + put_format(b, " origin='%d'", t->origin); + show_utf8_blanked(b, t->value, " value='", "'/>\n", 1, anonymize); + } + } + } + put_format(b, "</site>\n"); + } + put_format(b, "</divesites>\n"); +} + +int save_dive_sites_logic(const char *filename, const bool select_only, bool anonymize) +{ + struct membuffer buf = { 0 }; + FILE *f; + int error = 0; + + save_dive_sites_buffer(&buf, select_only, anonymize); + + if (same_string(filename, "-")) { + f = stdout; + } else { + try_to_backup(filename); + error = -1; + f = subsurface_fopen(filename, "w"); + } + if (f) { + flush_buffer(&buf, f); + error = fclose(f); + } + if (error) + report_error(translate("gettextFromC", "Failed to save divesites to %s (%s)"), filename, strerror(errno)); + + free_buffer(&buf); + return error; +} diff --git a/desktop-widgets/divelogexportdialog.cpp b/desktop-widgets/divelogexportdialog.cpp index 87f2e5597..4fef543a0 100644 --- a/desktop-widgets/divelogexportdialog.cpp +++ b/desktop-widgets/divelogexportdialog.cpp @@ -91,6 +91,8 @@ void DiveLogExportDialog::showExplanation() ui->description->setText(tr("HTML export of the dive locations, visualized on a world map.")); } else if (ui->exportSubsurfaceXML->isChecked()) { ui->description->setText(tr("Subsurface native XML format.")); + } else if (ui->exportSubsurfaceSitesXML->isChecked()) { + ui->description->setText(tr("Subsurface dive sites native XML format.")); } else if (ui->exportImageDepths->isChecked()) { ui->description->setText(tr("Write depths of images to file.")); } else if (ui->exportTeX->isChecked()) { @@ -166,6 +168,15 @@ void DiveLogExportDialog::on_buttonBox_accepted() QByteArray bt = QFile::encodeName(filename); save_dives_logic(bt.data(), ui->exportSelected->isChecked(), ui->anonymize->isChecked()); } + } else if (ui->exportSubsurfaceSitesXML->isChecked()) { + filename = QFileDialog::getSaveFileName(this, tr("Export Subsurface dive sites XML"), lastDir, + tr("Subsurface files") + " (*.xml)"); + if (!filename.isNull() && !filename.isEmpty()) { + if (!filename.contains('.')) + filename.append(".xml"); + QByteArray bt = QFile::encodeName(filename); + save_dive_sites_logic(bt.data(), ui->exportSelected->isChecked(), ui->anonymize->isChecked()); + } } else if (ui->exportImageDepths->isChecked()) { filename = QFileDialog::getSaveFileName(this, tr("Save image depths"), lastDir); if (!filename.isNull() && !filename.isEmpty()) diff --git a/desktop-widgets/divelogexportdialog.ui b/desktop-widgets/divelogexportdialog.ui index 07b06378b..3b15f348e 100644 --- a/desktop-widgets/divelogexportdialog.ui +++ b/desktop-widgets/divelogexportdialog.ui @@ -56,34 +56,6 @@ <property name="bottomMargin"> <number>0</number> </property> - <item row="2" column="0" colspan="2"> - <widget class="QLabel" name="description"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>50</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>50</height> - </size> - </property> - <property name="text"> - <string/> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> <item row="3" column="0"> <spacer name="verticalSpacer_2"> <property name="orientation"> @@ -97,6 +69,117 @@ </property> </spacer> </item> + <item row="0" column="1"> + <widget class="QWidget" name="widget" native="true"> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item> + <widget class="QGroupBox" name="exportSelection"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>100</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>16777215</height> + </size> + </property> + <property name="title"> + <string>Selection</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QRadioButton" name="exportSelected"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>Selected dives</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="exportAll"> + <property name="text"> + <string>All dives</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="title"> + <string>Options</string> + </property> + <widget class="QComboBox" name="CSVUnits_2"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="geometry"> + <rect> + <x>10</x> + <y>30</y> + <width>102</width> + <height>27</height> + </rect> + </property> + <item> + <property name="text"> + <string>Metric</string> + </property> + </item> + <item> + <property name="text"> + <string>Imperial</string> + </property> + </item> + </widget> + <widget class="QCheckBox" name="anonymize"> + <property name="geometry"> + <rect> + <x>10</x> + <y>70</y> + <width>111</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Anonymize</string> + </property> + </widget> + </widget> + </item> + </layout> + </widget> + </item> <item row="0" column="0"> <widget class="QGroupBox" name="exportFormat"> <property name="title"> @@ -123,6 +206,16 @@ </widget> </item> <item> + <widget class="QRadioButton" name="exportSubsurfaceSitesXML"> + <property name="text"> + <string>Subsurface dive sites XML</string> + </property> + <attribute name="buttonGroup"> + <string notr="true">exportGroup</string> + </attribute> + </widget> + </item> + <item> <widget class="QRadioButton" name="exportUDDF"> <property name="maximumSize"> <size> @@ -244,115 +337,32 @@ </layout> </widget> </item> - <item row="0" column="1"> - <widget class="QWidget" name="widget" native="true"> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QGroupBox" name="exportSelection"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>0</width> - <height>100</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>16777215</width> - <height>16777215</height> - </size> - </property> - <property name="title"> - <string>Selection</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3"> - <item> - <widget class="QRadioButton" name="exportSelected"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="text"> - <string>Selected dives</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QRadioButton" name="exportAll"> - <property name="text"> - <string>All dives</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QGroupBox" name="groupBox"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="title"> - <string>Options</string> - </property> - <widget class="QComboBox" name="CSVUnits_2"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="geometry"> - <rect> - <x>10</x> - <y>30</y> - <width>102</width> - <height>27</height> - </rect> - </property> - <item> - <property name="text"> - <string>Metric</string> - </property> - </item> - <item> - <property name="text"> - <string>Imperial</string> - </property> - </item> - </widget> - <widget class="QCheckBox" name="anonymize"> - <property name="geometry"> - <rect> - <x>10</x> - <y>70</y> - <width>111</width> - <height>20</height> - </rect> - </property> - <property name="text"> - <string>Anonymize</string> - </property> - </widget> - </widget> - </item> - </layout> + <item row="2" column="0" colspan="2"> + <widget class="QLabel" name="description"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>50</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>16777215</width> + <height>50</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="wordWrap"> + <bool>true</bool> + </property> </widget> </item> </layout> |