aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dive.h3
-rw-r--r--file.c53
-rw-r--r--parse-xml.c31
-rw-r--r--qt-ui/csvimportdialog.cpp102
-rw-r--r--qt-ui/csvimportdialog.h48
-rw-r--r--qt-ui/csvimportdialog.ui253
-rw-r--r--qt-ui/mainwindow.cpp15
-rw-r--r--qt-ui/mainwindow.h2
-rw-r--r--qt-ui/mainwindow.ui8
-rw-r--r--qt-ui/subsurfacewebservices.cpp2
-rw-r--r--subsurface.pro9
11 files changed, 494 insertions, 32 deletions
diff --git a/dive.h b/dive.h
index fd9431a30..b1a3614ef 100644
--- a/dive.h
+++ b/dive.h
@@ -609,13 +609,14 @@ extern int match_one_dc(struct divecomputer *a, struct divecomputer *b);
extern double ascii_strtod(char *, char **);
extern void parse_xml_init(void);
-extern void parse_xml_buffer(const char *url, const char *buf, int size, struct dive_table *table, char **error);
+extern void parse_xml_buffer(const char *url, const char *buf, int size, struct dive_table *table, const char **params, char **error);
extern void parse_xml_exit(void);
extern void set_filename(const char *filename, bool force);
extern int parse_dm4_buffer(const char *url, const char *buf, int size, struct dive_table *table, char **error);
extern void parse_file(const char *filename, char **error);
+extern void parse_csv_file(const char *filename, int time, int depth, int temp, char **error);
extern void save_dives(const char *filename);
extern void save_dives_logic(const char *filename, bool select_only);
diff --git a/file.c b/file.c
index a4b90129a..acabd1b6b 100644
--- a/file.c
+++ b/file.c
@@ -72,7 +72,7 @@ static void zip_read(struct zip_file *file, char **error, const char *filename)
mem = realloc(mem, size);
}
mem[read] = 0;
- parse_xml_buffer(filename, mem, read, &dive_table, error);
+ parse_xml_buffer(filename, mem, read, &dive_table, NULL, error);
free(mem);
}
@@ -286,7 +286,7 @@ static void parse_file_buffer(const char *filename, struct memblock *mem, char *
if (fmt && open_by_filename(filename, fmt+1, mem, error))
return;
- parse_xml_buffer(filename, mem->buffer, mem->size, &dive_table, error);
+ parse_xml_buffer(filename, mem->buffer, mem->size, &dive_table, NULL, error);
}
void parse_file(const char *filename, char **error)
@@ -319,3 +319,52 @@ void parse_file(const char *filename, char **error)
parse_file_buffer(filename, &mem, error);
free(mem.buffer);
}
+
+#define MAXCOLDIGITS 3
+#define MAXCOLS 100
+void parse_csv_file(const char *filename, int time, int depth, int temp, char **error)
+{
+ struct memblock mem;
+ char *params[7];
+ char timebuf[MAXCOLDIGITS];
+ char depthbuf[MAXCOLDIGITS];
+ char tempbuf[MAXCOLDIGITS];
+
+ if (time >= MAXCOLS || depth >= MAXCOLS || temp >= MAXCOLS) {
+ int len = strlen(translate("gettextFromC", "Maximum number of supported columns on CSV import is %d")) + MAXCOLDIGITS;
+ *error = malloc(len);
+ snprintf(*error, len, translate("gettextFromC", "Maximum number of supported columns on CSV import is %d"), MAXCOLS);
+
+ return;
+ }
+ snprintf(timebuf, MAXCOLDIGITS, "%d", time);
+ snprintf(depthbuf, MAXCOLDIGITS, "%d", depth);
+ snprintf(tempbuf, MAXCOLDIGITS, "%d", temp);
+
+ params[0] = "timeField";
+ params[1] = timebuf;
+ params[2] = "depthField";
+ params[3] = depthbuf;
+ params[4] = "tempField";
+ params[5] = tempbuf;
+ params[6] = NULL;
+
+ if (filename == NULL)
+ return;
+
+ if (readfile(filename, &mem) < 0) {
+ if (error) {
+ int len = strlen(translate("gettextFromC","Failed to read '%s'")) + strlen(filename);
+ *error = malloc(len);
+ snprintf(*error, len, translate("gettextFromC","Failed to read '%s'"), filename);
+ }
+
+ return;
+ }
+
+ if (try_to_xslt_open_csv(filename, &mem, error))
+ return;
+
+ parse_xml_buffer(filename, mem.buffer, mem.size, &dive_table, (const char **)params, error);
+ free(mem.buffer);
+}
diff --git a/parse-xml.c b/parse-xml.c
index fbe805a42..129e2dc4b 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -21,7 +21,7 @@
int verbose;
-static xmlDoc *test_xslt_transforms(xmlDoc *doc, char **error);
+static xmlDoc *test_xslt_transforms(xmlDoc *doc, const char **params, char **error);
char *xslt_path;
/* the dive table holds the overall dive list; target table points at
@@ -1681,7 +1681,7 @@ const char *preprocess_divelog_de(const char *buffer)
}
void parse_xml_buffer(const char *url, const char *buffer, int size,
- struct dive_table *table, char **error)
+ struct dive_table *table, const char **params, char **error)
{
xmlDoc *doc;
const char *res = preprocess_divelog_de(buffer);
@@ -1698,7 +1698,7 @@ void parse_xml_buffer(const char *url, const char *buffer, int size,
}
reset_all();
dive_start();
- doc = test_xslt_transforms(doc, error);
+ doc = test_xslt_transforms(doc, params, error);
traverse(xmlDocGetRootElement(doc));
dive_end();
xmlFreeDoc(doc);
@@ -2019,14 +2019,13 @@ static struct xslt_files {
{ NULL, }
};
-static xmlDoc *test_xslt_transforms(xmlDoc *doc, char **error)
+static xmlDoc *test_xslt_transforms(xmlDoc *doc, const char **params, char **error)
{
struct xslt_files *info = xslt_files;
xmlDoc *transformed;
xsltStylesheetPtr xslt = NULL;
xmlNode *root_element = xmlDocGetRootElement(doc);
char *attribute;
- char *params[3];
while ((info->root) && (strcasecmp(root_element->name, info->root) != 0)) {
info++;
@@ -2048,28 +2047,10 @@ static xmlDoc *test_xslt_transforms(xmlDoc *doc, char **error)
parser_error(error, translate("gettextFromC","Can't open stylesheet (%s)/%s"), xslt_path, info->file);
return doc;
}
-
- /*
- * params is only used for CSV import, but it does not
- * hurt if we supply unused parameters for other
- * transforms as well.
- *
- * We should have a GUI set the parameters but currently
- * we just have PoC how parameters would be handled.
- *
- * (Field 9 is temperature for XP5 import, field 15
- * is temperature for AP Logviewer.
- */
-
- params[0] = strdup("tempField");
- params[1] = strdup("15");
- params[2] = NULL;
-
- transformed = xsltApplyStylesheet(xslt, doc, (const char **)params);
+ transformed = xsltApplyStylesheet(xslt, doc, params);
xmlFreeDoc(doc);
xsltFreeStylesheet(xslt);
- free(params[0]);
- free(params[1]);
+
return transformed;
}
return doc;
diff --git a/qt-ui/csvimportdialog.cpp b/qt-ui/csvimportdialog.cpp
new file mode 100644
index 000000000..5ae4036f5
--- /dev/null
+++ b/qt-ui/csvimportdialog.cpp
@@ -0,0 +1,102 @@
+#include <QtDebug>
+#include <QFileDialog>
+#include "csvimportdialog.h"
+#include "mainwindow.h"
+#include "ui_csvimportdialog.h"
+
+const CSVImportDialog::CSVAppConfig CSVImportDialog::CSVApps[CSVAPPS] = {
+ {"", },
+ {"APD Log Viewer", 0, 1, 15, "Tab"},
+ {"XP5", 0, 1, 9, "Tab"},
+ {NULL,}
+};
+
+CSVImportDialog::CSVImportDialog(QWidget *parent) :
+ QDialog(parent),
+ selector(true),
+ ui(new Ui::CSVImportDialog)
+{
+ ui->setupUi(this);
+
+ for (int i = 0; !CSVApps[i].name.isNull(); ++i)
+ ui->knownImports->addItem(CSVApps[i].name);
+
+ ui->CSVSeparator->addItem("Tab");
+ ui->knownImports->setCurrentIndex(1);
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+}
+
+CSVImportDialog::~CSVImportDialog()
+{
+ delete ui;
+}
+
+void CSVImportDialog::on_buttonBox_accepted()
+{
+ char *error = NULL;
+
+ parse_csv_file(ui->CSVFile->text().toUtf8().data(), ui->CSVTime->value(), ui->CSVDepth->value(), ui->CSVTemperature->value(), &error);
+ if (error != NULL) {
+
+ mainWindow()->showError(error);
+ free(error);
+ error = NULL;
+ }
+ process_dives(TRUE, FALSE);
+
+ mainWindow()->refreshDisplay();
+}
+
+void CSVImportDialog::on_CSVFileSelector_clicked()
+{
+ QString filename = QFileDialog::getOpenFileName(this, tr("Open CSV Log File"), ".", tr("CSV Files (*.csv)"));
+ ui->CSVFile->setText(filename);
+ if (filename.isEmpty())
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ else
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+}
+
+void CSVImportDialog::on_knownImports_currentIndexChanged(int index)
+{
+ if (index == 0)
+ return;
+
+ ui->CSVTime->blockSignals(true);
+ ui->CSVDepth->blockSignals(true);
+ ui->CSVTemperature->blockSignals(true);
+ ui->CSVTime->setValue(CSVApps[index].time);
+ ui->CSVDepth->setValue(CSVApps[index].depth);
+ ui->CSVTemperature->setValue(CSVApps[index].temperature);
+ ui->CSVTime->blockSignals(false);
+ ui->CSVDepth->blockSignals(false);
+ ui->CSVTemperature->blockSignals(false);
+}
+
+void CSVImportDialog::on_CSVTime_valueChanged(int arg1)
+{
+ unknownImports();
+}
+
+void CSVImportDialog::on_CSVDepth_valueChanged(int arg1)
+{
+ unknownImports();
+}
+
+void CSVImportDialog::on_CSVTemperature_valueChanged(int arg1)
+{
+ unknownImports();
+}
+
+void CSVImportDialog::unknownImports()
+{
+ ui->knownImports->setCurrentIndex(0);
+}
+
+void CSVImportDialog::on_CSVFile_textEdited()
+{
+ if (ui->CSVFile->text().isEmpty())
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
+ else
+ ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true);
+}
diff --git a/qt-ui/csvimportdialog.h b/qt-ui/csvimportdialog.h
new file mode 100644
index 000000000..057533018
--- /dev/null
+++ b/qt-ui/csvimportdialog.h
@@ -0,0 +1,48 @@
+#ifndef CSVIMPORTDIALOG_H
+#define CSVIMPORTDIALOG_H
+
+#include <QDialog>
+#include <QModelIndex>
+#include "../dive.h"
+#include "../divelist.h"
+
+namespace Ui {
+class CSVImportDialog;
+}
+
+class CSVImportDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CSVImportDialog(QWidget *parent = 0);
+ ~CSVImportDialog();
+
+private slots:
+ void on_buttonBox_accepted();
+ void on_CSVFileSelector_clicked();
+ void on_knownImports_currentIndexChanged(int index);
+ void on_CSVTime_valueChanged(int arg1);
+ void on_CSVDepth_valueChanged(int arg1);
+ void on_CSVTemperature_valueChanged(int arg1);
+ void on_CSVFile_textEdited();
+
+private:
+ void unknownImports();
+
+ bool selector;
+ Ui::CSVImportDialog *ui;
+
+ struct CSVAppConfig {
+ QString name;
+ int time;
+ int depth;
+ int temperature;
+ QString separator;
+ };
+
+#define CSVAPPS 4
+ static const CSVAppConfig CSVApps[CSVAPPS];
+};
+
+#endif // CSVIMPORTDIALOG_H
diff --git a/qt-ui/csvimportdialog.ui b/qt-ui/csvimportdialog.ui
new file mode 100644
index 000000000..ec5002baf
--- /dev/null
+++ b/qt-ui/csvimportdialog.ui
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CSVImportDialog</class>
+ <widget class="QDialog" name="CSVImportDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="geometry">
+ <rect>
+ <x>30</x>
+ <y>240</y>
+ <width>341</width>
+ <height>32</height>
+ </rect>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>10</y>
+ <width>331</width>
+ <height>71</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Import File (CSV)</string>
+ </property>
+ <widget class="QLineEdit" name="CSVFile">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>30</y>
+ <width>291</width>
+ <height>29</height>
+ </rect>
+ </property>
+ </widget>
+ <widget class="QToolButton" name="CSVFileSelector">
+ <property name="geometry">
+ <rect>
+ <x>300</x>
+ <y>30</y>
+ <width>25</width>
+ <height>27</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>80</y>
+ <width>121</width>
+ <height>61</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Field Separator</string>
+ </property>
+ <widget class="QComboBox" name="CSVSeparator">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>30</y>
+ <width>111</width>
+ <height>29</height>
+ </rect>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="geometry">
+ <rect>
+ <x>40</x>
+ <y>80</y>
+ <width>151</width>
+ <height>151</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Field Configuration</string>
+ </property>
+ <widget class="QSpinBox" name="CSVTime">
+ <property name="geometry">
+ <rect>
+ <x>60</x>
+ <y>30</y>
+ <width>56</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>0</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" name="CSVDepth">
+ <property name="geometry">
+ <rect>
+ <x>60</x>
+ <y>70</y>
+ <width>56</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ <widget class="QSpinBox" name="CSVTemperature">
+ <property name="geometry">
+ <rect>
+ <x>60</x>
+ <y>110</y>
+ <width>56</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="minimum">
+ <number>0</number>
+ </property>
+ <property name="value">
+ <number>15</number>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>30</y>
+ <width>41</width>
+ <height>19</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Time</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_2">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>70</y>
+ <width>51</width>
+ <height>19</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Depth</string>
+ </property>
+ </widget>
+ <widget class="QLabel" name="label_3">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>110</y>
+ <width>41</width>
+ <height>19</height>
+ </rect>
+ </property>
+ <property name="text">
+ <string>Temp</string>
+ </property>
+ </widget>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="geometry">
+ <rect>
+ <x>200</x>
+ <y>159</y>
+ <width>181</width>
+ <height>61</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Pre-configured imports</string>
+ </property>
+ <widget class="QComboBox" name="knownImports">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>30</y>
+ <width>161</width>
+ <height>29</height>
+ </rect>
+ </property>
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ </widget>
+ </widget>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CSVImportDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>CSVImportDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index 247cfdf2f..3b56134c1 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -34,6 +34,7 @@
#include "diveplanner.h"
#include "about.h"
#include "printdialog.h"
+#include "csvimportdialog.h"
static MainWindow* instance = 0;
@@ -801,3 +802,17 @@ void MainWindow::loadFiles(const QStringList fileNames)
WSInfoModel *wsim = WSInfoModel::instance();
wsim->updateInfo();
}
+
+void MainWindow::on_actionImportCSV_triggered()
+{
+ CSVImportDialog *csvImport = new(CSVImportDialog);
+ csvImport->show();
+ process_dives(TRUE, FALSE);
+
+ ui.InfoWidget->reload();
+ ui.globe->reload();
+ ui.ListWidget->reload(DiveTripModel::TREE);
+ ui.ListWidget->setFocus();
+ WSInfoModel *wsim = WSInfoModel::instance();
+ wsim->updateInfo();
+}
diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
index 0319c7b28..5dfae3e98 100644
--- a/qt-ui/mainwindow.h
+++ b/qt-ui/mainwindow.h
@@ -99,6 +99,8 @@ private slots:
void current_dive_changed(int divenr);
void initialUiSetup();
+ void on_actionImportCSV_triggered();
+
protected:
void closeEvent(QCloseEvent *);
diff --git a/qt-ui/mainwindow.ui b/qt-ui/mainwindow.ui
index 63dded7f8..8a108118e 100644
--- a/qt-ui/mainwindow.ui
+++ b/qt-ui/mainwindow.ui
@@ -183,6 +183,7 @@
<addaction name="actionClose"/>
<addaction name="separator"/>
<addaction name="actionImport"/>
+ <addaction name="actionImportCSV"/>
<addaction name="actionExportUDDF"/>
<addaction name="separator"/>
<addaction name="actionPrint"/>
@@ -441,6 +442,13 @@
<string>Dive Planner</string>
</property>
</action>
+ <action name="actionImportCSV">
+ <property name="text">
+ <string>Import CSV</string>
+ </property>
+ <property name="toolTip">
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
diff --git a/qt-ui/subsurfacewebservices.cpp b/qt-ui/subsurfacewebservices.cpp
index 2a560efdd..f2b1b88cc 100644
--- a/qt-ui/subsurfacewebservices.cpp
+++ b/qt-ui/subsurfacewebservices.cpp
@@ -47,7 +47,7 @@ void SubsurfaceWebServices::buttonClicked(QAbstractButton* button)
case QDialogButtonBox::ApplyRole:{
clear_table(&gps_location_table);
QByteArray url = tr("Webservice").toLocal8Bit();
- parse_xml_buffer(url.data(), downloadedData.data(), downloadedData.length(), &gps_location_table, NULL);
+ parse_xml_buffer(url.data(), downloadedData.data(), downloadedData.length(), &gps_location_table, NULL, NULL);
/* now merge the data in the gps_location table into the dive_table */
if (merge_locations_into_dives()) {
diff --git a/subsurface.pro b/subsurface.pro
index a2fd97320..e9927686f 100644
--- a/subsurface.pro
+++ b/subsurface.pro
@@ -55,7 +55,8 @@ HEADERS = \
subsurface-icon.h \
subsurfacestartup.h \
uemis.h \
- webservice.h
+ webservice.h \
+ qt-ui/csvimportdialog.h
SOURCES = \
deco.c \
@@ -101,7 +102,8 @@ SOURCES = \
subsurfacestartup.c \
time.c \
uemis.c \
- uemis-downloader.c
+ uemis-downloader.c \
+ qt-ui/csvimportdialog.cpp
linux*: SOURCES += linux.c
mac: SOURCES += macos.c
@@ -118,7 +120,8 @@ FORMS = \
qt-ui/printoptions.ui \
qt-ui/renumber.ui \
qt-ui/subsurfacewebservices.ui \
- qt-ui/tableview.ui
+ qt-ui/tableview.ui \
+ qt-ui/csvimportdialog.ui
RESOURCES = subsurface.qrc