summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/user-manual.txt30
-rw-r--r--file.c218
-rw-r--r--parse-xml.c2
-rw-r--r--planner.c5
-rw-r--r--pref.h1
-rw-r--r--qt-ui/divelogimportdialog.cpp53
-rw-r--r--qt-ui/divelogimportdialog.h2
-rw-r--r--qt-ui/diveplanner.cpp6
-rw-r--r--qt-ui/preferences.cpp40
-rw-r--r--qt-ui/preferences.h1
-rw-r--r--qt-ui/preferences.ui11
-rw-r--r--qt-ui/subsurfacewebservices.cpp14
-rw-r--r--qt-ui/subsurfacewebservices.h3
13 files changed, 246 insertions, 140 deletions
diff --git a/Documentation/user-manual.txt b/Documentation/user-manual.txt
index 99ab33a32..566e19ed9 100644
--- a/Documentation/user-manual.txt
+++ b/Documentation/user-manual.txt
@@ -3961,21 +3961,27 @@ which can be imported into _Subsurface_.
4. The password for accessing the .zip file is _mares_.
[[S_ImportingDivingLog]]
-=== Exporting from *DivingLog 5.0*
+=== Exporting from *DivingLog 5.0 and 6.0*
[icon="images/icons/divingloglogo.jpg"]
[NOTE]
-Unfortunately DivingLog XML files give us no
-indication on the preferences set on one's system. So in order for
-_Subsurface_ to be able to successfully import XML files from DivingLog
-one first needs to ensure that DivingLog is configured
-to use the Metric system (one can easily change this within Diving Log by
-selecting 'File -> Preferences -> Units and Language' by clicking the 'Metric'
-button). Then do the following:
-
-1. In DivingLog open the 'File -> Export -> XML' menu
-2. Select the dives to export
-3. Click on the export button and select the filename
+The best way to bring your logs from DivingLog to Subsurface is to
+convert the whole database. This is because other export formats do not
+include all the details, and we would lack e.g. gas switches and
+information of what units are used. With database import, all this
+information is included and readily available for us.
+
+To transfer all files from DivingLog to Subsurface, do the following:
+
+1. In DivingLog open the 'File -> Export -> SQLite' menu
+2. Select 'Settings' button
+3. Set the 'RTF2Plaintext' to 'true'
+4. Close the Settings dialog
+5. Click 'Export' button and select the filename
+
+Once this is done, open the saved database file with Subsurface and the
+dives are automatically converted to our own format. Last step to do is
+save the log file in Subsurface.
[[S_Appendix_D]]
== APPENDIX D: Exporting a spreadsheet to CSV format
diff --git a/file.c b/file.c
index 8fca750ac..f7f98333f 100644
--- a/file.c
+++ b/file.c
@@ -824,98 +824,101 @@ int parse_txt_file(const char *filename, const char *csv)
return 0;
}
-#define MAXCOLDIGITS 3
+#define MAXCOLDIGITS 10
#define MAXCOLS 100
#define DATESTR 9
#define TIMESTR 6
-void init_csv_file_parsing(char **params, char *timebuf, char *depthbuf, char *tempbuf, char *po2buf, char *o2sensor1buf, char *o2sensor2buf, char *o2sensor3buf, char *cnsbuf, char *ndlbuf, char *ttsbuf, char *stopdepthbuf, char *pressurebuf, char *setpointbuf, char *unitbuf, char *separator_index, time_t *now, struct tm *timep, char *curdate, char *curtime, int timef, int depthf, int tempf, int po2f, int o2sensor1f, int o2sensor2f, int o2sensor3f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int setpointf, int sepidx, const char *csvtemplate, int unitidx)
+
+int init_csv_file_parsing(char **params, time_t *now, struct tm *timep, int timef, int depthf, int tempf, int po2f, int o2sensor1f, int o2sensor2f, int o2sensor3f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int setpointf, int sepidx, const char *csvtemplate, int unitidx)
{
int pnr = 0;
+ char tmpbuf[MAXCOLDIGITS];
- snprintf(timebuf, MAXCOLDIGITS, "%d", timef);
- snprintf(depthbuf, MAXCOLDIGITS, "%d", depthf);
- snprintf(tempbuf, MAXCOLDIGITS, "%d", tempf);
- snprintf(po2buf, MAXCOLDIGITS, "%d", po2f);
- snprintf(o2sensor1buf, MAXCOLDIGITS, "%d", o2sensor1f);
- snprintf(o2sensor2buf, MAXCOLDIGITS, "%d", o2sensor2f);
- snprintf(o2sensor3buf, MAXCOLDIGITS, "%d", o2sensor3f);
- snprintf(cnsbuf, MAXCOLDIGITS, "%d", cnsf);
- snprintf(ndlbuf, MAXCOLDIGITS, "%d", ndlf);
- snprintf(ttsbuf, MAXCOLDIGITS, "%d", ttsf);
- snprintf(stopdepthbuf, MAXCOLDIGITS, "%d", stopdepthf);
- snprintf(pressurebuf, MAXCOLDIGITS, "%d", pressuref);
- snprintf(setpointbuf, MAXCOLDIGITS, "%d", setpointf);
- snprintf(separator_index, MAXCOLDIGITS, "%d", sepidx);
- snprintf(unitbuf, MAXCOLDIGITS, "%d", unitidx);
- time(now);
- timep = localtime(now);
- strftime(curdate, DATESTR, "%Y%m%d", timep);
-
- /* As the parameter is numeric, we need to ensure that the leading zero
- * is not discarded during the transform, thus prepend time with 1 */
- strftime(curtime, TIMESTR, "1%H%M", timep);
-
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", timef);
params[pnr++] = "timeField";
- params[pnr++] = timebuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", depthf);
params[pnr++] = "depthField";
- params[pnr++] = depthbuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", tempf);
params[pnr++] = "tempField";
- params[pnr++] = tempbuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", po2f);
params[pnr++] = "po2Field";
- params[pnr++] = po2buf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", o2sensor1f);
params[pnr++] = "o2sensor1Field";
- params[pnr++] = o2sensor1buf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", o2sensor2f);
params[pnr++] = "o2sensor2Field";
- params[pnr++] = o2sensor2buf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", o2sensor3f);
params[pnr++] = "o2sensor3Field";
- params[pnr++] = o2sensor3buf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", cnsf);
params[pnr++] = "cnsField";
- params[pnr++] = cnsbuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", ndlf);
params[pnr++] = "ndlField";
- params[pnr++] = ndlbuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", ttsf);
params[pnr++] = "ttsField";
- params[pnr++] = ttsbuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", stopdepthf);
params[pnr++] = "stopdepthField";
- params[pnr++] = stopdepthbuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", pressuref);
params[pnr++] = "pressureField";
- params[pnr++] = pressurebuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", setpointf);
params[pnr++] = "setpointField";
- params[pnr++] = setpointbuf;
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", sepidx);
+ params[pnr++] = "separatorIndex";
+ params[pnr++] = strdup(tmpbuf);
+
+ snprintf(tmpbuf, MAXCOLDIGITS, "%d", unitidx);
+ params[pnr++] = "units";
+ params[pnr++] = strdup(tmpbuf);
+
+ time(now);
+ timep = localtime(now);
+
+ strftime(tmpbuf, MAXCOLDIGITS, "%Y%m%d", timep);
params[pnr++] = "date";
- params[pnr++] = curdate;
+ params[pnr++] = strdup(tmpbuf);
+
+ /* As the parameter is numeric, we need to ensure that the leading zero
+ * is not discarded during the transform, thus prepend time with 1 */
+ strftime(tmpbuf, MAXCOLDIGITS, "1%H%M", timep);
params[pnr++] = "time";
- params[pnr++] = curtime;
- params[pnr++] = "units";
- params[pnr++] = unitbuf;
- params[pnr++] = "separatorIndex";
- params[pnr++] = separator_index;
+ params[pnr++] = strdup(tmpbuf);
+
params[pnr++] = NULL;
+
+ return pnr - 1;
}
int parse_csv_file(const char *filename, int timef, int depthf, int tempf, int po2f, int o2sensor1f, int o2sensor2f, int o2sensor3f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int setpointf, int sepidx, const char *csvtemplate, int unitidx)
{
- int ret;
+ int ret, i;
struct memblock mem;
char *params[35];
- char timebuf[MAXCOLDIGITS];
- char depthbuf[MAXCOLDIGITS];
- char tempbuf[MAXCOLDIGITS];
- char po2buf[MAXCOLDIGITS];
- char o2sensor1buf[MAXCOLDIGITS];
- char o2sensor2buf[MAXCOLDIGITS];
- char o2sensor3buf[MAXCOLDIGITS];
- char cnsbuf[MAXCOLDIGITS];
- char ndlbuf[MAXCOLDIGITS];
- char ttsbuf[MAXCOLDIGITS];
- char stopdepthbuf[MAXCOLDIGITS];
- char pressurebuf[MAXCOLDIGITS];
- char setpointbuf[MAXCOLDIGITS];
- char unitbuf[MAXCOLDIGITS];
- char separator_index[MAXCOLDIGITS];
time_t now;
struct tm *timep = NULL;
- char curdate[DATESTR];
- char curtime[TIMESTR];
int previous;
/* Increase the limits for recursion and variables on XSLT
@@ -928,7 +931,7 @@ int parse_csv_file(const char *filename, int timef, int depthf, int tempf, int p
if (timef >= MAXCOLS || depthf >= MAXCOLS || tempf >= MAXCOLS || po2f >= MAXCOLS || o2sensor1f >= MAXCOLS || o2sensor2f >= MAXCOLS || o2sensor3f >= MAXCOLS || cnsf >= MAXCOLS || ndlf >= MAXCOLS || cnsf >= MAXCOLS || stopdepthf >= MAXCOLS || pressuref >= MAXCOLS || setpointf >= MAXCOLS)
return report_error(translate("gettextFromC", "Maximum number of supported columns on CSV import is %d"), MAXCOLS);
- init_csv_file_parsing(params, timebuf, depthbuf, tempbuf, po2buf, o2sensor1buf, o2sensor2buf, o2sensor3buf, cnsbuf, ndlbuf, ttsbuf, stopdepthbuf, pressurebuf, setpointbuf, unitbuf, separator_index, &now, timep, curdate, curtime, timef, depthf, tempf, po2f, o2sensor1f, o2sensor2f, o2sensor3f, cnsf, ndlf, ttsf, stopdepthf, pressuref, setpointf, sepidx, csvtemplate, unitidx);
+ init_csv_file_parsing(params, &now, timep, timef, depthf, tempf, po2f, o2sensor1f, o2sensor2f, o2sensor3f, cnsf, ndlf, ttsf, stopdepthf, pressuref, setpointf, sepidx, csvtemplate, unitidx);
if (filename == NULL)
return report_error("No CSV filename");
@@ -941,42 +944,35 @@ int parse_csv_file(const char *filename, int timef, int depthf, int tempf, int p
ret = parse_xml_buffer(filename, mem.buffer, mem.size, &dive_table, (const char **)params);
free(mem.buffer);
+ for (i = 0; params[i]; i += 2)
+ free(params[i + 1]);
+
return ret;
}
-#define SBPARAMS 35
+#define SBPARAMS 38
int parse_seabear_csv_file(const char *filename, int timef, int depthf, int tempf, int po2f, int o2sensor1f, int o2sensor2f, int o2sensor3f, int cnsf, int ndlf, int ttsf, int stopdepthf, int pressuref, int sepidx, const char *csvtemplate, int unitidx, const char *delta)
{
- int ret;
+ int ret, i, pnr;
struct memblock mem;
char *params[SBPARAMS];
- char timebuf[MAXCOLDIGITS];
- char depthbuf[MAXCOLDIGITS];
- char tempbuf[MAXCOLDIGITS];
- char po2buf[MAXCOLDIGITS];
- char o2sensor1buf[MAXCOLDIGITS];
- char o2sensor2buf[MAXCOLDIGITS];
- char o2sensor3buf[MAXCOLDIGITS];
- char cnsbuf[MAXCOLDIGITS];
- char ndlbuf[MAXCOLDIGITS];
- char ttsbuf[MAXCOLDIGITS];
- char stopdepthbuf[MAXCOLDIGITS];
- char pressurebuf[MAXCOLDIGITS];
- char setpointbuf[MAXCOLDIGITS];
- char unitbuf[MAXCOLDIGITS];
- char separator_index[MAXCOLDIGITS];
char deltabuf[MAXCOLDIGITS];
time_t now;
struct tm *timep = NULL;
- char curdate[DATESTR];
- char curtime[TIMESTR];
char *ptr, *ptr_old = NULL;
char *NL = NULL;
+ /* Increase the limits for recursion and variables on XSLT
+ * parsing */
+ xsltMaxDepth = 30000;
+#if LIBXSLT_VERSION > 10126
+ xsltMaxVars = 150000;
+#endif
+
if (timef >= MAXCOLS || depthf >= MAXCOLS || tempf >= MAXCOLS || po2f >= MAXCOLS || o2sensor1f >= MAXCOLS || o2sensor2f >= MAXCOLS || o2sensor3f >= MAXCOLS || cnsf >= MAXCOLS || ndlf >= MAXCOLS || cnsf >= MAXCOLS || stopdepthf >= MAXCOLS || pressuref >= MAXCOLS)
return report_error(translate("gettextFromC", "Maximum number of supported columns on CSV import is %d"), MAXCOLS);
- init_csv_file_parsing(params, timebuf, depthbuf, tempbuf, po2buf, o2sensor1buf, o2sensor2buf, o2sensor3buf, cnsbuf, ndlbuf, ttsbuf, stopdepthbuf, pressurebuf, setpointbuf, unitbuf, separator_index, &now, timep, curdate, curtime, timef, depthf, tempf, po2f, o2sensor1f, o2sensor2f, o2sensor3f, cnsf, ndlf, ttsf, stopdepthf, pressuref, -1, sepidx, csvtemplate, unitidx);
+ pnr = init_csv_file_parsing(params, &now, timep, timef, depthf, tempf, po2f, o2sensor1f, o2sensor2f, o2sensor3f, cnsf, ndlf, ttsf, stopdepthf, pressuref, -1, sepidx, csvtemplate, unitidx);
if (filename == NULL)
return report_error("No CSV filename");
@@ -993,6 +989,7 @@ int parse_seabear_csv_file(const char *filename, int timef, int depthf, int temp
}
if (!ptr_old) {
+ ptr = mem.buffer;
while ((ptr = strstr(ptr, "\n\n")) != NULL) {
ptr_old = ptr;
ptr += 1;
@@ -1012,30 +1009,41 @@ int parse_seabear_csv_file(const char *filename, int timef, int depthf, int temp
/*
* On my current sample of Seabear DC log file, the date is
* without any identifier. Thus we must search for the previous
- * line and step through from there.
+ * line and step through from there. That is the line after
+ * Serial number.
*/
ptr = strstr(mem.buffer, "Serial number:");
if (ptr)
ptr = strstr(ptr, NL);
- /* Write date and time values to params array */
+ /*
+ * Write date and time values to params array, if available in
+ * the CSV header
+ */
+
if (ptr) {
ptr += strlen(NL) + 2;
- memcpy(params[19], ptr, 4);
- memcpy(params[19] + 4, ptr + 5, 2);
- memcpy(params[19] + 6, ptr + 8, 2);
- params[19][8] = 0;
-
- params[21][0] = '1';
- memcpy(params[21] + 1, ptr + 11, 2);
- memcpy(params[21] + 3, ptr + 14, 2);
- params[21][5] = 0;
+ /*
+ * pnr is the index of NULL on the params as filled by
+ * the init function. The two last entries should be
+ * date and time. Here we overwrite them with the data
+ * from the CSV header.
+ */
+
+ memcpy(params[pnr - 3], ptr, 4);
+ memcpy(params[pnr - 3] + 4, ptr + 5, 2);
+ memcpy(params[pnr - 3] + 6, ptr + 8, 2);
+ params[pnr - 3][8] = 0;
+
+ memcpy(params[pnr - 1] + 1, ptr + 11, 2);
+ memcpy(params[pnr - 1] + 3, ptr + 14, 2);
+ params[pnr - 1][5] = 0;
}
snprintf(deltabuf, MAXCOLDIGITS, "%s", delta);
- params[SBPARAMS - 3] = "delta";
- params[SBPARAMS - 2] = deltabuf;
- params[SBPARAMS - 1] = NULL;
+ params[pnr++] = "delta";
+ params[pnr++] = strdup(deltabuf);
+ params[pnr++] = NULL;
/* Move the CSV data to the start of mem buffer */
memmove(mem.buffer, ptr_old, mem.size - (ptr_old - (char*)mem.buffer));
@@ -1044,8 +1052,24 @@ int parse_seabear_csv_file(const char *filename, int timef, int depthf, int temp
if (try_to_xslt_open_csv(filename, &mem, csvtemplate))
return -1;
+ /*
+ * Lets print command line for manual testing with xsltproc if
+ * verbosity level is high enough. The printed line needs the
+ * input file added as last parameter.
+ */
+
+ if (verbose >= 2) {
+ fprintf(stderr, "xsltproc ");
+ for (i=0; params[i]; i+=2)
+ fprintf(stderr, "--stringparam %s %s ", params[i], params[i+1]);
+ fprintf(stderr, "xslt/csv2xml.xslt\n");
+ }
+
ret = parse_xml_buffer(filename, mem.buffer, mem.size, &dive_table, (const char **)params);
free(mem.buffer);
+ for (i = 0; params[i]; i += 2)
+ free(params[i + 1]);
+
return ret;
}
diff --git a/parse-xml.c b/parse-xml.c
index 3d0c6a1e5..429277f49 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -3109,7 +3109,7 @@ extern int divinglog_dive(void *param, int columns, char **data, char **column)
utf8_string(data[4], &cur_dive->notes);
if (data[5])
- cur_dive->dc.maxdepth.mm = atoi(data[5]) * 1000;
+ cur_dive->dc.maxdepth.mm = atof(data[5]) * 1000;
if (data[6])
cur_dive->dc.duration.seconds = atoi(data[6]) * 60;
diff --git a/planner.c b/planner.c
index e5685a499..9fe5c1d05 100644
--- a/planner.c
+++ b/planner.c
@@ -542,7 +542,10 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
snprintf(temp, sizeof(temp), translate("gettextFromC", "based on Buhlmann ZHL-16B with GFlow = %d and GFhigh = %d"),
diveplan->gflow, diveplan->gfhigh);
} else if (prefs.deco_mode == VPMB){
- strncat(temp, translate("gettextFromC", "based on VPM-B"), sizeof(temp) - 1);
+ snprintf(temp, sizeof(temp), translate("gettextFromC", "based on VPM-B"));
+ } else if (prefs.deco_mode == RECREATIONAL){
+ snprintf(temp, sizeof(temp), translate("gettextFromC", "recreational mode based on Buhlmann ZHL-16B with GFlow = %d and GFhigh = %d"),
+ diveplan->gflow, diveplan->gfhigh);
}
len += snprintf(buffer + len, sizeof(buffer) - len, "<div><b>%s</b><br>%s</div><br>",
translate("gettextFromC", "Subsurface dive plan"), temp);
diff --git a/pref.h b/pref.h
index fcb051bd9..3791f62e7 100644
--- a/pref.h
+++ b/pref.h
@@ -109,6 +109,7 @@ struct preferences {
short default_file_behavior;
facebook_prefs_t facebook;
char *cloud_storage_password;
+ char *cloud_storage_newpassword;
char *cloud_storage_email;
char *cloud_storage_email_encoded;
bool save_password_local;
diff --git a/qt-ui/divelogimportdialog.cpp b/qt-ui/divelogimportdialog.cpp
index ea783b093..d799bf17f 100644
--- a/qt-ui/divelogimportdialog.cpp
+++ b/qt-ui/divelogimportdialog.cpp
@@ -13,7 +13,8 @@ const DiveLogImportDialog::CSVAppConfig DiveLogImportDialog::CSVApps[CSVAPPS] =
// time, depth, temperature, po2, sensor1, sensor2, sensor3, cns, ndl, tts, stopdepth, pressure, setpoint
// indices are 0 based, -1 means the column doesn't exist
{ "Manual import", },
- { "APD Log Viewer", 0, 1, 15, 6, 3, 4, 5, 17, -1, -1, 18, -1, 2, "Tab" },
+ { "APD Log Viewer - DC1", 0, 1, 15, 6, 3, 4, 5, 17, -1, -1, 18, -1, 2, "Tab" },
+ { "APD Log Viewer - DC2", 0, 1, 15, 6, 7, 8, 9, 17, -1, -1, 18, -1, 2, "Tab" },
{ "XP5", 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Tab" },
{ "SensusCSV", 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, "," },
{ "Seabear CSV", 0, 1, 5, -1, -1, -1, -1, -1, 2, 3, 4, 6, -1, ";" },
@@ -21,6 +22,16 @@ const DiveLogImportDialog::CSVAppConfig DiveLogImportDialog::CSVApps[CSVAPPS] =
{ NULL, }
};
+static enum {
+ MANUAL,
+ APD,
+ APD2,
+ XP5,
+ SENSUS,
+ SEABEAR,
+ SUBSURFACE
+} known;
+
ColumnNameProvider::ColumnNameProvider(QObject *parent) : QAbstractListModel(parent)
{
columnNames << tr("Dive #") << tr("Date") << tr("Time") << tr("Duration") << tr("Location") << tr("GPS") << tr("Weight") << tr("Cyl. size") << tr("Start pressure") <<
@@ -387,7 +398,7 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
while ((firstLine = f.readLine()).length() > 3 && !f.atEnd()) {
if (firstLine.contains("//Log interval: "))
- delta = firstLine.remove(QString::fromLatin1("//Log interval: ")).trimmed();
+ delta = firstLine.remove(QString::fromLatin1("//Log interval: ")).trimmed().remove(QString::fromLatin1(" s"));
}
/*
@@ -416,6 +427,8 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
headers.append("Sample sensor3 pO₂");
} else if (columnText == "Ceiling") {
headers.append("Sample ceiling");
+ } else if (columnText == "Tank pressure") {
+ headers.append("Sample pressure");
} else {
// We do not know about this value
qDebug() << "Seabear import found an un-handled field: " << columnText;
@@ -437,13 +450,13 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
}
// Special handling for APD Log Viewer
- if ((triggeredBy == KNOWNTYPES && value == 1) || (triggeredBy == INITIAL && fileNames.first().endsWith(".apd", Qt::CaseInsensitive))) {
+ if ((triggeredBy == KNOWNTYPES && (value == APD || value == APD2)) || (triggeredBy == INITIAL && fileNames.first().endsWith(".apd", Qt::CaseInsensitive))) {
apd=true;
- firstLine = "Sample time\tSample depth\tSample setpoint\t\t\t\tSample pO₂\t\t\t\t\t\t\t\t\tSample temperature\t\tSample CNS\tSample stopdepth";
+ firstLine = "Sample time\tSample depth\tSample setpoint\tSample sensor1 pO₂\tSample sensor2 pO₂\tSample sensor3 pO₂\tSample pO₂\t\t\t\t\t\t\t\t\tSample temperature\t\tSample CNS\tSample stopdepth";
blockSignals(true);
ui->CSVSeparator->setCurrentText(tr("Tab"));
if (triggeredBy == INITIAL && fileNames.first().contains(".apd", Qt::CaseInsensitive))
- ui->knownImports->setCurrentText("APD Log Viewer");
+ ui->knownImports->setCurrentText("APD Log Viewer - DC1");
blockSignals(false);
}
@@ -467,13 +480,21 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
currColumns = firstLine.split(separator);
}
}
- if (triggeredBy == INITIAL || (triggeredBy == KNOWNTYPES && value == 0) || triggeredBy == SEPARATOR) {
+ if (triggeredBy == INITIAL || (triggeredBy == KNOWNTYPES && value == MANUAL) || triggeredBy == SEPARATOR) {
// now try and guess the columns
Q_FOREACH (QString columnText, currColumns) {
- columnText.replace("\"", "");
- columnText.replace("number", "#", Qt::CaseInsensitive);
- columnText.replace("2", "₂", Qt::CaseInsensitive);
- columnText.replace("cylinder", "cyl.", Qt::CaseInsensitive);
+ /*
+ * We have to skip the conversion of 2 to ₂ for APD Log
+ * viewer as that would mess up the sensor numbering. We
+ * also know that the column headers do not need this
+ * conversion.
+ */
+ if (triggeredBy == KNOWNTYPES && value != APD) {
+ columnText.replace("\"", "");
+ columnText.replace("number", "#", Qt::CaseInsensitive);
+ columnText.replace("2", "₂", Qt::CaseInsensitive);
+ columnText.replace("cylinder", "cyl.", Qt::CaseInsensitive);
+ }
int idx = provider->mymatch(columnText);
if (idx >= 0) {
QString foundHeading = provider->data(provider->index(idx, 0), Qt::DisplayRole).toString();
@@ -493,9 +514,9 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
}
}
}
- if (triggeredBy == KNOWNTYPES && value != 0) {
+ if (triggeredBy == KNOWNTYPES && value != MANUAL) {
// an actual known type
- if (value == 5) {
+ if (value == SUBSURFACE) {
/*
* Subsurface CSV file needs separator detection
* as we used to default to comma but switched
@@ -530,11 +551,11 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
headers.replace(CSVApps[value].temperature, tr("Sample temperature"));
if (CSVApps[value].po2 > -1 && CSVApps[value].po2 < currColumns.count())
headers.replace(CSVApps[value].po2, tr("Sample pO₂"));
- if (CSVApps[value].po2 > -1 && CSVApps[value].po2 < currColumns.count())
+ if (CSVApps[value].sensor1 > -1 && CSVApps[value].sensor1 < currColumns.count())
headers.replace(CSVApps[value].sensor1, tr("Sample sensor1 pO₂"));
- if (CSVApps[value].po2 > -1 && CSVApps[value].po2 < currColumns.count())
+ if (CSVApps[value].sensor2 > -1 && CSVApps[value].sensor2 < currColumns.count())
headers.replace(CSVApps[value].sensor2, tr("Sample sensor2 pO₂"));
- if (CSVApps[value].po2 > -1 && CSVApps[value].po2 < currColumns.count())
+ if (CSVApps[value].sensor3 > -1 && CSVApps[value].sensor3 < currColumns.count())
headers.replace(CSVApps[value].sensor3, tr("Sample sensor3 pO₂"));
if (CSVApps[value].cns > -1 && CSVApps[value].cns < currColumns.count())
headers.replace(CSVApps[value].cns, tr("Sample CNS"));
@@ -601,7 +622,7 @@ void DiveLogImportDialog::on_buttonBox_accepted()
r.indexOf(tr("Sample stopdepth")),
r.indexOf(tr("Sample pressure")),
ui->CSVSeparator->currentIndex(),
- specialCSV.contains(ui->knownImports->currentIndex()) ? CSVApps[ui->knownImports->currentIndex()].name.toUtf8().data() : "csv",
+ "csv",
ui->CSVUnits->currentIndex(),
delta.toUtf8().data()
) < 0) {
diff --git a/qt-ui/divelogimportdialog.h b/qt-ui/divelogimportdialog.h
index c5c750973..050090f97 100644
--- a/qt-ui/divelogimportdialog.h
+++ b/qt-ui/divelogimportdialog.h
@@ -114,7 +114,7 @@ private:
QString separator;
};
-#define CSVAPPS 7
+#define CSVAPPS 8
static const CSVAppConfig CSVApps[CSVAPPS];
};
diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp
index f6f6c3894..efa75ddec 100644
--- a/qt-ui/diveplanner.cpp
+++ b/qt-ui/diveplanner.cpp
@@ -256,7 +256,7 @@ PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f)
ui.setupUi(this);
QSettings s;
- QStringList rebreater_modes;
+ QStringList rebreather_modes;
s.beginGroup("Planner");
prefs.last_stop = s.value("last_stop", prefs.last_stop).toBool();
prefs.verbatim_plan = s.value("verbatim_plan", prefs.verbatim_plan).toBool();
@@ -302,8 +302,8 @@ PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f)
ui.vpmb_deco->setChecked(prefs.deco_mode == VPMB);
// should be the same order as in dive_comp_type!
- rebreater_modes << tr("Open circuit") << tr("CCR") << tr("pSCR");
- ui.rebreathermode->insertItems(0, rebreater_modes);
+ rebreather_modes << tr("Open circuit") << tr("CCR") << tr("pSCR");
+ ui.rebreathermode->insertItems(0, rebreather_modes);
modeMapper = new QSignalMapper(this);
connect(modeMapper, SIGNAL(mapped(int)) , plannerModel, SLOT(setDecoMode(int)));
diff --git a/qt-ui/preferences.cpp b/qt-ui/preferences.cpp
index b30e76e03..04fb3a825 100644
--- a/qt-ui/preferences.cpp
+++ b/qt-ui/preferences.cpp
@@ -110,6 +110,10 @@ void PreferencesDialog::cloudPinNeeded()
ui.cloud_storage_pin->setVisible(prefs.cloud_verification_status == CS_NEED_TO_VERIFY);
ui.cloud_storage_pin_label->setEnabled(prefs.cloud_verification_status == CS_NEED_TO_VERIFY);
ui.cloud_storage_pin_label->setVisible(prefs.cloud_verification_status == CS_NEED_TO_VERIFY);
+ ui.cloud_storage_new_passwd->setEnabled(prefs.cloud_verification_status == CS_VERIFIED);
+ ui.cloud_storage_new_passwd->setVisible(prefs.cloud_verification_status == CS_VERIFIED);
+ ui.cloud_storage_new_passwd_label->setEnabled(prefs.cloud_verification_status == CS_VERIFIED);
+ ui.cloud_storage_new_passwd_label->setVisible(prefs.cloud_verification_status == CS_VERIFIED);
if (prefs.cloud_verification_status == CS_VERIFIED) {
ui.cloudStorageGroupBox->setTitle(tr("Subsurface cloud storage (credentials verified)"));
ui.cloudDefaultFile->setEnabled(true);
@@ -408,10 +412,29 @@ void PreferencesDialog::syncSettings()
s.beginGroup("CloudStorage");
QString email = ui.cloud_storage_email->text();
QString password = ui.cloud_storage_password->text();
- if (prefs.cloud_verification_status == CS_UNKNOWN ||
- prefs.cloud_verification_status == CS_INCORRECT_USER_PASSWD ||
- email != prefs.cloud_storage_email ||
- password != prefs.cloud_storage_password) {
+ QString newpassword = ui.cloud_storage_new_passwd->text();
+ if (prefs.cloud_verification_status == CS_VERIFIED && !newpassword.isEmpty()) {
+ // deal with password change
+ if (!email.isEmpty() && !password.isEmpty()) {
+ // connect to backend server to check / create credentials
+ QRegularExpression reg("^[a-zA-Z0-9@.+_-]+$");
+ if (!reg.match(email).hasMatch() || (!password.isEmpty() && !reg.match(password).hasMatch())) {
+ report_error(qPrintable(tr("Cloud storage email and password can only consist of letters, numbers, and '.', '-', '_', and '+'.")));
+ } else {
+ CloudStorageAuthenticate *cloudAuth = new CloudStorageAuthenticate(this);
+ connect(cloudAuth, SIGNAL(finishedAuthenticate()), this, SLOT(cloudPinNeeded()));
+ connect(cloudAuth, SIGNAL(passwordChangeSuccessful()), this, SLOT(passwordUpdateSuccessfull()));
+ QNetworkReply *reply = cloudAuth->backend(email, password, "", newpassword);
+ ui.cloud_storage_new_passwd->setText("");
+ free(prefs.cloud_storage_newpassword);
+ prefs.cloud_storage_newpassword = strdup(qPrintable(newpassword));
+ }
+ }
+ } else if (prefs.cloud_verification_status == CS_UNKNOWN ||
+ prefs.cloud_verification_status == CS_INCORRECT_USER_PASSWD ||
+ email != prefs.cloud_storage_email ||
+ password != prefs.cloud_storage_password) {
+
// different credentials - reset verification status
prefs.cloud_verification_status = CS_UNKNOWN;
if (!email.isEmpty() && !password.isEmpty()) {
@@ -422,7 +445,7 @@ void PreferencesDialog::syncSettings()
} else {
CloudStorageAuthenticate *cloudAuth = new CloudStorageAuthenticate(this);
connect(cloudAuth, SIGNAL(finishedAuthenticate()), this, SLOT(cloudPinNeeded()));
- QNetworkReply *reply = cloudAuth->authenticate(email, password);
+ QNetworkReply *reply = cloudAuth->backend(email, password);
}
}
} else if (prefs.cloud_verification_status == CS_NEED_TO_VERIFY) {
@@ -435,7 +458,7 @@ void PreferencesDialog::syncSettings()
}
CloudStorageAuthenticate *cloudAuth = new CloudStorageAuthenticate(this);
connect(cloudAuth, SIGNAL(finishedAuthenticate()), this, SLOT(cloudPinNeeded()));
- QNetworkReply *reply = cloudAuth->authenticate(email, password, pin);
+ QNetworkReply *reply = cloudAuth->backend(email, password, pin);
}
}
SAVE_OR_REMOVE("email", default_prefs.cloud_storage_email, email);
@@ -666,6 +689,11 @@ void PreferencesDialog::on_resetSettings_clicked()
}
}
+void PreferencesDialog::passwordUpdateSuccessfull()
+{
+ ui.cloud_storage_password->setText(prefs.cloud_storage_password);
+}
+
void PreferencesDialog::emitSettingsChanged()
{
emit settingsChanged();
diff --git a/qt-ui/preferences.h b/qt-ui/preferences.h
index 2402a7964..326b1f964 100644
--- a/qt-ui/preferences.h
+++ b/qt-ui/preferences.h
@@ -40,6 +40,7 @@ slots:
void facebookLoggedIn();
void facebookDisconnect();
void cloudPinNeeded();
+ void passwordUpdateSuccessfull();
private:
explicit PreferencesDialog(QWidget *parent = 0, Qt::WindowFlags f = 0);
void setUiFromPrefs();
diff --git a/qt-ui/preferences.ui b/qt-ui/preferences.ui
index 1b59e77a5..dc0d04a5a 100644
--- a/qt-ui/preferences.ui
+++ b/qt-ui/preferences.ui
@@ -1374,6 +1374,13 @@
</property>
</widget>
</item>
+ <item row="0" column="3">
+ <widget class="QLabel" name="cloud_storage_new_passwd_label">
+ <property name="text">
+ <string>New password</string>
+ </property>
+ </widget>
+ </item>
<item row="1" column="0">
<widget class="QLineEdit" name="cloud_storage_email">
<property name="toolTip">
@@ -1391,6 +1398,10 @@
</property>
</widget>
</item>
+ <item row="1" column="3">
+ <widget class="QLineEdit" name="cloud_storage_new_passwd">
+ </widget>
+ </item>
<item row="2" column="0">
<widget class="QCheckBox" name="cloud_background_sync">
<property name="text">
diff --git a/qt-ui/subsurfacewebservices.cpp b/qt-ui/subsurfacewebservices.cpp
index fd9f2fad1..8154ce5fb 100644
--- a/qt-ui/subsurfacewebservices.cpp
+++ b/qt-ui/subsurfacewebservices.cpp
@@ -988,13 +988,17 @@ CloudStorageAuthenticate::CloudStorageAuthenticate(QObject *parent) :
#define CLOUDURL QString(prefs.cloud_base_url)
#define CLOUDBACKENDSTORAGE CLOUDURL + "/storage"
#define CLOUDBACKENDVERIFY CLOUDURL + "/verify"
+#define CLOUDBACKENDUPDATE CLOUDURL + "/update"
-QNetworkReply* CloudStorageAuthenticate::authenticate(QString email, QString password, QString pin)
+QNetworkReply* CloudStorageAuthenticate::backend(QString email, QString password, QString pin, QString newpasswd)
{
QString payload(email + " " + password);
QUrl requestUrl;
- if (pin == "") {
+ if (pin == "" && newpasswd == "") {
requestUrl = QUrl(CLOUDBACKENDSTORAGE);
+ } else if (newpasswd != "") {
+ requestUrl = QUrl(CLOUDBACKENDUPDATE);
+ payload += " " + newpasswd;
} else {
requestUrl = QUrl(CLOUDBACKENDVERIFY);
payload += " " + pin;
@@ -1025,6 +1029,12 @@ void CloudStorageAuthenticate::uploadFinished()
myLastError.clear();
} else if (cloudAuthReply == "[VERIFY]") {
prefs.cloud_verification_status = CS_NEED_TO_VERIFY;
+ } else if (cloudAuthReply == "[PASSWDCHANGED]") {
+ free(prefs.cloud_storage_password);
+ prefs.cloud_storage_password = prefs.cloud_storage_newpassword;
+ prefs.cloud_storage_newpassword = NULL;
+ emit passwordChangeSuccessful();
+ return;
} else {
prefs.cloud_verification_status = CS_INCORRECT_USER_PASSWD;
myLastError = cloudAuthReply;
diff --git a/qt-ui/subsurfacewebservices.h b/qt-ui/subsurfacewebservices.h
index e4866c529..2b454ebc7 100644
--- a/qt-ui/subsurfacewebservices.h
+++ b/qt-ui/subsurfacewebservices.h
@@ -114,10 +114,11 @@ slots:
class CloudStorageAuthenticate : public QObject {
Q_OBJECT
public:
- QNetworkReply* authenticate(QString email, QString password, QString pin = "");
+ QNetworkReply* backend(QString email, QString password, QString pin = "", QString newpasswd = "");
explicit CloudStorageAuthenticate(QObject *parent);
signals:
void finishedAuthenticate();
+ void passwordChangeSuccessful();
private
slots:
void uploadError(QNetworkReply::NetworkError error);