summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dive.c1
-rw-r--r--dive.h19
-rw-r--r--divelist.c11
-rw-r--r--parse-xml.c30
-rw-r--r--profile.c93
-rw-r--r--profile.h1
-rw-r--r--qt-ui/csvimportdialog.h13
-rw-r--r--qt-ui/csvimportdialog.ui372
-rw-r--r--qt-ui/divelistview.cpp3
-rw-r--r--qt-ui/divelogimportdialog.cpp (renamed from qt-ui/csvimportdialog.cpp)60
-rw-r--r--qt-ui/divelogimportdialog.h49
-rw-r--r--qt-ui/divelogimportdialog.ui392
-rw-r--r--qt-ui/maintab.cpp15
-rw-r--r--qt-ui/mainwindow.cpp53
-rw-r--r--qt-ui/mainwindow.h7
-rw-r--r--qt-ui/mainwindow.ui23
-rw-r--r--qt-ui/models.cpp40
-rw-r--r--qt-ui/models.h4
-rw-r--r--qt-ui/printlayout.cpp2
-rw-r--r--qt-ui/profilegraphics.cpp25
-rw-r--r--qt-ui/profilegraphics.h2
-rw-r--r--qt-ui/usermanual.cpp93
-rw-r--r--qt-ui/usermanual.h32
-rw-r--r--qt-ui/usermanual.ui146
-rw-r--r--qthelper.cpp55
-rw-r--r--subsurface.pro13
26 files changed, 1035 insertions, 519 deletions
diff --git a/dive.c b/dive.c
index 540f40eb5..a902bca68 100644
--- a/dive.c
+++ b/dive.c
@@ -892,6 +892,7 @@ struct dive *fixup_dive(struct dive *dive)
weightsystem_t *ws = dive->weightsystem + i;
add_weightsystem_description(ws);
}
+ dive->id = getUniqID(dive);
return dive;
}
diff --git a/dive.h b/dive.h
index 2f800c5e5..ccba7a09f 100644
--- a/dive.h
+++ b/dive.h
@@ -412,9 +412,10 @@ struct dive {
pressure_t surface_pressure;
duration_t duration;
int salinity; // kg per 10000 l
- struct tag_entry *tag_list;
+ struct tag_entry *tag_list;
struct divecomputer dc;
+ int id; // unique ID for this dive
};
static inline int dive_has_gps_location(struct dive *dive)
@@ -611,6 +612,21 @@ static inline struct dive *get_dive_by_diveid(uint32_t diveid, uint32_t deviceid
}
return NULL;
}
+// this is very different from get_dive_by_diveid() (which is only used
+// by the UEMIS downloader) -- this uses the unique diveID to allow us
+// to hold an identifier for a dive across operations that might change
+// the dive_table
+static inline struct dive *getDiveById(int id)
+{
+ int i;
+ struct dive *dive = NULL;
+
+ for_each_dive(i, dive) {
+ if (dive->id == id)
+ break;
+ }
+ return dive;
+}
extern struct dive *find_dive_including(timestamp_t when);
extern bool dive_within_time_range(struct dive *dive, timestamp_t when, timestamp_t offset);
struct dive *find_dive_n_near(timestamp_t when, int n, timestamp_t offset);
@@ -654,6 +670,7 @@ extern void finish_sample(struct divecomputer *dc);
extern void sort_table(struct dive_table *table);
extern struct dive *fixup_dive(struct dive *dive);
+extern int getUniqID(struct dive *d);
extern unsigned int dc_airtemp(struct divecomputer *dc);
extern unsigned int dc_watertemp(struct divecomputer *dc);
extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded);
diff --git a/divelist.c b/divelist.c
index 90c5112bc..dfb7b6577 100644
--- a/divelist.c
+++ b/divelist.c
@@ -792,6 +792,7 @@ struct dive *merge_two_dives(struct dive *a, struct dive *b)
{
struct dive *res;
int i,j;
+ int id = a->id;
if (!a || !b)
return NULL;
@@ -804,6 +805,10 @@ struct dive *merge_two_dives(struct dive *a, struct dive *b)
add_single_dive(i, res);
delete_single_dive(i+1);
delete_single_dive(j);
+ // now make sure that we keep the id of the first dive.
+ // why?
+ // because this way one of the previously selected ids is still around
+ res->id = id;
mark_divelist_changed(TRUE);
return res;
}
@@ -956,6 +961,7 @@ void process_dives(bool is_imported, bool prefer_imported)
struct dive *prev = pp[0];
struct dive *dive = pp[1];
struct dive *merged;
+ int id;
/* only try to merge overlapping dives - or if one of the dives has
* zero duration (that might be a gps marker from the webservice) */
@@ -967,6 +973,9 @@ void process_dives(bool is_imported, bool prefer_imported)
if (!merged)
continue;
+ // remember the earlier dive's id
+ id = prev->id;
+
/* careful - we might free the dive that last points to. Oops... */
if (last == prev || last == dive)
last = merged;
@@ -976,6 +985,8 @@ void process_dives(bool is_imported, bool prefer_imported)
add_single_dive(i, merged);
delete_single_dive(i+1);
delete_single_dive(i+1);
+ // keep the id or the first dive for the merged dive
+ merged->id = id;
}
/* make sure no dives are still marked as downloaded */
for (i = 1; i < dive_table.nr; i++)
diff --git a/parse-xml.c b/parse-xml.c
index 8fc504a3f..04b6d4d7d 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -1681,6 +1681,10 @@ extern int dm4_events(void *handle, int columns, char **data, char **column)
/* 13 Air time */
cur_event.name = strdup("airtime");
break;
+ case 17:
+ /* 17 Ascent warning */
+ cur_event.name = strdup("ascent");
+ break;
case 18:
/* 18 Ceiling error */
cur_event.name = strdup("ceiling");
@@ -1689,6 +1693,14 @@ extern int dm4_events(void *handle, int columns, char **data, char **column)
/* 19 Surfaced */
cur_event.name = strdup("surface");
break;
+ case 20:
+ /* 20 Deco */
+ cur_event.name = strdup("deco");
+ break;
+ case 22:
+ /* 22 Mandatory safety stop violation */
+ cur_event.name = strdup("violation");
+ break;
case 257:
/* 257 Dive active */
/* This seems to be given after surface
@@ -1714,6 +1726,14 @@ extern int dm4_events(void *handle, int columns, char **data, char **column)
return 0;
}
+extern int dm4_tags(void *handle, int columns, char **data, char **column)
+{
+ if(data[0])
+ taglist_add_tag(cur_dive->tag_list, data[0]);
+
+ return 0;
+}
+
extern int dm4_dive(void *param, int columns, char **data, char **column)
{
int i, interval, retval = 0;
@@ -1723,6 +1743,7 @@ extern int dm4_dive(void *param, int columns, char **data, char **column)
int *pressureBlob;
char *err = NULL;
char get_events_template[] = "select * from Mark where DiveId = %d";
+ char get_tags_template[] = "select Text from DiveTag where DiveId = %d";
char get_events[64];
dive_start();
@@ -1802,7 +1823,7 @@ extern int dm4_dive(void *param, int columns, char **data, char **column)
else
cur_sample->depth.mm = cur_dive->dc.maxdepth.mm;
- if (tempBlob)
+ if (data[18] && data[18][0])
cur_sample->temperature.mkelvin = C_to_mkelvin(tempBlob[i]);
if (data[19] && data[19][0])
cur_sample->cylinderpressure.mbar = pressureBlob[i] ;
@@ -1816,6 +1837,13 @@ extern int dm4_dive(void *param, int columns, char **data, char **column)
return 1;
}
+ snprintf(get_events, sizeof(get_events) - 1, get_tags_template, cur_dive->number);
+ retval = sqlite3_exec(handle, get_events, &dm4_tags, 0, &err);
+ if (retval != SQLITE_OK) {
+ fprintf(stderr, "%s", translate("gettextFromC","Database query get_tags failed.\n"));
+ return 1;
+ }
+
dive_end();
/*
diff --git a/profile.c b/profile.c
index ea387bf6d..637c89494 100644
--- a/profile.c
+++ b/profile.c
@@ -417,6 +417,22 @@ static void dump_pr_track(pr_track_t **track_pr)
}
#endif
+typedef struct pr_interpolate_struct pr_interpolate_t;
+struct pr_interpolate_struct {
+ int start;
+ int end;
+ int pressure_time;
+ int acc_pressure_time;
+};
+
+#ifdef DEBUG_PR_INTERPOLATE
+static void dump_pr_interpolate(int i, pr_interpolate_t interpolate_pr)
+{
+ printf("Interpolate for entry %d: start %d - end %d - pt %d - acc_pt %d\n", i,
+ interpolate_pr.start, interpolate_pr.end, interpolate_pr.pressure_time, interpolate_pr.acc_pressure_time);
+}
+#endif
+
/*
* This looks at the pressures for one cylinder, and
* calculates any missing beginning/end pressures for
@@ -506,6 +522,57 @@ static inline int pressure_time(struct dive *dive, struct divecomputer *dc, stru
return depth_to_mbar(depth, dive) * time;
}
+static struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, struct plot_info *pi, int cur)
+{
+ struct pr_interpolate_struct interpolate;
+ int i;
+ struct plot_data *entry;
+
+ interpolate.start = segment->start;
+ interpolate.end = segment->end;
+ interpolate.acc_pressure_time = 0;
+ interpolate.pressure_time = 0;
+
+ for (i = 0; i < pi->nr; i++) {
+ entry = pi->entry + i;
+ if (entry->sec < segment->t_start)
+ continue;
+ if (entry->sec >= segment->t_end) {
+ interpolate.pressure_time += entry->pressure_time;
+ break;
+ }
+ if (entry->sec == segment->t_start) {
+ interpolate.acc_pressure_time = 0;
+ interpolate.pressure_time = 0;
+ if (SENSOR_PRESSURE(entry))
+ interpolate.start = SENSOR_PRESSURE(entry);
+ continue;
+ }
+ if (i < cur) {
+ if (SENSOR_PRESSURE(entry)) {
+ interpolate.start = SENSOR_PRESSURE(entry);
+ interpolate.acc_pressure_time = 0;
+ interpolate.pressure_time = 0;
+ } else {
+ interpolate.acc_pressure_time += entry->pressure_time;
+ interpolate.pressure_time += entry->pressure_time;
+ }
+ continue;
+ }
+ if (i == cur) {
+ interpolate.acc_pressure_time += entry->pressure_time;
+ interpolate.pressure_time += entry->pressure_time;
+ continue;
+ }
+ interpolate.pressure_time += entry->pressure_time;
+ if (SENSOR_PRESSURE(entry)) {
+ interpolate.end = SENSOR_PRESSURE(entry);
+ break;
+ }
+ }
+ return interpolate;
+}
+
static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr)
{
int cyl, i;
@@ -526,9 +593,9 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi,
/* The first two are "fillers", but in case we don't have a sample
* at time 0 we need to process the second of them here */
for (i = 1; i < pi->nr; i++) {
- double magic, cur_pt;
+ double magic;
pr_track_t *segment;
- int pressure;
+ pr_interpolate_t interpolate;
entry = pi->entry + i;
cyl = entry->cylinderindex;
@@ -549,14 +616,19 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi,
continue;
}
- /* Overall pressure change over total pressure-time for this segment*/
- magic = (segment->end - segment->start) / (double) segment->pressure_time;
+ interpolate = get_pr_interpolate_data(segment, pi, i);
+#ifdef DEBUG_PR_INTERPOLATE
+ dump_pr_interpolate(i, interpolate);
+#endif
+ /* if this segment has pressure time, calculate a new interpolated pressure */
+ if (interpolate.pressure_time) {
+ /* Overall pressure change over total pressure-time for this segment*/
+ magic = (interpolate.end - interpolate.start) / (double) interpolate.pressure_time;
- /* Use that overall pressure change to update the current pressure */
- cur_pt = pressure_time(dive, &dive->dc, entry-1, entry);
- pressure = cur_pr[cyl] + cur_pt * magic + 0.5;
- INTERPOLATED_PRESSURE(entry) = pressure;
- cur_pr[cyl] = pressure;
+ /* Use that overall pressure change to update the current pressure */
+ cur_pr[cyl] = interpolate.start + magic * interpolate.acc_pressure_time + 0.5;
+ }
+ INTERPOLATED_PRESSURE(entry) = cur_pr[cyl];
}
}
@@ -906,7 +978,8 @@ static void populate_pressure_information(struct dive *dive, struct divecomputer
/* discrete integration of pressure over time to get the SAC rate equivalent */
if (current) {
- current->pressure_time += pressure_time(dive, dc, entry-1, entry);
+ entry->pressure_time = pressure_time(dive, dc, entry-1, entry);
+ current->pressure_time += entry->pressure_time;
current->t_end = entry->sec;
}
diff --git a/profile.h b/profile.h
index c64ecfbf6..0453bff08 100644
--- a/profile.h
+++ b/profile.h
@@ -41,6 +41,7 @@ struct plot_data {
int tts_calc;
int stoptime_calc;
int stopdepth_calc;
+ int pressure_time;
};
void calculate_max_limits(struct dive *dive, struct divecomputer *dc, struct graphics_context *gc);
diff --git a/qt-ui/csvimportdialog.h b/qt-ui/csvimportdialog.h
index fda36bcb7..f062d49fd 100644
--- a/qt-ui/csvimportdialog.h
+++ b/qt-ui/csvimportdialog.h
@@ -7,16 +7,16 @@
#include "../divelist.h"
namespace Ui {
-class CSVImportDialog;
+class DiveLogImportDialog;
}
-class CSVImportDialog : public QDialog
+class DiveLogImportDialog : public QDialog
{
Q_OBJECT
public:
- explicit CSVImportDialog(QWidget *parent = 0);
- ~CSVImportDialog();
+ explicit DiveLogImportDialog(QWidget *parent = 0);
+ ~DiveLogImportDialog();
private slots:
void on_buttonBox_accepted();
@@ -26,11 +26,14 @@ private slots:
void unknownImports(int);
void unknownImports(bool);
+ void on_DiveLogFileSelector_clicked();
+ void on_DiveLogFile_editingFinished();
+
private:
void unknownImports();
bool selector;
- Ui::CSVImportDialog *ui;
+ Ui::DiveLogImportDialog *ui;
struct CSVAppConfig {
QString name;
diff --git a/qt-ui/csvimportdialog.ui b/qt-ui/csvimportdialog.ui
deleted file mode 100644
index 9c89704f3..000000000
--- a/qt-ui/csvimportdialog.ui
+++ /dev/null
@@ -1,372 +0,0 @@
-<?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>432</width>
- <height>330</height>
- </rect>
- </property>
- <property name="windowTitle">
- <string>Import CSV file</string>
- </property>
- <property name="windowIcon">
- <iconset>
- <normalon>:/subsurface-icon</normalon>
- </iconset>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <item>
- <widget class="QGroupBox" name="groupBox">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="title">
- <string>Import File (CSV)</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout">
- <item>
- <widget class="QLineEdit" name="CSVFile"/>
- </item>
- <item>
- <widget class="QToolButton" name="CSVFileSelector">
- <property name="text">
- <string>...</string>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QWidget" name="horizontalWidget" native="true">
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <property name="spacing">
- <number>0</number>
- </property>
- <property name="margin">
- <number>0</number>
- </property>
- <item>
- <widget class="QGroupBox" name="groupBox_3">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="title">
- <string>Field Configuration</string>
- </property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="0" column="1">
- <widget class="QSpinBox" name="CSVTime">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="value">
- <number>1</number>
- </property>
- </widget>
- </item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Time</string>
- </property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QSpinBox" name="CSVDepth">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="value">
- <number>2</number>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>Depth</string>
- </property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QSpinBox" name="CSVTemperature">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QCheckBox" name="temperatureCheckBox">
- <property name="text">
- <string>Temp</string>
- </property>
- </widget>
- </item>
- <item row="3" column="1">
- <widget class="QSpinBox" name="CSVpo2">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="value">
- <number>0</number>
- </property>
- </widget>
- </item>
- <item row="3" column="0">
- <widget class="QCheckBox" name="po2CheckBox">
- <property name="text">
- <string>PO2</string>
- </property>
- </widget>
- </item>
- <item row="4" column="1">
- <widget class="QSpinBox" name="CSVcns">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="value">
- <number>0</number>
- </property>
- </widget>
- </item>
- <item row="4" column="0">
- <widget class="QCheckBox" name="cnsCheckBox">
- <property name="text">
- <string>Cns</string>
- </property>
- </widget>
- </item>
- <item row="5" column="1">
- <widget class="QSpinBox" name="CSVstopdepth">
- <property name="minimum">
- <number>1</number>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="value">
- <number>0</number>
- </property>
- </widget>
- </item>
- <item row="5" column="0">
- <widget class="QCheckBox" name="stopdepthCheckBox">
- <property name="text">
- <string>Stopdepth</string>
- </property>
- </widget>
- </item>
- </layout>
- <zorder>label</zorder>
- <zorder>label_2</zorder>
- <zorder>CSVTime</zorder>
- <zorder>CSVDepth</zorder>
- <zorder>temperatureCheckBox</zorder>
- <zorder>CSVTemperature</zorder>
- <zorder>po2CheckBox</zorder>
- <zorder>CSVpo2</zorder>
- <zorder>cnsCheckBox</zorder>
- <zorder>CSVcns</zorder>
- <zorder>stopdepthCheckBox</zorder>
- <zorder>CSVstopdepth</zorder>
- </widget>
- </item>
- <item>
- <widget class="QWidget" name="verticalWidget" native="true">
- <layout class="QVBoxLayout" name="verticalLayout_2">
- <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="groupBox_2">
- <property name="title">
- <string>Field Separator</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_2">
- <item>
- <widget class="QComboBox" name="CSVSeparator"/>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <widget class="QGroupBox" name="groupBox_4">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="title">
- <string>Pre-configured imports</string>
- </property>
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <item>
- <widget class="QComboBox" name="knownImports">
- <property name="currentIndex">
- <number>-1</number>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- <item>
- <spacer name="verticalSpacer">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- <property name="sizeHint" stdset="0">
- <size>
- <width>20</width>
- <height>40</height>
- </size>
- </property>
- </spacer>
- </item>
- <item>
- <widget class="QDialogButtonBox" name="buttonBox">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- <property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
- </property>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- </item>
- </layout>
- </widget>
- <resources>
- <include location="../subsurface.qrc"/>
- </resources>
- <connections>
- <connection>
- <sender>buttonBox</sender>
- <signal>accepted()</signal>
- <receiver>CSVImportDialog</receiver>
- <slot>accept()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>310</x>
- <y>286</y>
- </hint>
- <hint type="destinationlabel">
- <x>215</x>
- <y>164</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>buttonBox</sender>
- <signal>rejected()</signal>
- <receiver>CSVImportDialog</receiver>
- <slot>reject()</slot>
- <hints>
- <hint type="sourcelabel">
- <x>310</x>
- <y>286</y>
- </hint>
- <hint type="destinationlabel">
- <x>215</x>
- <y>164</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>temperatureCheckBox</sender>
- <signal>clicked(bool)</signal>
- <receiver>CSVTemperature</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>77</x>
- <y>191</y>
- </hint>
- <hint type="destinationlabel">
- <x>161</x>
- <y>191</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>po2CheckBox</sender>
- <signal>clicked(bool)</signal>
- <receiver>CSVpo2</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>77</x>
- <y>223</y>
- </hint>
- <hint type="destinationlabel">
- <x>161</x>
- <y>223</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>cnsCheckBox</sender>
- <signal>clicked(bool)</signal>
- <receiver>CSVcns</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>77</x>
- <y>255</y>
- </hint>
- <hint type="destinationlabel">
- <x>161</x>
- <y>255</y>
- </hint>
- </hints>
- </connection>
- <connection>
- <sender>stopdepthCheckBox</sender>
- <signal>clicked(bool)</signal>
- <receiver>CSVstopdepth</receiver>
- <slot>setEnabled(bool)</slot>
- <hints>
- <hint type="sourcelabel">
- <x>77</x>
- <y>287</y>
- </hint>
- <hint type="destinationlabel">
- <x>161</x>
- <y>287</y>
- </hint>
- </hints>
- </connection>
- </connections>
-</ui>
diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index 9f5b0c0a7..5a436f2a9 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -31,6 +31,7 @@ DiveListView::DiveListView(QWidget *parent) : QTreeView(parent), mouseClickSelec
QSortFilterProxyModel *model = new QSortFilterProxyModel(this);
model->setSortRole(DiveTripModel::SORT_ROLE);
model->setFilterKeyColumn(-1); // filter all columns
+ model->setFilterCaseSensitivity(Qt::CaseInsensitive);
setModel(model);
connect(model, SIGNAL(layoutChanged()), this, SLOT(fixMessyQtModelBehaviour()));
@@ -42,7 +43,7 @@ DiveListView::DiveListView(QWidget *parent) : QTreeView(parent), mouseClickSelec
header()->setStretchLastSection(true);
QAction *showSearchBox = new QAction(tr("Show Search Box"), this);
showSearchBox->setShortcut( Qt::CTRL + Qt::Key_F);
- showSearchBox->setShortcutContext(Qt::ApplicationShortcut);
+ showSearchBox->setShortcutContext(Qt::WindowShortcut);
addAction(showSearchBox);
searchBox->installEventFilter(this);
diff --git a/qt-ui/csvimportdialog.cpp b/qt-ui/divelogimportdialog.cpp
index b88d9ceca..e5814795d 100644
--- a/qt-ui/csvimportdialog.cpp
+++ b/qt-ui/divelogimportdialog.cpp
@@ -1,22 +1,23 @@
#include <QtDebug>
#include <QFileDialog>
-#include "csvimportdialog.h"
+#include "divelogimportdialog.h"
#include "mainwindow.h"
-#include "ui_csvimportdialog.h"
+#include "ui_divelogimportdialog.h"
-const CSVImportDialog::CSVAppConfig CSVImportDialog::CSVApps[CSVAPPS] = {
+const DiveLogImportDialog::CSVAppConfig DiveLogImportDialog::CSVApps[CSVAPPS] = {
{"", },
{"APD Log Viewer", 1, 2, 16, 7, 18, 19, "Tab"},
{"XP5", 1, 2, 10, -1, -1, -1, "Tab"},
{NULL,}
};
-CSVImportDialog::CSVImportDialog(QWidget *parent) :
+DiveLogImportDialog::DiveLogImportDialog(QStringList *fn, QWidget *parent) :
QDialog(parent),
selector(true),
- ui(new Ui::CSVImportDialog)
+ ui(new Ui::DiveLogImportDialog)
{
ui->setupUi(this);
+ fileNames = *fn;
for (int i = 0; !CSVApps[i].name.isNull(); ++i)
ui->knownImports->addItem(CSVApps[i].name);
@@ -24,7 +25,6 @@ CSVImportDialog::CSVImportDialog(QWidget *parent) :
ui->CSVSeparator->addItem("Tab");
ui->CSVSeparator->addItem(",");
ui->knownImports->setCurrentIndex(1);
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false);
connect(ui->CSVDepth, SIGNAL(valueChanged(int)), this, SLOT(unknownImports(int)));
connect(ui->CSVTime, SIGNAL(valueChanged(int)), this, SLOT(unknownImports(int)));
@@ -38,40 +38,35 @@ CSVImportDialog::CSVImportDialog(QWidget *parent) :
connect(ui->stopdepthCheckBox, SIGNAL(clicked(bool)), this, SLOT(unknownImports(bool)));
}
-CSVImportDialog::~CSVImportDialog()
+DiveLogImportDialog::~DiveLogImportDialog()
{
delete ui;
}
#define VALUE_IF_CHECKED(x) (ui->x->isEnabled() ? ui->x->value() - 1: -1)
-void CSVImportDialog::on_buttonBox_accepted()
+void DiveLogImportDialog::on_buttonBox_accepted()
{
char *error = NULL;
- parse_csv_file(ui->CSVFile->text().toUtf8().data(), ui->CSVTime->value() - 1,
- ui->CSVDepth->value() - 1, VALUE_IF_CHECKED(CSVTemperature),
- VALUE_IF_CHECKED(CSVpo2),
- VALUE_IF_CHECKED(CSVcns),
- VALUE_IF_CHECKED(CSVstopdepth),
- ui->CSVSeparator->currentIndex(),
- &error);
- if (error != NULL) {
- mainWindow()->showError(error);
- free(error);
- error = NULL;
+ for (int i = 0; i < fileNames.size(); ++i) {
+ parse_csv_file(fileNames[i].toUtf8().data(), ui->CSVTime->value() - 1,
+ ui->CSVDepth->value() - 1, VALUE_IF_CHECKED(CSVTemperature),
+ VALUE_IF_CHECKED(CSVpo2),
+ VALUE_IF_CHECKED(CSVcns),
+ VALUE_IF_CHECKED(CSVstopdepth),
+ ui->CSVSeparator->currentIndex(),
+ &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);;All Files(*)"));
- ui->CSVFile->setText(filename);
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!filename.isEmpty());
-}
-
#define SET_VALUE_AND_CHECKBOX(CSV, BOX, VAL) ({\
ui->CSV->blockSignals(true);\
ui->CSV->setValue(VAL);\
@@ -79,7 +74,7 @@ void CSVImportDialog::on_CSVFileSelector_clicked()
ui->BOX->setChecked(VAL >= 0);\
ui->CSV->blockSignals(false);\
})
-void CSVImportDialog::on_knownImports_currentIndexChanged(int index)
+void DiveLogImportDialog::on_knownImports_currentIndexChanged(int index)
{
if (index == 0)
return;
@@ -96,22 +91,17 @@ void CSVImportDialog::on_knownImports_currentIndexChanged(int index)
SET_VALUE_AND_CHECKBOX(CSVstopdepth, stopdepthCheckBox, CSVApps[index].stopdepth);
}
-void CSVImportDialog::unknownImports(bool arg1)
+void DiveLogImportDialog::unknownImports(bool arg1)
{
unknownImports();
}
-void CSVImportDialog::unknownImports(int arg1)
+void DiveLogImportDialog::unknownImports(int arg1)
{
unknownImports();
}
-void CSVImportDialog::unknownImports()
+void DiveLogImportDialog::unknownImports()
{
ui->knownImports->setCurrentIndex(0);
}
-
-void CSVImportDialog::on_CSVFile_textEdited()
-{
- ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!ui->CSVFile->text().isEmpty());
-}
diff --git a/qt-ui/divelogimportdialog.h b/qt-ui/divelogimportdialog.h
new file mode 100644
index 000000000..d8cedab6a
--- /dev/null
+++ b/qt-ui/divelogimportdialog.h
@@ -0,0 +1,49 @@
+#ifndef DIVELOGIMPORTDIALOG_H
+#define DIVELOGIMPORTDIALOG_H
+
+#include <QDialog>
+#include <QModelIndex>
+#include "../dive.h"
+#include "../divelist.h"
+
+namespace Ui {
+class DiveLogImportDialog;
+}
+
+class DiveLogImportDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit DiveLogImportDialog(QStringList *fn, QWidget *parent = 0);
+ ~DiveLogImportDialog();
+
+private slots:
+ void on_buttonBox_accepted();
+ void on_knownImports_currentIndexChanged(int index);
+ void unknownImports(int);
+ void unknownImports(bool);
+
+private:
+ void unknownImports();
+
+ bool selector;
+ QStringList fileNames;
+ Ui::DiveLogImportDialog *ui;
+
+ struct CSVAppConfig {
+ QString name;
+ int time;
+ int depth;
+ int temperature;
+ int po2;
+ int cns;
+ int stopdepth;
+ QString separator;
+ };
+
+#define CSVAPPS 4
+ static const CSVAppConfig CSVApps[CSVAPPS];
+};
+
+#endif // DIVELOGIMPORTDIALOG_H
diff --git a/qt-ui/divelogimportdialog.ui b/qt-ui/divelogimportdialog.ui
new file mode 100644
index 000000000..36f62de54
--- /dev/null
+++ b/qt-ui/divelogimportdialog.ui
@@ -0,0 +1,392 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>DiveLogImportDialog</class>
+ <widget class="QDialog" name="DiveLogImportDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>515</width>
+ <height>370</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Import dive log file</string>
+ </property>
+ <property name="windowIcon">
+ <iconset>
+ <normalon>:/subsurface-icon</normalon>
+ </iconset>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="font">
+ <font>
+ <family>Droid Sans [unknown]</family>
+ <pointsize>14</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="text">
+ <string>Import CSV Dive Log Files</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>CSV options</string>
+ </attribute>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="geometry">
+ <rect>
+ <x>210</x>
+ <y>10</y>
+ <width>281</width>
+ <height>65</height>
+ </rect>
+ </property>
+ <property name="title">
+ <string>Field Separator</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QComboBox" name="CSVSeparator"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_4">
+ <property name="geometry">
+ <rect>
+ <x>210</x>
+ <y>80</y>
+ <width>281</width>
+ <height>65</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Pre-configured imports</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QComboBox" name="knownImports">
+ <property name="currentIndex">
+ <number>-1</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="geometry">
+ <rect>
+ <x>10</x>
+ <y>10</y>
+ <width>185</width>
+ <height>246</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Field Configuration</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="3" column="1">
+ <widget class="QSpinBox" name="CSVpo2">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="CSVDepth">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>2</number>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QSpinBox" name="CSVTemperature">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Depth</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QSpinBox" name="CSVstopdepth">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QCheckBox" name="stopdepthCheckBox">
+ <property name="text">
+ <string>Stopdepth</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="po2CheckBox">
+ <property name="text">
+ <string>PO2</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Time</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="temperatureCheckBox">
+ <property name="text">
+ <string>Temp</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="CSVTime">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QSpinBox" name="CSVcns">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="value">
+ <number>1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="cnsCheckBox">
+ <property name="text">
+ <string>Cns</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ <zorder>label</zorder>
+ <zorder>label_2</zorder>
+ <zorder>CSVTime</zorder>
+ <zorder>CSVDepth</zorder>
+ <zorder>temperatureCheckBox</zorder>
+ <zorder>CSVTemperature</zorder>
+ <zorder>po2CheckBox</zorder>
+ <zorder>CSVpo2</zorder>
+ <zorder>cnsCheckBox</zorder>
+ <zorder>CSVcns</zorder>
+ <zorder>stopdepthCheckBox</zorder>
+ <zorder>CSVstopdepth</zorder>
+ </widget>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <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="QWidget" name="verticalWidget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>DiveLogImportDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>310</x>
+ <y>286</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>215</x>
+ <y>164</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>DiveLogImportDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>310</x>
+ <y>286</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>215</x>
+ <y>164</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>temperatureCheckBox</sender>
+ <signal>clicked(bool)</signal>
+ <receiver>CSVTemperature</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>77</x>
+ <y>191</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>161</x>
+ <y>191</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>po2CheckBox</sender>
+ <signal>clicked(bool)</signal>
+ <receiver>CSVpo2</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>77</x>
+ <y>223</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>161</x>
+ <y>223</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>cnsCheckBox</sender>
+ <signal>clicked(bool)</signal>
+ <receiver>CSVcns</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>77</x>
+ <y>255</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>161</x>
+ <y>255</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>stopdepthCheckBox</sender>
+ <signal>clicked(bool)</signal>
+ <receiver>CSVstopdepth</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>77</x>
+ <y>287</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>161</x>
+ <y>287</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/qt-ui/maintab.cpp b/qt-ui/maintab.cpp
index d149815f6..1de4b6df7 100644
--- a/qt-ui/maintab.cpp
+++ b/qt-ui/maintab.cpp
@@ -980,7 +980,8 @@ void MainTab::editWeightWidget(const QModelIndex& index)
QString MainTab::printGPSCoords(int lat, int lon)
{
unsigned int latdeg, londeg;
- unsigned int ilatmin, ilonmin;
+ unsigned int latmin, lonmin;
+ double latsec, lonsec;
QString lath, lonh, result;
if (!lat && !lon)
@@ -992,11 +993,13 @@ QString MainTab::printGPSCoords(int lat, int lon)
lon = abs(lon);
latdeg = lat / 1000000;
londeg = lon / 1000000;
- ilatmin = (lat % 1000000) * 60;
- ilonmin = (lon % 1000000) * 60;
- result.sprintf("%s%u%s %2d.%05d\' , %s%u%s %2d.%05d\'",
- lath.toUtf8().data(), latdeg, UTF8_DEGREE, ilatmin / 1000000, (ilatmin % 1000000) / 10,
- lonh.toUtf8().data(), londeg, UTF8_DEGREE, ilonmin / 1000000, (ilonmin % 1000000) / 10);
+ latmin = (lat % 1000000) * 60;
+ lonmin = (lon % 1000000) * 60;
+ latsec = (latmin % 1000000) * 60;
+ lonsec = (lonmin % 1000000) * 60;
+ result.sprintf("%u%s%02d\'%06.3f\"%s %u%s%02d\'%06.3f\"%s",
+ latdeg, UTF8_DEGREE, latmin / 1000000, latsec / 1000000, lath.toUtf8().data(),
+ londeg, UTF8_DEGREE, lonmin / 1000000, lonsec / 1000000, lonh.toUtf8().data());
return result;
}
diff --git a/qt-ui/mainwindow.cpp b/qt-ui/mainwindow.cpp
index ad52c7d7f..80da754a2 100644
--- a/qt-ui/mainwindow.cpp
+++ b/qt-ui/mainwindow.cpp
@@ -35,7 +35,7 @@
#include "diveplanner.h"
#include "about.h"
#include "printdialog.h"
-#include "csvimportdialog.h"
+#include "divelogimportdialog.h"
static MainWindow* instance = 0;
@@ -167,15 +167,6 @@ void MainWindow::on_actionClose_triggered()
clear_events();
}
-void MainWindow::on_actionImport_triggered()
-{
- QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Import Files"), lastUsedDir(), filter());
- if (!fileNames.size())
- return; // no selection
- updateLastUsedDir(QFileInfo(fileNames.at(0)).dir().path());
- importFiles(fileNames);
-}
-
QString MainWindow::lastUsedDir()
{
QSettings settings;
@@ -493,27 +484,11 @@ void MainWindow::on_actionAboutSubsurface_triggered()
void MainWindow::on_actionUserManual_triggered()
{
if(!helpView){
- helpView = new QWebView();
- helpView->page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
- connect(helpView, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClickedSlot(QUrl)));
- }
- QString searchPath = getSubsurfaceDataPath("Documentation");
- if (searchPath != "") {
- QUrl url(searchPath.append("/user-manual.html"));
- helpView->setWindowTitle(tr("User Manual"));
- helpView->setWindowIcon(QIcon(":/subsurface-icon"));
- helpView->setUrl(url);
- } else {
- helpView->setHtml(tr("Cannot find the Subsurface manual"));
+ helpView = new UserManual();
}
helpView->show();
}
-void MainWindow::linkClickedSlot(QUrl url)
-{
- QDesktopServices::openUrl(url);
-}
-
QString MainWindow::filter()
{
QString f;
@@ -864,12 +839,26 @@ void MainWindow::loadFiles(const QStringList fileNames)
ui.actionAutoGroup->setChecked(autogroup);
}
-void MainWindow::on_actionImportCSV_triggered()
+void MainWindow::on_actionImportDiveLog_triggered()
{
- CSVImportDialog *csvImport = new CSVImportDialog();
- csvImport->show();
- process_dives(TRUE, FALSE);
- refreshDisplay();
+ QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open Dive Log File"), lastUsedDir(), tr("Dive Log Files (*.xml *.uddf *.udcf *.csv *.jlb *.dld *.sde *.db);;XML Files (*.xml);;UDDF/UDCF Files(*.uddf *.udcf);;JDiveLog Files(*.jlb);;Suunto Files(*.sde *.db);;CSV Files(*.csv);;All Files(*)"));
+
+ if (fileNames.isEmpty())
+ return;
+ updateLastUsedDir(QFileInfo(fileNames[0]).dir().path());
+
+ QStringList logFiles = fileNames.filter( QRegExp("^.*\\.(?!csv)", Qt::CaseInsensitive) ) ;
+ QStringList csvFiles = fileNames.filter(".csv", Qt::CaseInsensitive);
+ if (logFiles.size()) {
+ importFiles(logFiles);
+ }
+
+ if (csvFiles.size()) {
+ DiveLogImportDialog *diveLogImport = new DiveLogImportDialog(&csvFiles);
+ diveLogImport->show();
+ process_dives(TRUE, FALSE);
+ refreshDisplay();
+ }
}
void MainWindow::editCurrentDive()
diff --git a/qt-ui/mainwindow.h b/qt-ui/mainwindow.h
index d4e10e822..7d14fc7fe 100644
--- a/qt-ui/mainwindow.h
+++ b/qt-ui/mainwindow.h
@@ -12,6 +12,7 @@
#include <QUrl>
#include "ui_mainwindow.h"
+#include "usermanual.h"
struct DiveList;
class QSortFilterProxyModel;
@@ -62,7 +63,6 @@ private slots:
void on_actionSave_triggered();
void on_actionSaveAs_triggered();
void on_actionClose_triggered();
- void on_actionImport_triggered();
void on_actionExportUDDF_triggered();
void on_actionPrint_triggered();
void on_actionPreferences_triggered();
@@ -102,8 +102,7 @@ private slots:
void current_dive_changed(int divenr);
void initialUiSetup();
- void on_actionImportCSV_triggered();
- void linkClickedSlot(QUrl url);
+ void on_actionImportDiveLog_triggered();
protected:
void closeEvent(QCloseEvent *);
@@ -118,7 +117,7 @@ private:
Ui::MainWindow ui;
QAction *actionNextDive;
QAction *actionPreviousDive;
- QWebView *helpView;
+ UserManual *helpView;
CurrentState state;
QString filter();
bool askSaveChanges();
diff --git a/qt-ui/mainwindow.ui b/qt-ui/mainwindow.ui
index 60aa787e4..3748f5950 100644
--- a/qt-ui/mainwindow.ui
+++ b/qt-ui/mainwindow.ui
@@ -197,8 +197,7 @@
<string>&amp;Import</string>
</property>
<addaction name="actionDownloadDC"/>
- <addaction name="actionImport"/>
- <addaction name="actionImportCSV"/>
+ <addaction name="actionImportDiveLog"/>
<addaction name="actionDownloadWeb"/>
<addaction name="actionDivelogs_de"/>
</widget>
@@ -264,17 +263,6 @@
<string>Ctrl+W</string>
</property>
</action>
- <action name="actionImport">
- <property name="text">
- <string>Import Files</string>
- </property>
- <property name="toolTip">
- <string>Import Files</string>
- </property>
- <property name="shortcut">
- <string>Ctrl+I</string>
- </property>
- </action>
<action name="actionExportUDDF">
<property name="text">
<string>Export &amp;UDDF</string>
@@ -461,12 +449,15 @@
<string>Ctrl+L</string>
</property>
</action>
- <action name="actionImportCSV">
+ <action name="actionImportDiveLog">
<property name="text">
- <string>Import CSV</string>
+ <string>Import Log Files</string>
</property>
<property name="toolTip">
- <string>Import CS&amp;V</string>
+ <string>Import divelog files from other applications</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+I</string>
</property>
</action>
<action name="actionDivelogs_de">
diff --git a/qt-ui/models.cpp b/qt-ui/models.cpp
index b981793fb..4debafd9a 100644
--- a/qt-ui/models.cpp
+++ b/qt-ui/models.cpp
@@ -1010,6 +1010,7 @@ static int nitrox_sort_value(struct dive *dive)
QVariant DiveItem::data(int column, int role) const
{
QVariant retVal;
+ struct dive *dive = getDiveById(diveId);
switch (role) {
case Qt::TextAlignmentRole:
@@ -1025,6 +1026,7 @@ QVariant DiveItem::data(int column, int role) const
}
break;
case DiveTripModel::SORT_ROLE:
+ Q_ASSERT(dive != NULL);
switch (column) {
case NR: retVal = (qulonglong) dive->when; break;
case DATE: retVal = (qulonglong) dive->when; break;
@@ -1043,6 +1045,7 @@ QVariant DiveItem::data(int column, int role) const
}
break;
case Qt::DisplayRole:
+ Q_ASSERT(dive != NULL);
switch (column) {
case NR: retVal = dive->number; break;
case DATE: retVal = displayDate(); break;
@@ -1061,13 +1064,15 @@ QVariant DiveItem::data(int column, int role) const
break;
}
- if (role == DiveTripModel::STAR_ROLE)
+ if (role == DiveTripModel::STAR_ROLE) {
+ Q_ASSERT(dive != NULL);
retVal = dive->rating;
-
- if (role == DiveTripModel::DIVE_ROLE)
+ }
+ if (role == DiveTripModel::DIVE_ROLE) {
retVal = QVariant::fromValue<void*>(dive);
-
+ }
if(role == DiveTripModel::DIVE_IDX){
+ Q_ASSERT(dive != NULL);
retVal = get_divenr(dive);
}
return retVal;
@@ -1098,21 +1103,26 @@ bool DiveItem::setData(const QModelIndex& index, const QVariant& value, int role
if (d->number == v)
return false;
}
-
- dive->number = value.toInt();
+ d = getDiveById(diveId);
+ Q_ASSERT(d != NULL);
+ d->number = value.toInt();
mark_divelist_changed(TRUE);
return true;
}
QString DiveItem::displayDate() const
{
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
return get_dive_date_string(dive->when);
}
QString DiveItem::displayDepth() const
{
- const int scale = 1000;
QString fract, str;
+ const int scale = 1000;
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
if (get_units()->length == units::METERS) {
fract = QString::number((unsigned)(dive->maxdepth.mm % scale) / 100);
str = QString("%1.%2").arg((unsigned)(dive->maxdepth.mm / scale)).arg(fract, 1, QChar('0'));
@@ -1126,6 +1136,8 @@ QString DiveItem::displayDepth() const
QString DiveItem::displayDuration() const
{
int hrs, mins, secs;
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
secs = dive->duration.seconds % 60;
mins = dive->duration.seconds / 60;
hrs = mins / 60;
@@ -1143,6 +1155,8 @@ QString DiveItem::displayDuration() const
QString DiveItem::displayTemperature() const
{
QString str;
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
if (!dive->watertemp.mkelvin)
return str;
if (get_units()->temperature == units::CELSIUS)
@@ -1155,6 +1169,8 @@ QString DiveItem::displayTemperature() const
QString DiveItem::displaySac() const
{
QString str;
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
if (get_units()->volume == units::LITER)
str = QString::number(dive->sac / 1000.0, 'f', 1).append(tr(" l/min"));
else
@@ -1170,6 +1186,8 @@ QString DiveItem::displayWeight() const
int DiveItem::weight() const
{
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != 0);
weight_t tw = { total_weight(dive) };
return tw.grams;
}
@@ -1237,7 +1255,7 @@ void DiveTripModel::setupModelData()
dive_trip_t* trip = dive->divetrip;
DiveItem* diveItem = new DiveItem();
- diveItem->dive = dive;
+ diveItem->diveId = dive->id;
if (!trip || currentLayout == LIST) {
diveItem->parent = rootItem;
@@ -1644,7 +1662,7 @@ ProfilePrintModel::ProfilePrintModel(QObject *parent)
void ProfilePrintModel::setDive(struct dive *divePtr)
{
- dive = divePtr;
+ diveId = divePtr->id;
// reset();
}
@@ -1665,8 +1683,10 @@ QVariant ProfilePrintModel::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::DisplayRole: {
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
struct DiveItem di;
- di.dive = dive;
+ di.diveId = diveId;
const QString unknown = tr("unknown");
diff --git a/qt-ui/models.h b/qt-ui/models.h
index baa7b32c4..06dc66aa1 100644
--- a/qt-ui/models.h
+++ b/qt-ui/models.h
@@ -157,7 +157,7 @@ struct DiveItem : public TreeItem {
SUIT, CYLINDER, NITROX, SAC, OTU, MAXCNS, LOCATION, COLUMNS };
virtual QVariant data(int column, int role) const;
- struct dive* dive;
+ int diveId;
virtual bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
QString displayDate() const;
@@ -291,7 +291,7 @@ class ProfilePrintModel : public QAbstractTableModel
Q_OBJECT
private:
- struct dive *dive;
+ int diveId;
QString truncateString(char *str, const int maxlen) const;
public:
diff --git a/qt-ui/printlayout.cpp b/qt-ui/printlayout.cpp
index dad940fbb..e60a3189f 100644
--- a/qt-ui/printlayout.cpp
+++ b/qt-ui/printlayout.cpp
@@ -391,7 +391,7 @@ void PrintLayout::printTable()
void PrintLayout::addTablePrintDataRow(TablePrintModel *model, int row, struct dive *dive) const
{
struct DiveItem di;
- di.dive = dive;
+ di.diveId = dive->id;
model->insertRow();
model->setData(model->index(row, 0), QString::number(dive->number), Qt::DisplayRole);
model->setData(model->index(row, 1), di.displayDate(), Qt::DisplayRole);
diff --git a/qt-ui/profilegraphics.cpp b/qt-ui/profilegraphics.cpp
index 76eb64b84..5bb55d11b 100644
--- a/qt-ui/profilegraphics.cpp
+++ b/qt-ui/profilegraphics.cpp
@@ -52,7 +52,7 @@ extern int evn_used;
QPoint(viewport()->geometry().width() - toolBarProxy->boundingRect().width(), \
viewport()->geometry().height() - toolBarProxy->boundingRect().height() )
-ProfileGraphicsView::ProfileGraphicsView(QWidget* parent) : QGraphicsView(parent), toolTip(0) , dive(0), diveDC(0), rulerItem(0), toolBarProxy(0)
+ProfileGraphicsView::ProfileGraphicsView(QWidget* parent) : QGraphicsView(parent), toolTip(0) , diveId(0), diveDC(0), rulerItem(0), toolBarProxy(0)
{
printMode = false;
isGrayscale = false;
@@ -313,8 +313,8 @@ void ProfileGraphicsView::showEvent(QShowEvent* event)
// but the dive was not ploted.
// force a replot by modifying the dive
// hold by the view, and issuing a plot.
- if (dive && !scene()->items().count()) {
- dive = 0;
+ if (diveId && !scene()->items().count()) {
+ diveId = 0;
plot(get_dive(selected_dive));
}
if (toolBarProxy)
@@ -369,14 +369,14 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
if (d)
dc = select_dc(&d->dc);
- if (!forceRedraw && dive == d && (d && dc == diveDC))
+ if (!forceRedraw && getDiveById(diveId) == d && (d && dc == diveDC))
return;
clear();
- dive = d;
+ diveId = d ? d->id : 0;
diveDC = d ? dc : NULL;
- if (!isVisible() || !dive || !mainWindow()) {
+ if (!isVisible() || !d || !mainWindow()) {
return;
}
setBackgroundBrush(getColor(BACKGROUND));
@@ -415,14 +415,14 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
* Set up limits that are independent of
* the dive computer
*/
- calculate_max_limits(dive, dc, &gc);
+ calculate_max_limits(d, dc, &gc);
QRectF profile_grid_area = scene()->sceneRect();
gc.maxx = (profile_grid_area.width() - 2 * profile_grid_area.x());
gc.maxy = (profile_grid_area.height() - 2 * profile_grid_area.y());
/* This is per-dive-computer */
- gc.pi = *create_plot_info(dive, dc, &gc, printMode);
+ gc.pi = *create_plot_info(d, dc, &gc, printMode);
/* Bounding box */
QPen pen = defaultPen;
@@ -483,7 +483,7 @@ void ProfileGraphicsView::plot(struct dive *d, bool forceRedraw)
if(mode == PLAN){
timeEditor = new GraphicsTextEditor();
- timeEditor->setPlainText( dive->duration.seconds ? QString::number(dive->duration.seconds/60) : tr("Set Duration: 10 minutes"));
+ timeEditor->setPlainText(d->duration.seconds ? QString::number(d->duration.seconds/60) : tr("Set Duration: 10 minutes"));
timeEditor->setPos(profile_grid_area.width() - timeEditor->boundingRect().width(), timeMarkers->y());
timeEditor->document();
connect(timeEditor, SIGNAL(editingFinished(QString)), this, SLOT(edit_dive_time(QString)));
@@ -720,6 +720,8 @@ void ProfileGraphicsView::plot_cylinder_pressure_text()
int last_time[MAX_CYLINDERS] = { 0, };
struct plot_data *entry;
struct plot_info *pi = &gc.pi;
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
if (!get_cylinder_pressure_range(&gc))
return;
@@ -888,6 +890,8 @@ void ProfileGraphicsView::plot_cylinder_pressure()
if (!get_cylinder_pressure_range(&gc))
return;
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
QPointF from, to;
for (i = 0; i < gc.pi.nr; i++) {
int mbar;
@@ -1006,7 +1010,8 @@ void ProfileGraphicsView::plot_one_event(struct event *ev)
int x = SCALEXGC(ev->time.seconds);
int y = SCALEYGC(entry->depth);
-
+ struct dive *dive = getDiveById(diveId);
+ Q_ASSERT(dive != NULL);
EventItem *item = new EventItem(ev, 0, isGrayscale);
item->setPos(x, y);
scene()->addItem(item);
diff --git a/qt-ui/profilegraphics.h b/qt-ui/profilegraphics.h
index 064b4478d..b8e939ff8 100644
--- a/qt-ui/profilegraphics.h
+++ b/qt-ui/profilegraphics.h
@@ -190,7 +190,7 @@ private:
QBrush defaultBrush;
ToolTipItem *toolTip;
graphics_context gc;
- struct dive *dive;
+ int diveId;
struct divecomputer *diveDC;
int zoomLevel;
diff --git a/qt-ui/usermanual.cpp b/qt-ui/usermanual.cpp
new file mode 100644
index 000000000..cb9b4da50
--- /dev/null
+++ b/qt-ui/usermanual.cpp
@@ -0,0 +1,93 @@
+#include <QDesktopServices>
+
+#include "usermanual.h"
+#include "ui_usermanual.h"
+
+#include "../helpers.h"
+
+UserManual::UserManual(QWidget *parent) :
+ QMainWindow(parent),
+ ui(new Ui::UserManual)
+{
+ ui->setupUi(this);
+
+ QAction *actionShowSearch = new QAction(this);
+ actionShowSearch->setShortcut(Qt::CTRL + Qt::Key_F);
+ actionShowSearch->setShortcutContext(Qt::WindowShortcut);
+ addAction(actionShowSearch);
+
+ QAction *actionHideSearch = new QAction(this);
+ actionHideSearch->setShortcut(Qt::Key_Escape);
+ actionHideSearch->setShortcutContext(Qt::WindowShortcut);
+ addAction(actionHideSearch);
+
+ setWindowTitle(tr("User Manual"));
+
+ ui->webView->page()->setLinkDelegationPolicy(QWebPage::DelegateExternalLinks);
+ QString searchPath = getSubsurfaceDataPath("Documentation");
+ if (searchPath != "") {
+ QUrl url(searchPath.append("/user-manual.html"));
+ ui->webView->setUrl(url);
+ } else {
+ ui->webView->setHtml(tr("Cannot find the Subsurface manual"));
+ }
+ ui->searchPanel->setParent(this);
+ ui->searchPanel->hide();
+
+ connect(actionShowSearch, SIGNAL(triggered(bool)), this, SLOT(showSearchPanel()));
+ connect(actionHideSearch, SIGNAL(triggered(bool)), this, SLOT(hideSearchPanel()));
+ connect(ui->webView, SIGNAL(linkClicked(QUrl)), this, SLOT(linkClickedSlot(QUrl)));
+ connect(ui->searchEdit, SIGNAL(textChanged(QString)), this, SLOT(searchTextChanged(QString)));
+ connect(ui->findNext, SIGNAL(clicked()), this, SLOT(searchNext()));
+ connect(ui->findPrev, SIGNAL(clicked()), this, SLOT(searchPrev()));
+}
+
+void UserManual::showSearchPanel()
+{
+ ui->searchPanel->show();
+ ui->searchEdit->setFocus();
+ ui->searchEdit->selectAll();
+}
+
+void UserManual::hideSearchPanel()
+{
+ ui->searchPanel->hide();
+}
+
+void UserManual::search(QString text, QWebPage::FindFlags flags = 0)
+{
+ if (ui->webView->findText(text, QWebPage::FindWrapsAroundDocument|flags) || text.length() == 0) {
+ ui->searchEdit->setStyleSheet("");
+ } else {
+ ui->searchEdit->setStyleSheet("QLineEdit{background: red;}");
+ }
+}
+
+void UserManual::searchTextChanged(QString text) {
+ bool hasText = text.length() > 0;
+
+ ui->findPrev->setEnabled(hasText);
+ ui->findNext->setEnabled(hasText);
+
+ search(text);
+}
+
+void UserManual::searchNext()
+{
+ search(ui->searchEdit->text());
+}
+
+void UserManual::searchPrev()
+{
+ search(ui->searchEdit->text(), QWebPage::FindBackward);
+}
+
+void UserManual::linkClickedSlot(QUrl url)
+{
+ QDesktopServices::openUrl(url);
+}
+
+UserManual::~UserManual()
+{
+ delete ui;
+}
diff --git a/qt-ui/usermanual.h b/qt-ui/usermanual.h
new file mode 100644
index 000000000..6c5860206
--- /dev/null
+++ b/qt-ui/usermanual.h
@@ -0,0 +1,32 @@
+#ifndef USERMANUAL_H
+#define USERMANUAL_H
+
+#include <QMainWindow>
+#include <QWebPage>
+
+namespace Ui {
+class UserManual;
+}
+
+class UserManual : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit UserManual(QWidget *parent = 0);
+ ~UserManual();
+
+private slots:
+ void showSearchPanel();
+ void hideSearchPanel();
+ void searchTextChanged(QString);
+ void searchNext();
+ void searchPrev();
+ void linkClickedSlot(QUrl url);
+
+private:
+ Ui::UserManual *ui;
+ void search(QString, QWebPage::FindFlags);
+};
+
+#endif // USERMANUAL_H
diff --git a/qt-ui/usermanual.ui b/qt-ui/usermanual.ui
new file mode 100644
index 000000000..766a0a832
--- /dev/null
+++ b/qt-ui/usermanual.ui
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UserManual</class>
+ <widget class="QMainWindow" name="UserManual">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>834</width>
+ <height>599</height>
+ </rect>
+ </property>
+ <property name="windowIcon">
+ <iconset resource="../subsurface.qrc">
+ <normaloff>:/subsurface-icon</normaloff>:/subsurface-icon</iconset>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QWidget" name="searchPanel" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>230</width>
+ <height>40</height>
+ </size>
+ </property>
+ <property name="autoFillBackground">
+ <bool>true</bool>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>9</number>
+ </property>
+ <property name="topMargin">
+ <number>9</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLineEdit" name="searchEdit">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>100</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="findPrev">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset theme="go-previous">
+ <normaloff/>
+ </iconset>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="findNext">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset theme="go-next">
+ <normaloff/>
+ </iconset>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="findClose">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset theme="window-close">
+ <normaloff/>
+ </iconset>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWebView" name="webView" native="true"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <customwidgets>
+ <customwidget>
+ <class>QWebView</class>
+ <extends>QWidget</extends>
+ <header>qwebview.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="../subsurface.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/qthelper.cpp b/qthelper.cpp
index 9587fcf3f..9d503cb6a 100644
--- a/qthelper.cpp
+++ b/qthelper.cpp
@@ -104,8 +104,9 @@ QString weight_string(int weight_in_grams)
bool parseGpsText(const QString& gps_text, double *latitude, double *longitude)
{
- enum { SECONDS, MINUTES, DECIMAL } gpsStyle = DECIMAL;
+ enum { ISO6709D, SECONDS, MINUTES, DECIMAL } gpsStyle = ISO6709D;
int eastWest = 4;
+ int northSouth = 1;
QString regExp;
/* an empty string is interpreted as 0.0,0.0 and therefore "no gps location" */
if (gps_text.trimmed() == "") {
@@ -114,8 +115,16 @@ bool parseGpsText(const QString& gps_text, double *latitude, double *longitude)
return true;
}
// trying to parse all formats in one regexp might be possible, but it seems insane
- // so handle the three formats we understand separately
- if (gps_text.count(QChar('"')) == 2) {
+ // so handle the four formats we understand separately
+
+ // ISO 6709 Annex D representation
+ // http://en.wikipedia.org/wiki/ISO_6709#Representation_at_the_human_interface_.28Annex_D.29
+ if (gps_text.at(0).isDigit()) {
+ gpsStyle = ISO6709D;
+ regExp = QString("(\\d+)[" UTF8_DEGREE "\\s](\\d+)[\'\\s](\\d+)([,\\.](\\d+))?[\"\\s]([NS%1%2])"
+ "\\s*(\\d+)[" UTF8_DEGREE "\\s](\\d+)[\'\\s](\\d+)([,\\.](\\d+))?[\"\\s]([EW%3%4])")
+ .arg(tr("N")).arg(tr("S")).arg(tr("E")).arg(tr("W"));
+ } else if (gps_text.count(QChar('"')) == 2) {
gpsStyle = SECONDS;
regExp = QString("\\s*([NS%1%2])\\s*(\\d+)[" UTF8_DEGREE "\\s]+(\\d+)[\'\\s]+(\\d+)([,\\.](\\d+))?[^EW%3%4]*"
"([EW%6%7])\\s*(\\d+)[" UTF8_DEGREE "\\s]+(\\d+)[\'\\s]+(\\d+)([,\\.](\\d+))?")
@@ -126,6 +135,7 @@ bool parseGpsText(const QString& gps_text, double *latitude, double *longitude)
"([EW%6%7])\\s*(\\d+)[" UTF8_DEGREE "\\s]+(\\d+)([,\\.](\\d+))?")
.arg(tr("N")).arg(tr("S")).arg(tr("E")).arg(tr("W")).arg(tr("E")).arg(tr("W"));
} else {
+ gpsStyle = DECIMAL;
regExp = QString("\\s*([-NS%1%2]?)\\s*(\\d+)[,\\.](\\d+)[^-EW%3%4\\d]*([-EW%5%6]?)\\s*(\\d+)[,\\.](\\d+)")
.arg(tr("N")).arg(tr("S")).arg(tr("E")).arg(tr("W")).arg(tr("E")).arg(tr("W"));
}
@@ -134,6 +144,14 @@ bool parseGpsText(const QString& gps_text, double *latitude, double *longitude)
// qDebug() << "Hemisphere" << r.cap(1) << "deg" << r.cap(2) << "min" << r.cap(3) << "decimal" << r.cap(4);
// qDebug() << "Hemisphere" << r.cap(5) << "deg" << r.cap(6) << "min" << r.cap(7) << "decimal" << r.cap(8);
switch(gpsStyle) {
+ case ISO6709D:
+ *latitude = r.cap(1).toInt() + r.cap(2).toInt() / 60.0 +
+ (r.cap(3) + QString(".") + r.cap(5)).toDouble() / 3600.0;
+ *longitude = r.cap(7).toInt() + r.cap(8).toInt() / 60.0 +
+ (r.cap(9) + QString(".") + r.cap(11)).toDouble() / 3600.0;
+ northSouth = 6;
+ eastWest = 12;
+ break;
case SECONDS:
*latitude = r.cap(2).toInt() + r.cap(3).toInt() / 60.0 +
(r.cap(4) + QString(".") + r.cap(6)).toDouble() / 3600.0;
@@ -147,15 +165,14 @@ bool parseGpsText(const QString& gps_text, double *latitude, double *longitude)
eastWest = 6;
break;
case DECIMAL:
- default:
+ default:
*latitude = (r.cap(2) + QString(".") + r.cap(3)).toDouble();
*longitude = (r.cap(5) + QString(".") + r.cap(6)).toDouble();
- eastWest = 4;
break;
}
- if (r.cap(1) == "S" || r.cap(1) == tr("S") || r.cap(1) == "-")
+ if (r.cap(northSouth) == "S" || r.cap(northSouth) == tr("S") || r.cap(northSouth) == "-")
*latitude *= -1.0;
- if (r.cap(eastWest) == "W" || r.cap(5) == tr("W") || r.cap(5) == "-")
+ if (r.cap(eastWest) == "W" || r.cap(eastWest) == tr("W") || r.cap(eastWest) == "-")
*longitude *= -1.0;
// qDebug("%s -> %8.5f / %8.5f", gps_text.toLocal8Bit().data(), *latitude, *longitude);
return true;
@@ -200,3 +217,27 @@ QList< int > getDivesInTrip ( dive_trip_t* trip )
}
return ret;
}
+
+// we need this to be uniq, but also make sure
+// it doesn't change during the life time of a Subsurface session
+// oh, and it has no meaning whatsoever - that's why we have the
+// silly initial number and increment by 3 :-)
+int getUniqID(struct dive *d)
+{
+ static QSet<int> ids;
+ static int maxId = 83529;
+
+ int id = d->id;
+ if (id) {
+ if (!ids.contains(id)) {
+ qDebug() << "WTF - only I am allowed to create IDs";
+ ids.insert(id);
+ }
+ return id;
+ }
+ maxId += 3;
+ id = maxId;
+ Q_ASSERT(!ids.contains(id));
+ ids.insert(id);
+ return id;
+}
diff --git a/subsurface.pro b/subsurface.pro
index 5d51d242a..d230b3885 100644
--- a/subsurface.pro
+++ b/subsurface.pro
@@ -54,9 +54,10 @@ HEADERS = \
subsurfacestartup.h \
uemis.h \
webservice.h \
- qt-ui/csvimportdialog.h \
+ qt-ui/divelogimportdialog.h \
qt-ui/tagwidget.h \
- qt-ui/groupedlineedit.h
+ qt-ui/groupedlineedit.h \
+ qt-ui/usermanual.h
SOURCES = \
deco.c \
@@ -103,9 +104,10 @@ SOURCES = \
time.c \
uemis.c \
uemis-downloader.c \
- qt-ui/csvimportdialog.cpp \
+ qt-ui/divelogimportdialog.cpp \
qt-ui/tagwidget.cpp \
- qt-ui/groupedlineedit.cpp
+ qt-ui/groupedlineedit.cpp \
+ qt-ui/usermanual.cpp
linux*: SOURCES += linux.c
mac: SOURCES += macos.c
@@ -124,7 +126,8 @@ FORMS = \
qt-ui/shifttimes.ui \
qt-ui/webservices.ui \
qt-ui/tableview.ui \
- qt-ui/csvimportdialog.ui
+ qt-ui/divelogimportdialog.ui \
+ qt-ui/usermanual.ui
RESOURCES = subsurface.qrc