mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Merge branch 'master' into freediving-tweaks
Signed-off-by: Maximilian Güntner <maximilian.guentner@gmail.com>
This commit is contained in:
commit
0c0ec7e4f6
20 changed files with 1818 additions and 639 deletions
8
Makefile
8
Makefile
|
@ -51,19 +51,19 @@ libdc-usr64 := $(wildcard /usr/lib64/libdivecomputer.a)
|
|||
|
||||
ifneq ($(strip $(libdc-local)),)
|
||||
LIBDIVECOMPUTERDIR = /usr/local
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include/libdivecomputer
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include
|
||||
LIBDIVECOMPUTERARCHIVE = $(LIBDIVECOMPUTERDIR)/lib/libdivecomputer.a
|
||||
else ifneq ($(strip $(libdc-local64)),)
|
||||
LIBDIVECOMPUTERDIR = /usr/local
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include/libdivecomputer
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include
|
||||
LIBDIVECOMPUTERARCHIVE = $(LIBDIVECOMPUTERDIR)/lib64/libdivecomputer.a
|
||||
else ifneq ($(strip $(libdc-usr)),)
|
||||
LIBDIVECOMPUTERDIR = /usr
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include/libdivecomputer
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include
|
||||
LIBDIVECOMPUTERARCHIVE = $(LIBDIVECOMPUTERDIR)/lib/libdivecomputer.a
|
||||
else ifneq ($(strip $(libdc-usr64)),)
|
||||
LIBDIVECOMPUTERDIR = /usr
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include/libdivecomputer
|
||||
LIBDIVECOMPUTERINCLUDES = -I$(LIBDIVECOMPUTERDIR)/include
|
||||
LIBDIVECOMPUTERARCHIVE = $(LIBDIVECOMPUTERDIR)/lib64/libdivecomputer.a
|
||||
else
|
||||
$(error Cannot find libdivecomputer - please edit Makefile)
|
||||
|
|
59
cochran.c
59
cochran.c
|
@ -150,6 +150,64 @@ static void parse_cochran_header(const char *filename,
|
|||
free(buf);
|
||||
}
|
||||
|
||||
/*
|
||||
* Cochran export files show that depths seem to be in
|
||||
* quarter feet (rounded up to tenths).
|
||||
*
|
||||
* Temperature seems to be exported in Fahrenheit.
|
||||
*
|
||||
* Cylinder pressure seems to be in multiples of 4 psi.
|
||||
*
|
||||
* The data seems to be some byte-stream where the pattern
|
||||
* appears to be that the two high bits indicate type of
|
||||
* data.
|
||||
*
|
||||
* For '00', the low six bits seem to be positive
|
||||
* values with a distribution towards zero, probably depth
|
||||
* deltas. '0 0' exists, but is very rare ("surface"?). 63
|
||||
* exists, but is rare.
|
||||
*
|
||||
* For '01', the low six bits seem to be a signed binary value,
|
||||
* with the most common being 0, and 1 and -1 (63) being the
|
||||
* next most common values.
|
||||
*
|
||||
* NOTE! Don's CAN data is different. It shows the reverse pattern
|
||||
* for 00 and 01 above: 00 looks like signed data, with 01 looking
|
||||
* like unsigned data.
|
||||
*
|
||||
* For '10', there seems to be another positive value distribution,
|
||||
* but unlike '00' the value 0 is common, and I see examples of 63
|
||||
* too ("overflow"?) and a spike at '7'.
|
||||
*
|
||||
* Again, Don's data is different.
|
||||
*
|
||||
* The values for '11' seem to be some exception case. Possibly
|
||||
* overflow handling, possibly warning events. It doesn't have
|
||||
* any clear distribution: values 0, 1, 16, 33, 35, 48, 51, 55
|
||||
* and 63 are common.
|
||||
*
|
||||
* For David and Don's data, '01' is the most common, with '00'
|
||||
* and '10' not uncommon. '11' is two orders of magnitude less
|
||||
* common.
|
||||
*
|
||||
* For Alex, '00' is the most common, with 01 about a third as
|
||||
* common, and 02 a third of that. 11 is least common.
|
||||
*
|
||||
* There clearly are variations in the format here. And Alex has
|
||||
* a different data offset than Don/David too (see the #ifdef DON).
|
||||
* Christ. Maybe I've misread the patterns entirely.
|
||||
*/
|
||||
static void cochran_profile_write(const unsigned char *buf, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
unsigned char c = buf[i];
|
||||
printf("%d %d\n",
|
||||
c >> 6, c & 0x3f);
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_cochran_dive(const char *filename, int dive,
|
||||
const unsigned char *decode, unsigned mod,
|
||||
const unsigned char *in, unsigned size)
|
||||
|
@ -187,6 +245,7 @@ static void parse_cochran_dive(const char *filename, int dive,
|
|||
|
||||
printf("\n%s, dive %d\n\n", filename, dive);
|
||||
cochran_debug_write(filename, buf, size);
|
||||
cochran_profile_write(buf + offset, size - offset);
|
||||
|
||||
free(buf);
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ typedef struct {
|
|||
typedef struct {
|
||||
gboolean cylinder;
|
||||
gboolean temperature;
|
||||
gboolean totalweight;
|
||||
gboolean suit;
|
||||
gboolean nitrox;
|
||||
gboolean sac;
|
||||
gboolean otu;
|
||||
|
@ -29,9 +31,11 @@ typedef enum {
|
|||
|
||||
#if defined __APPLE__
|
||||
#define CTRLCHAR "<Meta>"
|
||||
#define SHIFTCHAR "<Shift>"
|
||||
#define PREFERENCE_ACCEL "<Meta>comma"
|
||||
#else
|
||||
#define CTRLCHAR "<Control>"
|
||||
#define SHIFTCHAR "<Shift>"
|
||||
#define PREFERENCE_ACCEL NULL
|
||||
#endif
|
||||
|
||||
|
@ -54,6 +58,7 @@ extern const char *divelist_font;
|
|||
extern void set_divelist_font(const char *);
|
||||
|
||||
extern void import_dialog(GtkWidget *, gpointer);
|
||||
extern void add_dive_cb(GtkWidget *, gpointer);
|
||||
extern void report_error(GError* error);
|
||||
extern int process_ui_events(void);
|
||||
extern void update_progressbar(progressbar_t *progress, double value);
|
||||
|
@ -62,16 +67,17 @@ extern void update_progressbar_text(progressbar_t *progress, const char *text);
|
|||
extern GtkWidget *dive_profile_widget(void);
|
||||
extern GtkWidget *dive_info_frame(void);
|
||||
extern GtkWidget *extended_dive_info_widget(void);
|
||||
extern GtkWidget *equipment_widget(void);
|
||||
extern GtkWidget *equipment_widget(int w_idx);
|
||||
extern GtkWidget *single_stats_widget(void);
|
||||
extern GtkWidget *total_stats_widget(void);
|
||||
extern GtkWidget *cylinder_list_widget(void);
|
||||
extern GtkWidget *cylinder_list_widget(int w_idx);
|
||||
extern GtkWidget *weightsystem_list_widget(int w_idx);
|
||||
|
||||
extern GtkWidget *dive_list_create(void);
|
||||
|
||||
unsigned int amount_selected;
|
||||
|
||||
extern void process_selected_dives(GList *, GtkTreeModel *);
|
||||
extern void process_selected_dives(void);
|
||||
|
||||
typedef void (*data_func_t)(GtkTreeViewColumn *col,
|
||||
GtkCellRenderer *renderer,
|
||||
|
|
42
dive.c
42
dive.c
|
@ -120,6 +120,28 @@ double get_depth_units(unsigned int mm, int *frac, const char **units)
|
|||
return d;
|
||||
}
|
||||
|
||||
double get_weight_units(unsigned int grams, int *frac, const char **units)
|
||||
{
|
||||
int decimals;
|
||||
double value;
|
||||
const char* unit;
|
||||
|
||||
if (output_units.weight == LBS) {
|
||||
value = grams_to_lbs(grams);
|
||||
unit = "lbs";
|
||||
decimals = 0;
|
||||
} else {
|
||||
value = grams / 1000.0;
|
||||
unit = "kg";
|
||||
decimals = 1;
|
||||
}
|
||||
if (frac)
|
||||
*frac = decimals;
|
||||
if (units)
|
||||
*units = unit;
|
||||
return value;
|
||||
}
|
||||
|
||||
struct dive *alloc_dive(void)
|
||||
{
|
||||
const int initial_samples = 5;
|
||||
|
@ -450,8 +472,20 @@ struct dive *fixup_dive(struct dive *dive)
|
|||
cyl->sample_end.mbar = 0;
|
||||
}
|
||||
}
|
||||
if (end < 0)
|
||||
if (end < 0) {
|
||||
/* Assume an ascent/descent rate of 9 m/min */
|
||||
int depth = dive->maxdepth.mm;
|
||||
int asc_desc_time = depth*60/9000;
|
||||
int duration = dive->duration.seconds;
|
||||
|
||||
/* Protect against insane dives - make mean be half of max */
|
||||
if (duration <= asc_desc_time) {
|
||||
duration = 2;
|
||||
asc_desc_time = 1;
|
||||
}
|
||||
dive->meandepth.mm = depth*(duration-asc_desc_time)/duration;
|
||||
return dive;
|
||||
}
|
||||
|
||||
update_duration(&dive->duration, end - start);
|
||||
if (start != end)
|
||||
|
@ -464,6 +498,7 @@ struct dive *fixup_dive(struct dive *dive)
|
|||
add_people(dive->buddy);
|
||||
add_people(dive->divemaster);
|
||||
add_location(dive->location);
|
||||
add_suit(dive->suit);
|
||||
for (i = 0; i < MAX_CYLINDERS; i++) {
|
||||
cylinder_t *cyl = dive->cylinder + i;
|
||||
add_cylinder_description(&cyl->type);
|
||||
|
@ -472,6 +507,10 @@ struct dive *fixup_dive(struct dive *dive)
|
|||
if (same_rounded_pressure(cyl->sample_end, cyl->end))
|
||||
cyl->end.mbar = 0;
|
||||
}
|
||||
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++) {
|
||||
weightsystem_t *ws = dive->weightsystem + i;
|
||||
add_weightsystem_description(ws);
|
||||
}
|
||||
|
||||
return dive;
|
||||
}
|
||||
|
@ -677,6 +716,7 @@ struct dive *try_to_merge(struct dive *a, struct dive *b)
|
|||
MERGE_TXT(res, a, b, buddy);
|
||||
MERGE_TXT(res, a, b, divemaster);
|
||||
MERGE_MAX(res, a, b, rating);
|
||||
MERGE_TXT(res, a, b, suit);
|
||||
MERGE_MAX(res, a, b, number);
|
||||
MERGE_MAX(res, a, b, maxdepth.mm);
|
||||
res->meandepth.mm = 0;
|
||||
|
|
54
dive.h
54
dive.h
|
@ -92,13 +92,17 @@ typedef struct {
|
|||
const char *description; /* "integrated", "belt", "ankle" */
|
||||
} weightsystem_t;
|
||||
|
||||
extern int cylinder_none(void *_data);
|
||||
extern int weightsystem_none(void *_data);
|
||||
extern gboolean cylinder_none(void *_data);
|
||||
extern gboolean no_cylinders(cylinder_t *cyl);
|
||||
extern gboolean cylinders_equal(cylinder_t *cyl1, cylinder_t *cyl2);
|
||||
extern gboolean no_weightsystems(weightsystem_t *ws);
|
||||
extern gboolean weightsystems_equal(weightsystem_t *ws1, weightsystem_t *ws2);
|
||||
|
||||
extern int get_pressure_units(unsigned int mb, const char **units);
|
||||
extern double get_depth_units(unsigned int mm, int *frac, const char **units);
|
||||
extern double get_volume_units(unsigned int mm, int *frac, const char **units);
|
||||
extern double get_temp_units(unsigned int mm, const char **units);
|
||||
extern double get_volume_units(unsigned int ml, int *frac, const char **units);
|
||||
extern double get_temp_units(unsigned int mk, const char **units);
|
||||
extern double get_weight_units(unsigned int grams, int *frac, const char **units);
|
||||
|
||||
static inline double grams_to_lbs(int grams)
|
||||
{
|
||||
|
@ -125,21 +129,31 @@ static inline double mm_to_feet(int mm)
|
|||
return mm * 0.00328084;
|
||||
}
|
||||
|
||||
static inline unsigned long feet_to_mm(double feet)
|
||||
{
|
||||
return feet * 304.8 + 0.5;
|
||||
}
|
||||
|
||||
static inline int to_feet(depth_t depth)
|
||||
{
|
||||
return mm_to_feet(depth.mm) + 0.5;
|
||||
}
|
||||
|
||||
static double mkelvin_to_C(int mkelvin)
|
||||
static inline double mkelvin_to_C(int mkelvin)
|
||||
{
|
||||
return (mkelvin - 273150) / 1000.0;
|
||||
}
|
||||
|
||||
static double mkelvin_to_F(int mkelvin)
|
||||
static inline double mkelvin_to_F(int mkelvin)
|
||||
{
|
||||
return mkelvin * 9 / 5000.0 - 459.670;
|
||||
}
|
||||
|
||||
static inline unsigned long F_to_mkelvin(double f)
|
||||
{
|
||||
return (f-32) * 1000 / 1.8 + 273150.5;
|
||||
}
|
||||
|
||||
static inline int to_C(temperature_t temp)
|
||||
{
|
||||
if (!temp.mkelvin)
|
||||
|
@ -165,6 +179,12 @@ static inline double psi_to_bar(double psi)
|
|||
{
|
||||
return psi / 14.5037738;
|
||||
}
|
||||
|
||||
static inline unsigned long psi_to_mbar(double psi)
|
||||
{
|
||||
return psi_to_bar(psi)*1000 + 0.5;
|
||||
}
|
||||
|
||||
static inline int to_PSI(pressure_t pressure)
|
||||
{
|
||||
return pressure.mbar * 0.0145037738 + 0.5;
|
||||
|
@ -211,9 +231,12 @@ struct event {
|
|||
|
||||
#define MAX_CYLINDERS (8)
|
||||
#define MAX_WEIGHTSYSTEMS (4)
|
||||
#define W_IDX_PRIMARY 0
|
||||
#define W_IDX_SECONDARY 1
|
||||
|
||||
struct dive {
|
||||
int number;
|
||||
int selected;
|
||||
time_t when;
|
||||
char *location;
|
||||
char *notes;
|
||||
|
@ -226,6 +249,7 @@ struct dive {
|
|||
temperature_t airtemp, watertemp;
|
||||
cylinder_t cylinder[MAX_CYLINDERS];
|
||||
weightsystem_t weightsystem[MAX_WEIGHTSYSTEMS];
|
||||
char *suit;
|
||||
int sac, otu;
|
||||
struct event *events;
|
||||
int samples, alloc_samples;
|
||||
|
@ -266,11 +290,21 @@ extern int selected_dive;
|
|||
|
||||
static inline struct dive *get_dive(unsigned int nr)
|
||||
{
|
||||
if (nr >= dive_table.nr)
|
||||
if (nr >= dive_table.nr || nr < 0)
|
||||
return NULL;
|
||||
return dive_table.dives[nr];
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over each dive, with the first parameter being the index
|
||||
* iterator variable, and the second one being the dive one.
|
||||
*
|
||||
* I don't think anybody really wants the index, and we could make
|
||||
* it local to the for-loop, but that would make us requires C99.
|
||||
*/
|
||||
#define for_each_dive(_i,_x) \
|
||||
for ((_i) = 0; ((_x) = get_dive(_i)) != NULL; (_i)++)
|
||||
|
||||
extern void parse_xml_init(void);
|
||||
extern void parse_xml_buffer(const char *url, const char *buf, int size, GError **error);
|
||||
extern void set_filename(const char *filename);
|
||||
|
@ -283,7 +317,7 @@ extern xmlDoc *test_xslt_transforms(xmlDoc *doc);
|
|||
|
||||
extern void show_dive_info(struct dive *);
|
||||
|
||||
extern void show_dive_equipment(struct dive *);
|
||||
extern void show_dive_equipment(struct dive *, int w_idx);
|
||||
|
||||
extern void show_dive_stats(struct dive *);
|
||||
|
||||
|
@ -322,12 +356,16 @@ extern void exit_ui(void);
|
|||
extern void report_error(GError* error);
|
||||
|
||||
extern void add_cylinder_description(cylinder_type_t *);
|
||||
extern void add_weightsystem_description(weightsystem_t *);
|
||||
extern void add_people(const char *string);
|
||||
extern void add_location(const char *string);
|
||||
extern void add_suit(const char *string);
|
||||
extern void remember_event(const char *eventname);
|
||||
extern void evn_foreach(void (*callback)(const char *, int *, void *), void *data);
|
||||
|
||||
extern int add_new_dive(struct dive *dive);
|
||||
extern int edit_dive_info(struct dive *dive);
|
||||
extern int edit_multi_dive_info(struct dive *single_dive);
|
||||
extern void dive_list_update_dives(void);
|
||||
extern void flush_divelist(struct dive *dive);
|
||||
|
||||
|
|
841
divelist.c
841
divelist.c
File diff suppressed because it is too large
Load diff
251
equipment.c
251
equipment.c
|
@ -2,10 +2,10 @@
|
|||
/* creates the UI for the equipment page -
|
||||
* controlled through the following interfaces:
|
||||
*
|
||||
* void show_dive_equipment(struct dive *dive)
|
||||
* void show_dive_equipment(struct dive *dive, int w_idx)
|
||||
*
|
||||
* called from gtk-ui:
|
||||
* GtkWidget *equipment_widget(void)
|
||||
* GtkWidget *equipment_widget(int w_idx)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -40,10 +40,11 @@ enum {
|
|||
struct equipment_list {
|
||||
int max_index;
|
||||
GtkListStore *model;
|
||||
GtkTreeView *tree_view;
|
||||
GtkWidget *edit, *add, *del;
|
||||
};
|
||||
|
||||
static struct equipment_list cylinder_list, weightsystem_list;
|
||||
static struct equipment_list cylinder_list[2], weightsystem_list[2];
|
||||
|
||||
|
||||
struct cylinder_widget {
|
||||
|
@ -308,13 +309,15 @@ static GtkTreeIter *add_weightsystem_type(const char *desc, int weight, GtkTreeI
|
|||
model = GTK_TREE_MODEL(weightsystem_model);
|
||||
gtk_tree_model_foreach(model, match_desc, (void *)desc);
|
||||
|
||||
if (!found_match) {
|
||||
GtkListStore *store = GTK_LIST_STORE(model);
|
||||
|
||||
gtk_list_store_append(store, iter);
|
||||
gtk_list_store_set(store, iter,
|
||||
0, desc,
|
||||
1, weight,
|
||||
if (found_match) {
|
||||
gtk_list_store_set(GTK_LIST_STORE(model), found_match,
|
||||
WS_WEIGHT, weight,
|
||||
-1);
|
||||
} else if (desc && desc[0]) {
|
||||
gtk_list_store_append(GTK_LIST_STORE(model), iter);
|
||||
gtk_list_store_set(GTK_LIST_STORE(model), iter,
|
||||
WS_DESC, desc,
|
||||
WS_WEIGHT, weight,
|
||||
-1);
|
||||
return iter;
|
||||
}
|
||||
|
@ -425,7 +428,7 @@ static void show_weightsystem(weightsystem_t *ws, struct ws_widget *weightsystem
|
|||
set_weight_weight_spinbutton(weightsystem_widget, ws->weight.grams);
|
||||
}
|
||||
|
||||
int cylinder_none(void *_data)
|
||||
gboolean cylinder_none(void *_data)
|
||||
{
|
||||
cylinder_t *cyl = _data;
|
||||
return !cyl->type.size.mliter &&
|
||||
|
@ -439,12 +442,77 @@ int cylinder_none(void *_data)
|
|||
!cyl->end.mbar;
|
||||
}
|
||||
|
||||
int weightsystem_none(void *_data)
|
||||
gboolean no_cylinders(cylinder_t *cyl)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CYLINDERS; i++)
|
||||
if (!cylinder_none(cyl + i))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* descriptions are equal if they are both NULL or both non-NULL
|
||||
and the same text */
|
||||
gboolean description_equal(const char *desc1, const char *desc2)
|
||||
{
|
||||
return ((! desc1 && ! desc2) ||
|
||||
(desc1 && desc2 && strcmp(desc1, desc2) == 0));
|
||||
}
|
||||
|
||||
/* when checking for the same cylinder we want the size and description to match
|
||||
but don't compare the start and end pressures */
|
||||
static gboolean one_cylinder_equal(cylinder_t *cyl1, cylinder_t *cyl2)
|
||||
{
|
||||
return cyl1->type.size.mliter == cyl2->type.size.mliter &&
|
||||
cyl1->type.workingpressure.mbar == cyl2->type.workingpressure.mbar &&
|
||||
cyl1->gasmix.o2.permille == cyl2->gasmix.o2.permille &&
|
||||
cyl1->gasmix.he.permille == cyl2->gasmix.he.permille &&
|
||||
description_equal(cyl1->type.description, cyl2->type.description);
|
||||
}
|
||||
|
||||
gboolean cylinders_equal(cylinder_t *cyl1, cylinder_t *cyl2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_CYLINDERS; i++)
|
||||
if (!one_cylinder_equal(cyl1 + i, cyl2 + i))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean weightsystem_none(void *_data)
|
||||
{
|
||||
weightsystem_t *ws = _data;
|
||||
return !ws->weight.grams && !ws->description;
|
||||
}
|
||||
|
||||
gboolean no_weightsystems(weightsystem_t *ws)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++)
|
||||
if (!weightsystem_none(ws + i))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean one_weightsystem_equal(weightsystem_t *ws1, weightsystem_t *ws2)
|
||||
{
|
||||
return ws1->weight.grams == ws2->weight.grams &&
|
||||
description_equal(ws1->description, ws2->description);
|
||||
}
|
||||
|
||||
gboolean weightsystems_equal(weightsystem_t *ws1, weightsystem_t *ws2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++)
|
||||
if (!one_weightsystem_equal(ws1 + i, ws2 + i))
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void set_one_cylinder(void *_data, GtkListStore *model, GtkTreeIter *iter)
|
||||
{
|
||||
cylinder_t *cyl = _data;
|
||||
|
@ -490,7 +558,7 @@ static void *ws_ptr(struct dive *dive, int idx)
|
|||
static void show_equipment(struct dive *dive, int max,
|
||||
struct equipment_list *equipment_list,
|
||||
void*(*ptr_function)(struct dive*, int),
|
||||
int(*none_function)(void *),
|
||||
gboolean(*none_function)(void *),
|
||||
void(*set_one_function)(void*, GtkListStore*, GtkTreeIter *))
|
||||
{
|
||||
int i, used;
|
||||
|
@ -519,11 +587,11 @@ static void show_equipment(struct dive *dive, int max,
|
|||
}
|
||||
}
|
||||
|
||||
void show_dive_equipment(struct dive *dive)
|
||||
void show_dive_equipment(struct dive *dive, int w_idx)
|
||||
{
|
||||
show_equipment(dive, MAX_CYLINDERS, &cylinder_list,
|
||||
show_equipment(dive, MAX_CYLINDERS, &cylinder_list[w_idx],
|
||||
&cyl_ptr, &cylinder_none, &set_one_cylinder);
|
||||
show_equipment(dive, MAX_WEIGHTSYSTEMS, &weightsystem_list,
|
||||
show_equipment(dive, MAX_WEIGHTSYSTEMS, &weightsystem_list[w_idx],
|
||||
&ws_ptr, &weightsystem_none, &set_one_weightsystem);
|
||||
}
|
||||
|
||||
|
@ -623,6 +691,7 @@ static void record_weightsystem_changes(weightsystem_t *ws, struct ws_widget *we
|
|||
GtkComboBox *box;
|
||||
int grams;
|
||||
double value;
|
||||
GtkTreeIter iter;
|
||||
|
||||
/* Ignore uninitialized cylinder widgets */
|
||||
box = weightsystem_widget->description;
|
||||
|
@ -638,6 +707,7 @@ static void record_weightsystem_changes(weightsystem_t *ws, struct ws_widget *we
|
|||
grams = value * 1000;
|
||||
ws->weight.grams = grams;
|
||||
ws->description = desc;
|
||||
add_weightsystem_type(desc, grams, &iter);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -744,8 +814,6 @@ static struct ws_info {
|
|||
const char *name;
|
||||
int grams;
|
||||
} ws_info[100] = {
|
||||
/* Need an empty entry for the no weight system case */
|
||||
{ "", },
|
||||
{ "integrated", 0 },
|
||||
{ "belt", 0 },
|
||||
{ "ankle", 0 },
|
||||
|
@ -1061,11 +1129,12 @@ static int get_model_index(GtkListStore *model, GtkTreeIter *iter)
|
|||
return index;
|
||||
}
|
||||
|
||||
static void edit_cb(GtkButton *button, GtkTreeView *tree_view)
|
||||
static void edit_cb(GtkButton *button, int w_idx)
|
||||
{
|
||||
int index;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *model = cylinder_list.model;
|
||||
GtkListStore *model = cylinder_list[w_idx].model;
|
||||
GtkTreeView *tree_view = cylinder_list[w_idx].tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
cylinder_t cyl;
|
||||
|
||||
|
@ -1083,11 +1152,12 @@ static void edit_cb(GtkButton *button, GtkTreeView *tree_view)
|
|||
repaint_dive();
|
||||
}
|
||||
|
||||
static void add_cb(GtkButton *button, GtkTreeView *tree_view)
|
||||
static void add_cb(GtkButton *button, int w_idx)
|
||||
{
|
||||
int index = cylinder_list.max_index;
|
||||
int index = cylinder_list[w_idx].max_index;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *model = cylinder_list.model;
|
||||
GtkListStore *model = cylinder_list[w_idx].model;
|
||||
GtkTreeView *tree_view = cylinder_list[w_idx].tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
cylinder_t cyl;
|
||||
|
||||
|
@ -1100,15 +1170,16 @@ static void add_cb(GtkButton *button, GtkTreeView *tree_view)
|
|||
selection = gtk_tree_view_get_selection(tree_view);
|
||||
gtk_tree_selection_select_iter(selection, &iter);
|
||||
|
||||
cylinder_list.max_index++;
|
||||
gtk_widget_set_sensitive(cylinder_list.add, cylinder_list.max_index < MAX_CYLINDERS);
|
||||
cylinder_list[w_idx].max_index++;
|
||||
gtk_widget_set_sensitive(cylinder_list[w_idx].add, cylinder_list[w_idx].max_index < MAX_CYLINDERS);
|
||||
}
|
||||
|
||||
static void del_cb(GtkButton *button, GtkTreeView *tree_view)
|
||||
static void del_cb(GtkButton *button, int w_idx)
|
||||
{
|
||||
int index, nr;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *model = cylinder_list.model;
|
||||
GtkListStore *model = cylinder_list[w_idx].model;
|
||||
GtkTreeView *tree_view = cylinder_list[w_idx].tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
struct dive *dive;
|
||||
cylinder_t *cyl;
|
||||
|
@ -1125,27 +1196,28 @@ static void del_cb(GtkButton *button, GtkTreeView *tree_view)
|
|||
if (!dive)
|
||||
return;
|
||||
cyl = dive->cylinder + index;
|
||||
nr = cylinder_list.max_index - index - 1;
|
||||
nr = cylinder_list[w_idx].max_index - index - 1;
|
||||
|
||||
gtk_list_store_remove(model, &iter);
|
||||
|
||||
cylinder_list.max_index--;
|
||||
cylinder_list[w_idx].max_index--;
|
||||
memmove(cyl, cyl+1, nr*sizeof(*cyl));
|
||||
memset(cyl+nr, 0, sizeof(*cyl));
|
||||
|
||||
mark_divelist_changed(TRUE);
|
||||
flush_divelist(dive);
|
||||
|
||||
gtk_widget_set_sensitive(cylinder_list.edit, 0);
|
||||
gtk_widget_set_sensitive(cylinder_list.del, 0);
|
||||
gtk_widget_set_sensitive(cylinder_list.add, 1);
|
||||
gtk_widget_set_sensitive(cylinder_list[w_idx].edit, 0);
|
||||
gtk_widget_set_sensitive(cylinder_list[w_idx].del, 0);
|
||||
gtk_widget_set_sensitive(cylinder_list[w_idx].add, 1);
|
||||
}
|
||||
|
||||
static void ws_edit_cb(GtkButton *button, GtkTreeView *tree_view)
|
||||
static void ws_edit_cb(GtkButton *button, int w_idx)
|
||||
{
|
||||
int index;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *model = weightsystem_list.model;
|
||||
GtkListStore *model = weightsystem_list[w_idx].model;
|
||||
GtkTreeView *tree_view = weightsystem_list[w_idx].tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
weightsystem_t ws;
|
||||
|
||||
|
@ -1163,11 +1235,12 @@ static void ws_edit_cb(GtkButton *button, GtkTreeView *tree_view)
|
|||
repaint_dive();
|
||||
}
|
||||
|
||||
static void ws_add_cb(GtkButton *button, GtkTreeView *tree_view)
|
||||
static void ws_add_cb(GtkButton *button, int w_idx)
|
||||
{
|
||||
int index = weightsystem_list.max_index;
|
||||
int index = weightsystem_list[w_idx].max_index;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *model = weightsystem_list.model;
|
||||
GtkListStore *model = weightsystem_list[w_idx].model;
|
||||
GtkTreeView *tree_view = weightsystem_list[w_idx].tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
weightsystem_t ws;
|
||||
|
||||
|
@ -1180,15 +1253,16 @@ static void ws_add_cb(GtkButton *button, GtkTreeView *tree_view)
|
|||
selection = gtk_tree_view_get_selection(tree_view);
|
||||
gtk_tree_selection_select_iter(selection, &iter);
|
||||
|
||||
weightsystem_list.max_index++;
|
||||
gtk_widget_set_sensitive(weightsystem_list.add, weightsystem_list.max_index < MAX_WEIGHTSYSTEMS);
|
||||
weightsystem_list[w_idx].max_index++;
|
||||
gtk_widget_set_sensitive(weightsystem_list[w_idx].add, weightsystem_list[w_idx].max_index < MAX_WEIGHTSYSTEMS);
|
||||
}
|
||||
|
||||
static void ws_del_cb(GtkButton *button, GtkTreeView *tree_view)
|
||||
static void ws_del_cb(GtkButton *button, int w_idx)
|
||||
{
|
||||
int index, nr;
|
||||
GtkTreeIter iter;
|
||||
GtkListStore *model = weightsystem_list.model;
|
||||
GtkListStore *model = weightsystem_list[w_idx].model;
|
||||
GtkTreeView *tree_view = weightsystem_list[w_idx].tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
struct dive *dive;
|
||||
weightsystem_t *ws;
|
||||
|
@ -1205,20 +1279,20 @@ static void ws_del_cb(GtkButton *button, GtkTreeView *tree_view)
|
|||
if (!dive)
|
||||
return;
|
||||
ws = dive->weightsystem + index;
|
||||
nr = weightsystem_list.max_index - index - 1;
|
||||
nr = weightsystem_list[w_idx].max_index - index - 1;
|
||||
|
||||
gtk_list_store_remove(model, &iter);
|
||||
|
||||
weightsystem_list.max_index--;
|
||||
weightsystem_list[w_idx].max_index--;
|
||||
memmove(ws, ws+1, nr*sizeof(*ws));
|
||||
memset(ws+nr, 0, sizeof(*ws));
|
||||
|
||||
mark_divelist_changed(TRUE);
|
||||
flush_divelist(dive);
|
||||
|
||||
gtk_widget_set_sensitive(weightsystem_list.edit, 0);
|
||||
gtk_widget_set_sensitive(weightsystem_list.del, 0);
|
||||
gtk_widget_set_sensitive(weightsystem_list.add, 1);
|
||||
gtk_widget_set_sensitive(weightsystem_list[w_idx].edit, 0);
|
||||
gtk_widget_set_sensitive(weightsystem_list[w_idx].del, 0);
|
||||
gtk_widget_set_sensitive(weightsystem_list[w_idx].add, 1);
|
||||
}
|
||||
|
||||
static GtkListStore *create_tank_size_model(void)
|
||||
|
@ -1338,33 +1412,33 @@ static void selection_cb(GtkTreeSelection *selection, struct equipment_list *lis
|
|||
static void row_activated_cb(GtkTreeView *tree_view,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *column,
|
||||
GtkTreeModel *model)
|
||||
int w_idx)
|
||||
{
|
||||
edit_cb(NULL, tree_view);
|
||||
edit_cb(NULL, w_idx);
|
||||
}
|
||||
|
||||
static void ws_row_activated_cb(GtkTreeView *tree_view,
|
||||
GtkTreePath *path,
|
||||
GtkTreeViewColumn *column,
|
||||
GtkTreeModel *model)
|
||||
int w_idx)
|
||||
{
|
||||
ws_edit_cb(NULL, tree_view);
|
||||
ws_edit_cb(NULL, w_idx);
|
||||
}
|
||||
|
||||
GtkWidget *cylinder_list_widget(void)
|
||||
GtkWidget *cylinder_list_widget(int w_idx)
|
||||
{
|
||||
GtkListStore *model = cylinder_list.model;
|
||||
GtkListStore *model = cylinder_list[w_idx].model;
|
||||
GtkWidget *tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
||||
gtk_widget_set_can_focus(tree_view, FALSE);
|
||||
|
||||
g_signal_connect(tree_view, "row-activated", G_CALLBACK(row_activated_cb), model);
|
||||
g_signal_connect(tree_view, "row-activated", G_CALLBACK(row_activated_cb), GINT_TO_POINTER(w_idx));
|
||||
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
|
||||
gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
|
||||
g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), &cylinder_list);
|
||||
g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), &cylinder_list[w_idx]);
|
||||
|
||||
g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
|
||||
"enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH,
|
||||
|
@ -1380,19 +1454,19 @@ GtkWidget *cylinder_list_widget(void)
|
|||
return tree_view;
|
||||
}
|
||||
|
||||
GtkWidget *weightsystem_list_widget(void)
|
||||
GtkWidget *weightsystem_list_widget(int w_idx)
|
||||
{
|
||||
GtkListStore *model = weightsystem_list.model;
|
||||
GtkListStore *model = weightsystem_list[w_idx].model;
|
||||
GtkWidget *tree_view;
|
||||
GtkTreeSelection *selection;
|
||||
|
||||
tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
|
||||
gtk_widget_set_can_focus(tree_view, FALSE);
|
||||
g_signal_connect(tree_view, "row-activated", G_CALLBACK(ws_row_activated_cb), model);
|
||||
g_signal_connect(tree_view, "row-activated", G_CALLBACK(ws_row_activated_cb), GINT_TO_POINTER(w_idx));
|
||||
|
||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view));
|
||||
gtk_tree_selection_set_mode(GTK_TREE_SELECTION(selection), GTK_SELECTION_BROWSE);
|
||||
g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), &weightsystem_list);
|
||||
g_signal_connect(selection, "changed", G_CALLBACK(selection_cb), &weightsystem_list[w_idx]);
|
||||
|
||||
g_object_set(G_OBJECT(tree_view), "headers-visible", TRUE,
|
||||
"enable-grid-lines", GTK_TREE_VIEW_GRID_LINES_BOTH,
|
||||
|
@ -1405,7 +1479,7 @@ GtkWidget *weightsystem_list_widget(void)
|
|||
return tree_view;
|
||||
}
|
||||
|
||||
static GtkWidget *cylinder_list_create(void)
|
||||
static GtkWidget *cylinder_list_create(int w_idx)
|
||||
{
|
||||
GtkListStore *model;
|
||||
|
||||
|
@ -1418,11 +1492,11 @@ static GtkWidget *cylinder_list_create(void)
|
|||
G_TYPE_INT, /* CYL_O2: permille */
|
||||
G_TYPE_INT /* CYL_HE: permille */
|
||||
);
|
||||
cylinder_list.model = model;
|
||||
return cylinder_list_widget();
|
||||
cylinder_list[w_idx].model = model;
|
||||
return cylinder_list_widget(w_idx);
|
||||
}
|
||||
|
||||
static GtkWidget *weightsystem_list_create(void)
|
||||
static GtkWidget *weightsystem_list_create(int w_idx)
|
||||
{
|
||||
GtkListStore *model;
|
||||
|
||||
|
@ -1430,11 +1504,11 @@ static GtkWidget *weightsystem_list_create(void)
|
|||
G_TYPE_STRING, /* WS_DESC: utf8 */
|
||||
G_TYPE_INT /* WS_WEIGHT: grams */
|
||||
);
|
||||
weightsystem_list.model = model;
|
||||
return weightsystem_list_widget();
|
||||
weightsystem_list[w_idx].model = model;
|
||||
return weightsystem_list_widget(w_idx);
|
||||
}
|
||||
|
||||
GtkWidget *equipment_widget(void)
|
||||
GtkWidget *equipment_widget(int w_idx)
|
||||
{
|
||||
GtkWidget *vbox, *hbox, *frame, *framebox, *tree_view;
|
||||
GtkWidget *add, *del, *edit;
|
||||
|
@ -1442,14 +1516,17 @@ GtkWidget *equipment_widget(void)
|
|||
vbox = gtk_vbox_new(FALSE, 3);
|
||||
|
||||
/*
|
||||
* We create the cylinder size model at startup, since
|
||||
* we're going to share it across all cylinders and all
|
||||
* dives. So if you add a new cylinder type in one dive,
|
||||
* it will show up when you edit the cylinder types for
|
||||
* another dive.
|
||||
* We create the cylinder size (and weightsystem) models
|
||||
* at startup for the primary cylinder / weightsystem widget,
|
||||
* since we're going to share it across all cylinders and all
|
||||
* dives. So if you add a new cylinder type or weightsystem in
|
||||
* one dive, it will show up when you edit the cylinder types
|
||||
* or weightsystems for another dive.
|
||||
*/
|
||||
cylinder_model = create_tank_size_model();
|
||||
tree_view = cylinder_list_create();
|
||||
if (w_idx == W_IDX_PRIMARY)
|
||||
cylinder_model = create_tank_size_model();
|
||||
tree_view = cylinder_list_create(w_idx);
|
||||
cylinder_list[w_idx].tree_view = GTK_TREE_VIEW(tree_view);
|
||||
|
||||
hbox = gtk_hbox_new(FALSE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
||||
|
@ -1475,19 +1552,21 @@ GtkWidget *equipment_widget(void)
|
|||
gtk_box_pack_start(GTK_BOX(hbox), add, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), del, FALSE, FALSE, 0);
|
||||
|
||||
cylinder_list.edit = edit;
|
||||
cylinder_list.add = add;
|
||||
cylinder_list.del = del;
|
||||
cylinder_list[w_idx].edit = edit;
|
||||
cylinder_list[w_idx].add = add;
|
||||
cylinder_list[w_idx].del = del;
|
||||
|
||||
g_signal_connect(edit, "clicked", G_CALLBACK(edit_cb), tree_view);
|
||||
g_signal_connect(add, "clicked", G_CALLBACK(add_cb), tree_view);
|
||||
g_signal_connect(del, "clicked", G_CALLBACK(del_cb), tree_view);
|
||||
g_signal_connect(edit, "clicked", G_CALLBACK(edit_cb), GINT_TO_POINTER(w_idx));
|
||||
g_signal_connect(add, "clicked", G_CALLBACK(add_cb), GINT_TO_POINTER(w_idx));
|
||||
g_signal_connect(del, "clicked", G_CALLBACK(del_cb), GINT_TO_POINTER(w_idx));
|
||||
|
||||
hbox = gtk_hbox_new(FALSE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
||||
|
||||
weightsystem_model = create_weightsystem_model();
|
||||
tree_view = weightsystem_list_create();
|
||||
if (w_idx == W_IDX_PRIMARY)
|
||||
weightsystem_model = create_weightsystem_model();
|
||||
tree_view = weightsystem_list_create(w_idx);
|
||||
weightsystem_list[w_idx].tree_view = GTK_TREE_VIEW(tree_view);
|
||||
|
||||
frame = gtk_frame_new("Weight");
|
||||
gtk_box_pack_start(GTK_BOX(hbox), frame, TRUE, FALSE, 3);
|
||||
|
@ -1510,13 +1589,13 @@ GtkWidget *equipment_widget(void)
|
|||
gtk_box_pack_start(GTK_BOX(hbox), add, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), del, FALSE, FALSE, 0);
|
||||
|
||||
weightsystem_list.edit = edit;
|
||||
weightsystem_list.add = add;
|
||||
weightsystem_list.del = del;
|
||||
weightsystem_list[w_idx].edit = edit;
|
||||
weightsystem_list[w_idx].add = add;
|
||||
weightsystem_list[w_idx].del = del;
|
||||
|
||||
g_signal_connect(edit, "clicked", G_CALLBACK(ws_edit_cb), tree_view);
|
||||
g_signal_connect(add, "clicked", G_CALLBACK(ws_add_cb), tree_view);
|
||||
g_signal_connect(del, "clicked", G_CALLBACK(ws_del_cb), tree_view);
|
||||
g_signal_connect(edit, "clicked", G_CALLBACK(ws_edit_cb), GINT_TO_POINTER(w_idx));
|
||||
g_signal_connect(add, "clicked", G_CALLBACK(ws_add_cb), GINT_TO_POINTER(w_idx));
|
||||
g_signal_connect(del, "clicked", G_CALLBACK(ws_del_cb), GINT_TO_POINTER(w_idx));
|
||||
|
||||
return vbox;
|
||||
}
|
||||
|
|
129
file.c
129
file.c
|
@ -10,7 +10,7 @@
|
|||
|
||||
static int readfile(const char *filename, struct memblock *mem)
|
||||
{
|
||||
int ret, fd = open(filename, O_RDONLY);
|
||||
int ret, fd;
|
||||
struct stat st;
|
||||
char *buf;
|
||||
|
||||
|
@ -94,6 +94,125 @@ static int try_to_open_suunto(const char *filename, struct memblock *mem, GError
|
|||
return success;
|
||||
}
|
||||
|
||||
static time_t parse_date(const char *date)
|
||||
{
|
||||
int hour, min, sec;
|
||||
struct tm tm;
|
||||
char *p;
|
||||
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_mday = strtol(date, &p, 10);
|
||||
if (tm.tm_mday < 1 || tm.tm_mday > 31)
|
||||
return 0;
|
||||
for (tm.tm_mon = 0; tm.tm_mon < 12; tm.tm_mon++) {
|
||||
if (!memcmp(p, monthname(tm.tm_mon), 3))
|
||||
break;
|
||||
}
|
||||
if (tm.tm_mon > 11)
|
||||
return 0;
|
||||
date = p+3;
|
||||
tm.tm_year = strtol(date, &p, 10);
|
||||
if (date == p)
|
||||
return 0;
|
||||
if (tm.tm_year < 70)
|
||||
tm.tm_year += 2000;
|
||||
if (tm.tm_year < 100)
|
||||
tm.tm_year += 1900;
|
||||
if (sscanf(p, "%d:%d:%d", &hour, &min, &sec) != 3)
|
||||
return 0;
|
||||
tm.tm_hour = hour;
|
||||
tm.tm_min = min;
|
||||
tm.tm_sec = sec;
|
||||
return utc_mktime(&tm);
|
||||
}
|
||||
|
||||
enum csv_format {
|
||||
CSV_DEPTH, CSV_TEMP, CSV_PRESSURE
|
||||
};
|
||||
|
||||
static void add_sample_data(struct sample *sample, enum csv_format type, double val)
|
||||
{
|
||||
switch (type) {
|
||||
case CSV_DEPTH:
|
||||
sample->depth.mm = feet_to_mm(val);
|
||||
break;
|
||||
case CSV_TEMP:
|
||||
sample->temperature.mkelvin = F_to_mkelvin(val);
|
||||
break;
|
||||
case CSV_PRESSURE:
|
||||
sample->cylinderpressure.mbar = psi_to_mbar(val*4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cochran comma-separated values: depth in feet, temperature in F, pressure in psi.
|
||||
*
|
||||
* They start with eight comma-separated fields like:
|
||||
*
|
||||
* filename: {C:\Analyst4\can\T036785.can},{C:\Analyst4\can\K031892.can}
|
||||
* divenr: %d
|
||||
* datetime: {03Sep11 16:37:22},{15Dec11 18:27:02}
|
||||
* ??: 1
|
||||
* serialnr??: {CCI134},{CCI207}
|
||||
* computer??: {GeminiII},{CommanderIII}
|
||||
* computer??: {GeminiII},{CommanderIII}
|
||||
* ??: 1
|
||||
*
|
||||
* Followed by the data values (all comma-separated, all one long line).
|
||||
*/
|
||||
static int try_to_open_csv(const char *filename, struct memblock *mem, enum csv_format type)
|
||||
{
|
||||
char *p = mem->buffer;
|
||||
char *header[8];
|
||||
int i, time;
|
||||
time_t date;
|
||||
struct dive *dive;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
header[i] = p;
|
||||
p = strchr(p, ',');
|
||||
if (!p)
|
||||
return 0;
|
||||
p++;
|
||||
}
|
||||
|
||||
date = parse_date(header[2]);
|
||||
if (!date)
|
||||
return 0;
|
||||
|
||||
dive = alloc_dive();
|
||||
dive->when = date;
|
||||
dive->number = atoi(header[1]);
|
||||
|
||||
time = 0;
|
||||
for (;;) {
|
||||
char *end;
|
||||
double val;
|
||||
struct sample *sample;
|
||||
|
||||
errno = 0;
|
||||
val = strtod(p,&end);
|
||||
if (end == p)
|
||||
break;
|
||||
if (errno)
|
||||
break;
|
||||
|
||||
sample = prepare_sample(&dive);
|
||||
sample->time.seconds = time;
|
||||
add_sample_data(sample, type, val);
|
||||
finish_sample(dive);
|
||||
|
||||
time++;
|
||||
dive->duration.seconds = time;
|
||||
if (*end != ',')
|
||||
break;
|
||||
p = end+1;
|
||||
}
|
||||
record_dive(dive);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int open_by_filename(const char *filename, const char *fmt, struct memblock *mem, GError **error)
|
||||
{
|
||||
/* Suunto Dive Manager files: SDE */
|
||||
|
@ -104,6 +223,14 @@ static int open_by_filename(const char *filename, const char *fmt, struct memblo
|
|||
if (!strcasecmp(fmt, "CAN"))
|
||||
return try_to_open_cochran(filename, mem, error);
|
||||
|
||||
/* Cochran export comma-separated-value files */
|
||||
if (!strcasecmp(fmt, "DPT"))
|
||||
return try_to_open_csv(filename, mem, CSV_DEPTH);
|
||||
if (!strcasecmp(fmt, "TMP"))
|
||||
return try_to_open_csv(filename, mem, CSV_TEMP);
|
||||
if (!strcasecmp(fmt, "HP1"))
|
||||
return try_to_open_csv(filename, mem, CSV_PRESSURE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
224
gtk-gui.c
224
gtk-gui.c
|
@ -21,6 +21,8 @@ GtkWidget *main_vbox;
|
|||
GtkWidget *error_info_bar;
|
||||
GtkWidget *error_label;
|
||||
GtkWidget *vpane, *hpane;
|
||||
GtkWidget *notebook;
|
||||
|
||||
int error_count;
|
||||
extern char zoomed_plot;
|
||||
|
||||
|
@ -32,12 +34,14 @@ static GtkWidget *dive_profile;
|
|||
|
||||
visible_cols_t visible_cols = {TRUE, FALSE};
|
||||
|
||||
static const char *default_dive_computer;
|
||||
static const char *default_dive_computer_vendor;
|
||||
static const char *default_dive_computer_product;
|
||||
static const char *default_dive_computer_device;
|
||||
|
||||
static int is_default_dive_computer(const char *name)
|
||||
static int is_default_dive_computer(const char *vendor, const char *product)
|
||||
{
|
||||
return default_dive_computer && !strcmp(name, default_dive_computer);
|
||||
return default_dive_computer_vendor && !strcmp(vendor, default_dive_computer_vendor) &&
|
||||
default_dive_computer_product && !strcmp(product, default_dive_computer_product);
|
||||
}
|
||||
|
||||
static int is_default_dive_computer_device(const char *name)
|
||||
|
@ -45,14 +49,18 @@ static int is_default_dive_computer_device(const char *name)
|
|||
return default_dive_computer_device && !strcmp(name, default_dive_computer_device);
|
||||
}
|
||||
|
||||
static void set_default_dive_computer(const char *name)
|
||||
static void set_default_dive_computer(const char *vendor, const char *product)
|
||||
{
|
||||
if (!name || !*name)
|
||||
if (!vendor || !*vendor)
|
||||
return;
|
||||
if (is_default_dive_computer(name))
|
||||
if (!product || !*product)
|
||||
return;
|
||||
default_dive_computer = name;
|
||||
subsurface_set_conf("dive_computer", PREF_STRING, name);
|
||||
if (is_default_dive_computer(vendor, product))
|
||||
return;
|
||||
default_dive_computer_vendor = vendor;
|
||||
default_dive_computer_product = product;
|
||||
subsurface_set_conf("dive_computer_vendor", PREF_STRING, vendor);
|
||||
subsurface_set_conf("dive_computer_product", PREF_STRING, product);
|
||||
}
|
||||
|
||||
static void set_default_dive_computer_device(const char *name)
|
||||
|
@ -165,48 +173,75 @@ static void file_open(GtkWidget *w, gpointer data)
|
|||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
static void file_save(GtkWidget *w, gpointer data)
|
||||
static void file_save_as(GtkWidget *w, gpointer data)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
dialog = gtk_file_chooser_dialog_new("Save File",
|
||||
char *filename = NULL;
|
||||
dialog = gtk_file_chooser_dialog_new("Save File As",
|
||||
GTK_WINDOW(main_window),
|
||||
GTK_FILE_CHOOSER_ACTION_SAVE,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
||||
NULL);
|
||||
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
|
||||
if (!existing_filename) {
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document");
|
||||
} else
|
||||
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), existing_filename);
|
||||
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), existing_filename);
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
char *filename;
|
||||
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
if (filename){
|
||||
save_dives(filename);
|
||||
set_filename(filename);
|
||||
g_free(filename);
|
||||
mark_divelist_changed(FALSE);
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
}
|
||||
|
||||
static void ask_save_changes()
|
||||
static void file_save(GtkWidget *w, gpointer data)
|
||||
{
|
||||
if (!existing_filename)
|
||||
return file_save_as(w, data);
|
||||
|
||||
save_dives(existing_filename);
|
||||
mark_divelist_changed(FALSE);
|
||||
}
|
||||
|
||||
static gboolean ask_save_changes()
|
||||
{
|
||||
GtkWidget *dialog, *label, *content;
|
||||
gboolean quit = TRUE;
|
||||
dialog = gtk_dialog_new_with_buttons("Save Changes?",
|
||||
GTK_WINDOW(main_window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
|
||||
GTK_STOCK_NO, GTK_RESPONSE_NO,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
NULL);
|
||||
content = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
|
||||
label = gtk_label_new ("You have unsaved changes\nWould you like to save those before exiting the program?");
|
||||
|
||||
if (!existing_filename){
|
||||
label = gtk_label_new (
|
||||
"You have unsaved changes\nWould you like to save those before exiting the program?");
|
||||
} else {
|
||||
char *label_text = (char*) malloc(sizeof(char) * (92 + strlen(existing_filename)));
|
||||
sprintf(label_text,
|
||||
"You have unsaved changes to file: %s \nWould you like to save those before exiting the program?",
|
||||
existing_filename);
|
||||
label = gtk_label_new (label_text);
|
||||
g_free(label_text);
|
||||
}
|
||||
gtk_container_add (GTK_CONTAINER (content), label);
|
||||
gtk_widget_show_all (dialog);
|
||||
gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
|
||||
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
|
||||
gint outcode = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
if (outcode == GTK_RESPONSE_ACCEPT) {
|
||||
file_save(NULL,NULL);
|
||||
} else if (outcode == GTK_RESPONSE_CANCEL) {
|
||||
quit = FALSE;
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
return quit;
|
||||
}
|
||||
|
||||
static gboolean on_delete(GtkWidget* w, gpointer data)
|
||||
|
@ -214,10 +249,15 @@ static gboolean on_delete(GtkWidget* w, gpointer data)
|
|||
/* Make sure to flush any modified dive data */
|
||||
update_dive(NULL);
|
||||
|
||||
gboolean quit = TRUE;
|
||||
if (unsaved_changes())
|
||||
ask_save_changes();
|
||||
quit = ask_save_changes();
|
||||
|
||||
return FALSE; /* go ahead, kill the program, we're good now */
|
||||
if (quit){
|
||||
return FALSE; /* go ahead, kill the program, we're good now */
|
||||
} else {
|
||||
return TRUE; /* We are not leaving */
|
||||
}
|
||||
}
|
||||
|
||||
static void on_destroy(GtkWidget* w, gpointer data)
|
||||
|
@ -230,9 +270,13 @@ static void quit(GtkWidget *w, gpointer data)
|
|||
/* Make sure to flush any modified dive data */
|
||||
update_dive(NULL);
|
||||
|
||||
gboolean quit = TRUE;
|
||||
if (unsaved_changes())
|
||||
ask_save_changes();
|
||||
gtk_main_quit();
|
||||
quit = ask_save_changes();
|
||||
|
||||
if (quit){
|
||||
gtk_main_quit();
|
||||
}
|
||||
}
|
||||
|
||||
GtkTreeViewColumn *tree_view_column(GtkWidget *tree_view, int index, const char *title,
|
||||
|
@ -343,6 +387,8 @@ OPTIONCALLBACK(otu_toggle, visible_cols.otu)
|
|||
OPTIONCALLBACK(sac_toggle, visible_cols.sac)
|
||||
OPTIONCALLBACK(nitrox_toggle, visible_cols.nitrox)
|
||||
OPTIONCALLBACK(temperature_toggle, visible_cols.temperature)
|
||||
OPTIONCALLBACK(totalweight_toggle, visible_cols.totalweight)
|
||||
OPTIONCALLBACK(suit_toggle, visible_cols.suit)
|
||||
OPTIONCALLBACK(cylinder_toggle, visible_cols.cylinder)
|
||||
|
||||
static void event_toggle(GtkWidget *w, gpointer _data)
|
||||
|
@ -398,37 +444,47 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
|
|||
"lbs", set_lbs, (output_units.weight == LBS),
|
||||
NULL);
|
||||
|
||||
frame = gtk_frame_new("Columns");
|
||||
frame = gtk_frame_new("Show Columns");
|
||||
gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
|
||||
|
||||
box = gtk_hbox_new(FALSE, 6);
|
||||
gtk_container_add(GTK_CONTAINER(frame), box);
|
||||
|
||||
button = gtk_check_button_new_with_label("Show Temp");
|
||||
button = gtk_check_button_new_with_label("Temp");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.temperature);
|
||||
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(temperature_toggle), NULL);
|
||||
|
||||
button = gtk_check_button_new_with_label("Show Cyl");
|
||||
button = gtk_check_button_new_with_label("Cyl");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.cylinder);
|
||||
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(cylinder_toggle), NULL);
|
||||
|
||||
button = gtk_check_button_new_with_label("Show O" UTF8_SUBSCRIPT_2 "%");
|
||||
button = gtk_check_button_new_with_label("O" UTF8_SUBSCRIPT_2 "%");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.nitrox);
|
||||
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(nitrox_toggle), NULL);
|
||||
|
||||
button = gtk_check_button_new_with_label("Show SAC");
|
||||
button = gtk_check_button_new_with_label("SAC");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.sac);
|
||||
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(sac_toggle), NULL);
|
||||
|
||||
button = gtk_check_button_new_with_label("Show OTU");
|
||||
button = gtk_check_button_new_with_label("OTU");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.otu);
|
||||
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(otu_toggle), NULL);
|
||||
|
||||
button = gtk_check_button_new_with_label("Weight");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.totalweight);
|
||||
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(totalweight_toggle), NULL);
|
||||
|
||||
button = gtk_check_button_new_with_label("Suit");
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), visible_cols.suit);
|
||||
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
|
||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(suit_toggle), NULL);
|
||||
|
||||
font = gtk_font_button_new_with_font(divelist_font);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
|
||||
|
||||
|
@ -452,6 +508,8 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
|
|||
subsurface_set_conf("fahrenheit", PREF_BOOL, BOOL_TO_PTR(output_units.temperature == FAHRENHEIT));
|
||||
subsurface_set_conf("lbs", PREF_BOOL, BOOL_TO_PTR(output_units.weight == LBS));
|
||||
subsurface_set_conf("TEMPERATURE", PREF_BOOL, BOOL_TO_PTR(visible_cols.temperature));
|
||||
subsurface_set_conf("TOTALWEIGHT", PREF_BOOL, BOOL_TO_PTR(visible_cols.totalweight));
|
||||
subsurface_set_conf("SUIT", PREF_BOOL, BOOL_TO_PTR(visible_cols.suit));
|
||||
subsurface_set_conf("CYLINDER", PREF_BOOL, BOOL_TO_PTR(visible_cols.cylinder));
|
||||
subsurface_set_conf("NITROX", PREF_BOOL, BOOL_TO_PTR(visible_cols.nitrox));
|
||||
subsurface_set_conf("SAC", PREF_BOOL, BOOL_TO_PTR(visible_cols.sac));
|
||||
|
@ -604,11 +662,17 @@ static void view_info(GtkWidget *w, gpointer data)
|
|||
gtk_paned_set_position(GTK_PANED(hpane), 65535);
|
||||
}
|
||||
|
||||
/* Ooh. I don't know how to get the half-way size. So I'm just using random numbers */
|
||||
static void view_three(GtkWidget *w, gpointer data)
|
||||
{
|
||||
gtk_paned_set_position(GTK_PANED(hpane), 400);
|
||||
gtk_paned_set_position(GTK_PANED(vpane), 200);
|
||||
GtkAllocation alloc;
|
||||
GtkRequisition requisition;
|
||||
|
||||
gtk_widget_get_allocation(hpane, &alloc);
|
||||
gtk_paned_set_position(GTK_PANED(hpane), alloc.width/2);
|
||||
gtk_widget_get_allocation(vpane, &alloc);
|
||||
gtk_widget_size_request(notebook, &requisition);
|
||||
/* pick the requested size for the notebook plus 6 pixels for frame */
|
||||
gtk_paned_set_position(GTK_PANED(vpane), requisition.height + 6);
|
||||
}
|
||||
|
||||
static void toggle_zoom(GtkWidget *w, gpointer data)
|
||||
|
@ -619,16 +683,18 @@ static void toggle_zoom(GtkWidget *w, gpointer data)
|
|||
}
|
||||
|
||||
static GtkActionEntry menu_items[] = {
|
||||
{ "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL},
|
||||
{ "LogMenuAction", GTK_STOCK_FILE, "Log", NULL, NULL, NULL},
|
||||
{ "ViewMenuAction", GTK_STOCK_FILE, "View", NULL, NULL, NULL},
|
||||
{ "FilterMenuAction", GTK_STOCK_FILE, "Filter", NULL, NULL, NULL},
|
||||
{ "HelpMenuAction", GTK_STOCK_HELP, "Help", NULL, NULL, NULL},
|
||||
{ "FileMenuAction", NULL, "File", NULL, NULL, NULL},
|
||||
{ "LogMenuAction", NULL, "Log", NULL, NULL, NULL},
|
||||
{ "ViewMenuAction", NULL, "View", NULL, NULL, NULL},
|
||||
{ "FilterMenuAction", NULL, "Filter", NULL, NULL, NULL},
|
||||
{ "HelpMenuAction", NULL, "Help", NULL, NULL, NULL},
|
||||
{ "OpenFile", GTK_STOCK_OPEN, NULL, CTRLCHAR "O", NULL, G_CALLBACK(file_open) },
|
||||
{ "SaveFile", GTK_STOCK_SAVE, NULL, CTRLCHAR "S", NULL, G_CALLBACK(file_save) },
|
||||
{ "SaveAsFile", GTK_STOCK_SAVE_AS, NULL, SHIFTCHAR CTRLCHAR "S", NULL, G_CALLBACK(file_save_as) },
|
||||
{ "Print", GTK_STOCK_PRINT, NULL, CTRLCHAR "P", NULL, G_CALLBACK(do_print) },
|
||||
{ "Import", NULL, "Import", NULL, NULL, G_CALLBACK(import_dialog) },
|
||||
{ "Preferences", NULL, "Preferences", PREFERENCE_ACCEL, NULL, G_CALLBACK(preferences_dialog) },
|
||||
{ "AddDive", GTK_STOCK_ADD, "Add Dive", NULL, NULL, G_CALLBACK(add_dive_cb) },
|
||||
{ "Preferences", GTK_STOCK_PREFERENCES, "Preferences", PREFERENCE_ACCEL, NULL, G_CALLBACK(preferences_dialog) },
|
||||
{ "Renumber", NULL, "Renumber", NULL, NULL, G_CALLBACK(renumber_dialog) },
|
||||
{ "SelectEvents", NULL, "SelectEvents", NULL, NULL, G_CALLBACK(selectevents_dialog) },
|
||||
{ "Quit", GTK_STOCK_QUIT, NULL, CTRLCHAR "Q", NULL, G_CALLBACK(quit) },
|
||||
|
@ -647,6 +713,7 @@ static const gchar* ui_string = " \
|
|||
<menu name=\"FileMenu\" action=\"FileMenuAction\"> \
|
||||
<menuitem name=\"Open\" action=\"OpenFile\" /> \
|
||||
<menuitem name=\"Save\" action=\"SaveFile\" /> \
|
||||
<menuitem name=\"Save As\" action=\"SaveAsFile\" /> \
|
||||
<menuitem name=\"Print\" action=\"Print\" /> \
|
||||
<separator name=\"Separator1\"/> \
|
||||
<menuitem name=\"Preferences\" action=\"Preferences\" /> \
|
||||
|
@ -655,6 +722,7 @@ static const gchar* ui_string = " \
|
|||
</menu> \
|
||||
<menu name=\"LogMenu\" action=\"LogMenuAction\"> \
|
||||
<menuitem name=\"Import\" action=\"Import\" /> \
|
||||
<menuitem name=\"Add Dive\" action=\"AddDive\" /> \
|
||||
<separator name=\"Separator\"/> \
|
||||
<menuitem name=\"Renumber\" action=\"Renumber\" /> \
|
||||
<menuitem name=\"Toggle Zoom\" action=\"ToggleZoom\" /> \
|
||||
|
@ -698,11 +766,11 @@ static void switch_page(GtkNotebook *notebook, gint arg1, gpointer user_data)
|
|||
void init_ui(int *argcp, char ***argvp)
|
||||
{
|
||||
GtkWidget *win;
|
||||
GtkWidget *notebook;
|
||||
GtkWidget *nb_page;
|
||||
GtkWidget *dive_list;
|
||||
GtkWidget *menubar;
|
||||
GtkWidget *vbox;
|
||||
GtkWidget *scrolled;
|
||||
GdkScreen *screen;
|
||||
GtkIconTheme *icon_theme=NULL;
|
||||
GtkSettings *settings;
|
||||
|
@ -728,13 +796,16 @@ void init_ui(int *argcp, char ***argvp)
|
|||
/* an unset key is FALSE - all these are hidden by default */
|
||||
visible_cols.cylinder = PTR_TO_BOOL(subsurface_get_conf("CYLINDER", PREF_BOOL));
|
||||
visible_cols.temperature = PTR_TO_BOOL(subsurface_get_conf("TEMPERATURE", PREF_BOOL));
|
||||
visible_cols.totalweight = PTR_TO_BOOL(subsurface_get_conf("TOTALWEIGHT", PREF_BOOL));
|
||||
visible_cols.suit = PTR_TO_BOOL(subsurface_get_conf("SUIT", PREF_BOOL));
|
||||
visible_cols.nitrox = PTR_TO_BOOL(subsurface_get_conf("NITROX", PREF_BOOL));
|
||||
visible_cols.otu = PTR_TO_BOOL(subsurface_get_conf("OTU", PREF_BOOL));
|
||||
visible_cols.sac = PTR_TO_BOOL(subsurface_get_conf("SAC", PREF_BOOL));
|
||||
|
||||
divelist_font = subsurface_get_conf("divelist_font", PREF_STRING);
|
||||
|
||||
default_dive_computer = subsurface_get_conf("dive_computer", PREF_STRING);
|
||||
default_dive_computer_vendor = subsurface_get_conf("dive_computer_vendor", PREF_STRING);
|
||||
default_dive_computer_product = subsurface_get_conf("dive_computer_product", PREF_STRING);
|
||||
default_dive_computer_device = subsurface_get_conf("dive_computer_device", PREF_STRING);
|
||||
|
||||
error_info_bar = NULL;
|
||||
|
@ -771,13 +842,16 @@ void init_ui(int *argcp, char ***argvp)
|
|||
|
||||
vpane = gtk_vpaned_new();
|
||||
gtk_box_pack_start(GTK_BOX(vbox), vpane, TRUE, TRUE, 3);
|
||||
|
||||
hpane = gtk_hpaned_new();
|
||||
gtk_paned_add1(GTK_PANED(vpane), hpane);
|
||||
g_signal_connect_after(G_OBJECT(vbox), "realize", G_CALLBACK(view_three), NULL);
|
||||
|
||||
/* Notebook for dive info vs profile vs .. */
|
||||
notebook = gtk_notebook_new();
|
||||
gtk_paned_add1(GTK_PANED(hpane), notebook);
|
||||
scrolled = gtk_scrolled_window_new(NULL, NULL);
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
|
||||
gtk_paned_add1(GTK_PANED(hpane), scrolled);
|
||||
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), notebook);
|
||||
g_signal_connect(notebook, "switch-page", G_CALLBACK(switch_page), NULL);
|
||||
|
||||
/* Create the actual divelist */
|
||||
|
@ -795,7 +869,7 @@ void init_ui(int *argcp, char ***argvp)
|
|||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), nb_page, gtk_label_new("Dive Notes"));
|
||||
|
||||
/* Frame for dive equipment */
|
||||
nb_page = equipment_widget();
|
||||
nb_page = equipment_widget(W_IDX_PRIMARY);
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), nb_page, gtk_label_new("Equipment"));
|
||||
|
||||
/* Frame for single dive statistics */
|
||||
|
@ -924,20 +998,45 @@ static int fill_computer_list(GtkListStore *store)
|
|||
{
|
||||
int index = -1, i;
|
||||
GtkTreeIter iter;
|
||||
struct device_list *list = device_list;
|
||||
dc_iterator_t *iterator = NULL;
|
||||
dc_descriptor_t *descriptor = NULL;
|
||||
|
||||
i = 0;
|
||||
dc_descriptor_iterator(&iterator);
|
||||
while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) {
|
||||
const char *vendor = dc_descriptor_get_vendor(descriptor);
|
||||
const char *product = dc_descriptor_get_product(descriptor);
|
||||
|
||||
for (list = device_list, i = 0 ; list->name ; list++, i++) {
|
||||
gtk_list_store_append(store, &iter);
|
||||
gtk_list_store_set(store, &iter,
|
||||
0, list->name,
|
||||
1, list->type,
|
||||
0, descriptor,
|
||||
-1);
|
||||
if (is_default_dive_computer(list->name))
|
||||
if (is_default_dive_computer(vendor, product))
|
||||
index = i;
|
||||
i++;
|
||||
}
|
||||
dc_iterator_free(iterator);
|
||||
return index;
|
||||
}
|
||||
|
||||
void render_dive_computer(GtkCellLayout *cell,
|
||||
GtkCellRenderer *renderer,
|
||||
GtkTreeModel *model,
|
||||
GtkTreeIter *iter,
|
||||
gpointer data)
|
||||
{
|
||||
char buffer[40];
|
||||
dc_descriptor_t *descriptor = NULL;
|
||||
const char *vendor, *product;
|
||||
|
||||
gtk_tree_model_get(model, iter, 0, &descriptor, -1);
|
||||
vendor = dc_descriptor_get_vendor(descriptor);
|
||||
product = dc_descriptor_get_product(descriptor);
|
||||
snprintf(buffer, sizeof(buffer), "%s %s", vendor, product);
|
||||
g_object_set(renderer, "text", buffer, NULL);
|
||||
}
|
||||
|
||||
|
||||
static GtkComboBox *dive_computer_selector(GtkWidget *vbox)
|
||||
{
|
||||
GtkWidget *hbox, *combo_box, *frame;
|
||||
|
@ -948,7 +1047,7 @@ static GtkComboBox *dive_computer_selector(GtkWidget *vbox)
|
|||
hbox = gtk_hbox_new(FALSE, 6);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
||||
|
||||
model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
|
||||
model = gtk_list_store_new(1, G_TYPE_POINTER);
|
||||
default_index = fill_computer_list(model);
|
||||
|
||||
frame = gtk_frame_new("Dive computer");
|
||||
|
@ -959,7 +1058,7 @@ static GtkComboBox *dive_computer_selector(GtkWidget *vbox)
|
|||
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE);
|
||||
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box), renderer, "text", 0, NULL);
|
||||
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(combo_box), renderer, render_dive_computer, NULL, NULL);
|
||||
|
||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), default_index);
|
||||
|
||||
|
@ -1104,10 +1203,9 @@ repeat:
|
|||
gtk_widget_show_all(dialog);
|
||||
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||
switch (result) {
|
||||
int type;
|
||||
dc_descriptor_t *descriptor;
|
||||
GtkTreeIter iter;
|
||||
GtkTreeModel *model;
|
||||
const char *comp;
|
||||
GSList *list;
|
||||
case GTK_RESPONSE_ACCEPT:
|
||||
/* what happened - did the user pick a file? In that case
|
||||
|
@ -1116,17 +1214,23 @@ repeat:
|
|||
gtk_widget_destroy(info);
|
||||
list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(XMLchooser));
|
||||
if (g_slist_length(list) == 0) {
|
||||
const char *vendor, *product;
|
||||
|
||||
if (!gtk_combo_box_get_active_iter(computer, &iter))
|
||||
break;
|
||||
model = gtk_combo_box_get_model(computer);
|
||||
gtk_tree_model_get(model, &iter,
|
||||
0, &comp,
|
||||
1, &type,
|
||||
0, &descriptor,
|
||||
-1);
|
||||
devicedata.type = type;
|
||||
devicedata.name = comp;
|
||||
|
||||
vendor = dc_descriptor_get_vendor(descriptor);
|
||||
product = dc_descriptor_get_product(descriptor);
|
||||
|
||||
devicedata.descriptor = descriptor;
|
||||
devicedata.vendor = vendor;
|
||||
devicedata.product = product;
|
||||
devicedata.devname = gtk_entry_get_text(device);
|
||||
set_default_dive_computer(devicedata.name);
|
||||
set_default_dive_computer(vendor, product);
|
||||
set_default_dive_computer_device(devicedata.devname);
|
||||
info = import_dive_computer(&devicedata, GTK_DIALOG(dialog));
|
||||
if (info)
|
||||
|
@ -1156,7 +1260,9 @@ void update_progressbar_text(progressbar_t *progress, const char *text)
|
|||
|
||||
void set_filename(const char *filename)
|
||||
{
|
||||
if (!existing_filename && filename)
|
||||
if (existing_filename)
|
||||
free(existing_filename);
|
||||
existing_filename = NULL;
|
||||
if (filename)
|
||||
existing_filename = strdup(filename);
|
||||
return;
|
||||
}
|
||||
|
|
352
info.c
352
info.c
|
@ -12,15 +12,16 @@
|
|||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "dive.h"
|
||||
#include "display.h"
|
||||
#include "display-gtk.h"
|
||||
#include "divelist.h"
|
||||
|
||||
static GtkEntry *location, *buddy, *divemaster, *rating;
|
||||
static GtkEntry *location, *buddy, *divemaster, *rating, *suit;
|
||||
static GtkTextView *notes;
|
||||
static GtkListStore *location_list, *people_list, *star_list;
|
||||
static GtkListStore *location_list, *people_list, *star_list, *suit_list;
|
||||
|
||||
static char *get_text(GtkTextView *view)
|
||||
{
|
||||
|
@ -42,16 +43,50 @@ static int text_changed(const char *old, const char *new)
|
|||
(!old && strcmp("",new));
|
||||
}
|
||||
|
||||
static char *get_combo_box_entry_text(GtkComboBoxEntry *combo_box, char **textp)
|
||||
static const char *skip_space(const char *str)
|
||||
{
|
||||
if (str) {
|
||||
while (isspace(*str))
|
||||
str++;
|
||||
if (!*str)
|
||||
str = NULL;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the string from a combo box.
|
||||
*
|
||||
* The "master" string is the string of the current dive - we only consider it
|
||||
* changed if the old string is either empty, or matches that master string.
|
||||
*/
|
||||
static char *get_combo_box_entry_text(GtkComboBoxEntry *combo_box, char **textp, const char *master)
|
||||
{
|
||||
char *old = *textp;
|
||||
const char *old_text;
|
||||
const gchar *new;
|
||||
GtkEntry *entry;
|
||||
|
||||
old_text = skip_space(old);
|
||||
master = skip_space(master);
|
||||
|
||||
/*
|
||||
* If we had a master string, and it doesn't match our old
|
||||
* string, we will always pick the old value (it means that
|
||||
* we're editing another dive's info that already had a
|
||||
* valid value).
|
||||
*/
|
||||
if (master && old_text)
|
||||
if (strcmp(master, old_text))
|
||||
return NULL;
|
||||
|
||||
entry = GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo_box)));
|
||||
new = gtk_entry_get_text(entry);
|
||||
while (isspace(*new))
|
||||
new++;
|
||||
/* If the master string didn't change, don't change other dives either! */
|
||||
if (!text_changed(master,new))
|
||||
return NULL;
|
||||
if (!text_changed(old,new))
|
||||
return NULL;
|
||||
free(old);
|
||||
|
@ -95,6 +130,7 @@ void show_dive_info(struct dive *dive)
|
|||
SET_TEXT_VALUE(divemaster);
|
||||
SET_TEXT_VALUE(buddy);
|
||||
SET_TEXT_VALUE(location);
|
||||
SET_TEXT_VALUE(suit);
|
||||
gtk_entry_set_text(rating, star_strings[dive->rating]);
|
||||
gtk_text_buffer_set_text(gtk_text_view_get_buffer(notes),
|
||||
dive && dive->notes ? dive->notes : "", -1);
|
||||
|
@ -130,17 +166,26 @@ static int delete_dive_info(struct dive *dive)
|
|||
|
||||
static void info_menu_edit_cb(GtkMenuItem *menuitem, gpointer user_data)
|
||||
{
|
||||
edit_dive_info(current_dive);
|
||||
edit_multi_dive_info(NULL);
|
||||
}
|
||||
|
||||
static void info_menu_delete_cb(GtkMenuItem *menuitem, gpointer user_data)
|
||||
{
|
||||
/* this needs to delete all the selected dives as well, I guess? */
|
||||
delete_dive_info(current_dive);
|
||||
}
|
||||
|
||||
static void add_menu_item(GtkMenu *menu, const char *label, void (*cb)(GtkMenuItem *, gpointer))
|
||||
static void add_menu_item(GtkMenu *menu, const char *label, const char *icon, void (*cb)(GtkMenuItem *, gpointer))
|
||||
{
|
||||
GtkWidget *item = gtk_menu_item_new_with_label(label);
|
||||
GtkWidget *item;
|
||||
if (icon) {
|
||||
GtkWidget *image;
|
||||
item = gtk_image_menu_item_new_with_label(label);
|
||||
image = gtk_image_new_from_stock(icon, GTK_ICON_SIZE_MENU);
|
||||
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), image);
|
||||
} else {
|
||||
item = gtk_menu_item_new_with_label(label);
|
||||
}
|
||||
g_signal_connect(item, "activate", G_CALLBACK(cb), NULL);
|
||||
gtk_widget_show(item); /* Yes, really */
|
||||
gtk_menu_prepend(menu, item);
|
||||
|
@ -148,8 +193,8 @@ static void add_menu_item(GtkMenu *menu, const char *label, void (*cb)(GtkMenuIt
|
|||
|
||||
static void populate_popup_cb(GtkTextView *entry, GtkMenu *menu, gpointer user_data)
|
||||
{
|
||||
add_menu_item(menu, "Delete", info_menu_delete_cb);
|
||||
add_menu_item(menu, "Edit", info_menu_edit_cb);
|
||||
add_menu_item(menu, "Delete", GTK_STOCK_DELETE, info_menu_delete_cb);
|
||||
add_menu_item(menu, "Edit", GTK_STOCK_EDIT, info_menu_edit_cb);
|
||||
}
|
||||
|
||||
static GtkEntry *text_value(GtkWidget *box, const char *label)
|
||||
|
@ -241,6 +286,8 @@ static gboolean match_string_entry(GtkTreeModel *model, GtkTreePath *path, GtkTr
|
|||
|
||||
gtk_tree_model_get(model, iter, 0, &entry, -1);
|
||||
cmp = strcmp(entry, string);
|
||||
if (entry)
|
||||
free(entry);
|
||||
|
||||
/* Stop. The entry is bigger than the new one */
|
||||
if (cmp > 0)
|
||||
|
@ -295,6 +342,11 @@ void add_location(const char *string)
|
|||
add_string_list_entry(string, location_list);
|
||||
}
|
||||
|
||||
void add_suit(const char *string)
|
||||
{
|
||||
add_string_list_entry(string, suit_list);
|
||||
}
|
||||
|
||||
static int get_rating(const char *string)
|
||||
{
|
||||
int rating_val = 0;
|
||||
|
@ -307,61 +359,69 @@ static int get_rating(const char *string)
|
|||
}
|
||||
|
||||
struct dive_info {
|
||||
GtkComboBoxEntry *location, *divemaster, *buddy, *rating;
|
||||
GtkComboBoxEntry *location, *divemaster, *buddy, *rating, *suit;
|
||||
GtkTextView *notes;
|
||||
};
|
||||
|
||||
static void save_dive_info_changes(struct dive *dive, struct dive_info *info)
|
||||
static void save_dive_info_changes(struct dive *dive, struct dive *master, struct dive_info *info)
|
||||
{
|
||||
char *old_text, *new_text;
|
||||
char *rating_string;
|
||||
int changed = 0;
|
||||
|
||||
new_text = get_combo_box_entry_text(info->location, &dive->location);
|
||||
new_text = get_combo_box_entry_text(info->location, &dive->location, master->location);
|
||||
if (new_text) {
|
||||
add_location(new_text);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
new_text = get_combo_box_entry_text(info->divemaster, &dive->divemaster);
|
||||
new_text = get_combo_box_entry_text(info->divemaster, &dive->divemaster, master->divemaster);
|
||||
if (new_text) {
|
||||
add_people(new_text);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
new_text = get_combo_box_entry_text(info->buddy, &dive->buddy);
|
||||
new_text = get_combo_box_entry_text(info->buddy, &dive->buddy, master->buddy);
|
||||
if (new_text) {
|
||||
add_people(new_text);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
new_text = get_combo_box_entry_text(info->suit, &dive->suit, master->suit);
|
||||
if (new_text) {
|
||||
add_suit(new_text);
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
rating_string = strdup(star_strings[dive->rating]);
|
||||
new_text = get_combo_box_entry_text(info->rating, &rating_string);
|
||||
new_text = get_combo_box_entry_text(info->rating, &rating_string, star_strings[master->rating]);
|
||||
if (new_text) {
|
||||
dive->rating = get_rating(rating_string);
|
||||
free(rating_string);
|
||||
changed =1;
|
||||
}
|
||||
|
||||
old_text = dive->notes;
|
||||
dive->notes = get_text(info->notes);
|
||||
if (text_changed(old_text,dive->notes))
|
||||
changed = 1;
|
||||
if (old_text)
|
||||
g_free(old_text);
|
||||
|
||||
if (info->notes) {
|
||||
old_text = dive->notes;
|
||||
dive->notes = get_text(info->notes);
|
||||
if (text_changed(old_text,dive->notes))
|
||||
changed = 1;
|
||||
if (old_text)
|
||||
g_free(old_text);
|
||||
}
|
||||
if (changed) {
|
||||
mark_divelist_changed(TRUE);
|
||||
update_dive(dive);
|
||||
}
|
||||
}
|
||||
|
||||
static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info *info)
|
||||
static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info *info, gboolean multi)
|
||||
{
|
||||
GtkWidget *hbox, *label, *cylinder, *frame;
|
||||
char buffer[80];
|
||||
GtkWidget *hbox, *label, *frame, *equipment;
|
||||
char buffer[80] = "Edit multiple dives";
|
||||
|
||||
divename(buffer, sizeof(buffer), dive);
|
||||
if (!multi)
|
||||
divename(buffer, sizeof(buffer), dive);
|
||||
label = gtk_label_new(buffer);
|
||||
gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0);
|
||||
|
||||
|
@ -377,28 +437,65 @@ static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info
|
|||
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0);
|
||||
|
||||
info->rating = text_entry(hbox, "Rating", star_list, star_strings[dive->rating]);
|
||||
info->suit = text_entry(hbox, "Suit", suit_list, dive->suit);
|
||||
|
||||
info->notes = text_view(box, "Notes", READ_WRITE);
|
||||
if (dive->notes && *dive->notes)
|
||||
gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), dive->notes, -1);
|
||||
|
||||
/* only show notes if editing a single dive */
|
||||
if (multi) {
|
||||
info->notes = NULL;
|
||||
} else {
|
||||
info->notes = text_view(box, "Notes", READ_WRITE);
|
||||
if (dive->notes && *dive->notes)
|
||||
gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), dive->notes, -1);
|
||||
}
|
||||
hbox = gtk_hbox_new(FALSE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0);
|
||||
|
||||
frame = gtk_frame_new("Cylinder");
|
||||
cylinder = cylinder_list_widget();
|
||||
gtk_container_add(GTK_CONTAINER(frame), cylinder);
|
||||
/* create a secondary Equipment widget */
|
||||
frame = gtk_frame_new("Equipment");
|
||||
equipment = equipment_widget(W_IDX_SECONDARY);
|
||||
gtk_container_add(GTK_CONTAINER(frame), equipment);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 0);
|
||||
}
|
||||
|
||||
int edit_dive_info(struct dive *dive)
|
||||
/* we use these to find out if we edited the cylinder or weightsystem entries */
|
||||
static cylinder_t remember_cyl[MAX_CYLINDERS];
|
||||
static weightsystem_t remember_ws[MAX_WEIGHTSYSTEMS];
|
||||
#define CYL_BYTES sizeof(cylinder_t) * MAX_CYLINDERS
|
||||
#define WS_BYTES sizeof(weightsystem_t) * MAX_WEIGHTSYSTEMS
|
||||
|
||||
void save_equipment_data(struct dive *dive)
|
||||
{
|
||||
if (dive) {
|
||||
memcpy(remember_cyl, dive->cylinder, CYL_BYTES);
|
||||
memcpy(remember_ws, dive->weightsystem, WS_BYTES);
|
||||
}
|
||||
}
|
||||
|
||||
/* the editing happens on the master dive; we copy the equipment
|
||||
data if it has changed in the master dive and the other dive
|
||||
either has no entries for the equipment or the same entries
|
||||
as the master dive had before it was edited */
|
||||
void update_equipment_data(struct dive *dive, struct dive *master)
|
||||
{
|
||||
if (dive == master)
|
||||
return;
|
||||
if ( ! cylinders_equal(remember_cyl, master->cylinder) &&
|
||||
(no_cylinders(dive->cylinder) ||
|
||||
cylinders_equal(dive->cylinder, remember_cyl)))
|
||||
memcpy(dive->cylinder, master->cylinder, CYL_BYTES);
|
||||
if (! weightsystems_equal(remember_ws, master->weightsystem) &&
|
||||
(no_weightsystems(dive->weightsystem) ||
|
||||
weightsystems_equal(dive->weightsystem, remember_ws)))
|
||||
memcpy(dive->weightsystem, master->weightsystem, WS_BYTES);
|
||||
}
|
||||
|
||||
/* A negative index means "all selected" */
|
||||
int edit_multi_dive_info(struct dive *single_dive)
|
||||
{
|
||||
int success;
|
||||
GtkWidget *dialog, *vbox;
|
||||
struct dive_info info;
|
||||
|
||||
if (!dive)
|
||||
return 0;
|
||||
struct dive *master;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons("Dive Info",
|
||||
GTK_WINDOW(main_window),
|
||||
|
@ -408,18 +505,191 @@ int edit_dive_info(struct dive *dive)
|
|||
NULL);
|
||||
|
||||
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
dive_info_widget(vbox, dive, &info);
|
||||
|
||||
master = single_dive;
|
||||
if (!master)
|
||||
master = current_dive;
|
||||
dive_info_widget(vbox, master, &info, !single_dive);
|
||||
show_dive_equipment(master, W_IDX_SECONDARY);
|
||||
save_equipment_data(master);
|
||||
gtk_widget_show_all(dialog);
|
||||
success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT;
|
||||
if (success)
|
||||
save_dive_info_changes(dive, &info);
|
||||
if (success) {
|
||||
/* Update the non-current selected dives first */
|
||||
if (!single_dive) {
|
||||
int i;
|
||||
struct dive *dive;
|
||||
|
||||
for_each_dive(i, dive) {
|
||||
if (dive == master || !dive->selected)
|
||||
continue;
|
||||
/* copy all "info" fields */
|
||||
save_dive_info_changes(dive, master, &info);
|
||||
/* copy the cylinders / weightsystems */
|
||||
update_equipment_data(dive, master);
|
||||
/* this is extremely inefficient... it loops through all
|
||||
dives to find the right one - but we KNOW the index already */
|
||||
flush_divelist(dive);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update the master dive last! */
|
||||
save_dive_info_changes(master, master, &info);
|
||||
update_equipment_data(master, master);
|
||||
flush_divelist(master);
|
||||
}
|
||||
gtk_widget_destroy(dialog);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
int edit_dive_info(struct dive *dive)
|
||||
{
|
||||
if (!dive)
|
||||
return 0;
|
||||
return edit_multi_dive_info(dive);
|
||||
}
|
||||
|
||||
static GtkWidget *frame_box(GtkWidget *vbox, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char buffer[64];
|
||||
GtkWidget *frame, *hbox;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
frame = gtk_frame_new(buffer);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 0);
|
||||
hbox = gtk_hbox_new(0, 3);
|
||||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||||
return hbox;
|
||||
}
|
||||
|
||||
/* Fixme - should do at least depths too - a dive without a depth is kind of pointless */
|
||||
static time_t dive_time_widget(struct dive *dive)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *cal, *hbox, *vbox, *box;
|
||||
GtkWidget *h, *m;
|
||||
GtkWidget *duration, *depth;
|
||||
GtkWidget *label;
|
||||
guint yval, mval, dval;
|
||||
struct tm tm, *time;
|
||||
int success;
|
||||
double depthinterval, val;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons("Date and Time",
|
||||
GTK_WINDOW(main_window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
||||
NULL);
|
||||
|
||||
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||
|
||||
/* Calendar hbox */
|
||||
hbox = frame_box(vbox, "Date:");
|
||||
cal = gtk_calendar_new();
|
||||
gtk_box_pack_start(GTK_BOX(hbox), cal, FALSE, TRUE, 0);
|
||||
|
||||
/* Time hbox */
|
||||
hbox = frame_box(vbox, "Time");
|
||||
|
||||
h = gtk_spin_button_new_with_range (0.0, 23.0, 1.0);
|
||||
m = gtk_spin_button_new_with_range (0.0, 59.0, 1.0);
|
||||
|
||||
/*
|
||||
* If we have a dive selected, 'add dive' will default
|
||||
* to one hour after the end of that dive. Otherwise,
|
||||
* we'll just take the current time.
|
||||
*/
|
||||
if (amount_selected == 1) {
|
||||
time_t when = current_dive->when;
|
||||
when += current_dive->duration.seconds;
|
||||
when += 60*60;
|
||||
time = gmtime(&when);
|
||||
} else {
|
||||
time_t now;
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
now = tv.tv_sec;
|
||||
time = localtime(&now);
|
||||
}
|
||||
gtk_calendar_select_month(GTK_CALENDAR(cal), time->tm_mon, time->tm_year + 1900);
|
||||
gtk_calendar_select_day(GTK_CALENDAR(cal), time->tm_mday);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(h), time->tm_hour);
|
||||
gtk_spin_button_set_value(GTK_SPIN_BUTTON(m), (time->tm_min / 5)*5);
|
||||
|
||||
gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(h), TRUE);
|
||||
gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(m), TRUE);
|
||||
|
||||
gtk_box_pack_end(GTK_BOX(hbox), m, FALSE, FALSE, 0);
|
||||
label = gtk_label_new(":");
|
||||
gtk_box_pack_end(GTK_BOX(hbox), label, FALSE, FALSE, 0);
|
||||
gtk_box_pack_end(GTK_BOX(hbox), h, FALSE, FALSE, 0);
|
||||
|
||||
hbox = gtk_hbox_new(TRUE, 3);
|
||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
|
||||
|
||||
/* Duration hbox */
|
||||
box = frame_box(hbox, "Duration (min)");
|
||||
duration = gtk_spin_button_new_with_range (0.0, 1000.0, 1.0);
|
||||
gtk_box_pack_end(GTK_BOX(box), duration, FALSE, FALSE, 0);
|
||||
|
||||
/* Depth box */
|
||||
box = frame_box(hbox, "Depth (%s):", output_units.length == FEET ? "ft" : "m");
|
||||
if (output_units.length == FEET) {
|
||||
depthinterval = 1.0;
|
||||
} else {
|
||||
depthinterval = 0.1;
|
||||
}
|
||||
depth = gtk_spin_button_new_with_range (0.0, 1000.0, depthinterval);
|
||||
gtk_box_pack_end(GTK_BOX(box), depth, FALSE, FALSE, 0);
|
||||
|
||||
/* All done, show it and wait for editing */
|
||||
gtk_widget_show_all(dialog);
|
||||
success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT;
|
||||
if (!success) {
|
||||
gtk_widget_destroy(dialog);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
gtk_calendar_get_date(GTK_CALENDAR(cal), &yval, &mval, &dval);
|
||||
tm.tm_year = yval;
|
||||
tm.tm_mon = mval;
|
||||
tm.tm_mday = dval;
|
||||
|
||||
tm.tm_hour = gtk_spin_button_get_value(GTK_SPIN_BUTTON(h));
|
||||
tm.tm_min = gtk_spin_button_get_value(GTK_SPIN_BUTTON(m));
|
||||
|
||||
val = gtk_spin_button_get_value(GTK_SPIN_BUTTON(depth));
|
||||
if (output_units.length == FEET) {
|
||||
dive->maxdepth.mm = feet_to_mm(val);
|
||||
} else {
|
||||
dive->maxdepth.mm = val * 1000 + 0.5;
|
||||
}
|
||||
|
||||
dive->duration.seconds = gtk_spin_button_get_value(GTK_SPIN_BUTTON(duration))*60;
|
||||
|
||||
gtk_widget_destroy(dialog);
|
||||
dive->when = utc_mktime(&tm);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int add_new_dive(struct dive *dive)
|
||||
{
|
||||
if (!dive)
|
||||
return 0;
|
||||
|
||||
if (!dive_time_widget(dive))
|
||||
return 0;
|
||||
|
||||
return edit_dive_info(dive);
|
||||
}
|
||||
|
||||
GtkWidget *extended_dive_info_widget(void)
|
||||
{
|
||||
GtkWidget *vbox, *hbox;
|
||||
|
@ -434,6 +704,7 @@ GtkWidget *extended_dive_info_widget(void)
|
|||
add_string_list_entry(THREE_STARS, star_list);
|
||||
add_string_list_entry(FOUR_STARS, star_list);
|
||||
add_string_list_entry(FIVE_STARS, star_list);
|
||||
suit_list = gtk_list_store_new(1, G_TYPE_STRING);
|
||||
|
||||
gtk_container_set_border_width(GTK_CONTAINER(vbox), 6);
|
||||
location = text_value(vbox, "Location");
|
||||
|
@ -448,6 +719,7 @@ GtkWidget *extended_dive_info_widget(void)
|
|||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
|
||||
|
||||
rating = text_value(hbox, "Rating");
|
||||
suit = text_value(hbox, "Suit");
|
||||
|
||||
notes = text_view(vbox, "Notes", READ_ONLY);
|
||||
return vbox;
|
||||
|
|
|
@ -31,90 +31,22 @@ static GError *error(const char *fmt, ...)
|
|||
return error;
|
||||
}
|
||||
|
||||
static parser_status_t create_parser(device_data_t *devdata, parser_t **parser)
|
||||
static dc_status_t create_parser(device_data_t *devdata, dc_parser_t **parser)
|
||||
{
|
||||
switch (devdata->type) {
|
||||
case DEVICE_TYPE_SUUNTO_SOLUTION:
|
||||
return suunto_solution_parser_create(parser);
|
||||
|
||||
case DEVICE_TYPE_SUUNTO_EON:
|
||||
return suunto_eon_parser_create(parser, 0);
|
||||
|
||||
case DEVICE_TYPE_SUUNTO_VYPER:
|
||||
if (devdata->devinfo.model == 0x01)
|
||||
return suunto_eon_parser_create(parser, 1);
|
||||
return suunto_vyper_parser_create(parser);
|
||||
|
||||
case DEVICE_TYPE_SUUNTO_VYPER2:
|
||||
case DEVICE_TYPE_SUUNTO_D9:
|
||||
return suunto_d9_parser_create(parser, devdata->devinfo.model);
|
||||
|
||||
case DEVICE_TYPE_UWATEC_ALADIN:
|
||||
case DEVICE_TYPE_UWATEC_MEMOMOUSE:
|
||||
return uwatec_memomouse_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
|
||||
|
||||
case DEVICE_TYPE_UWATEC_SMART:
|
||||
return uwatec_smart_parser_create(parser, devdata->devinfo.model, devdata->clock.devtime, devdata->clock.systime);
|
||||
|
||||
case DEVICE_TYPE_REEFNET_SENSUS:
|
||||
return reefnet_sensus_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
|
||||
|
||||
case DEVICE_TYPE_REEFNET_SENSUSPRO:
|
||||
return reefnet_sensuspro_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
|
||||
|
||||
case DEVICE_TYPE_REEFNET_SENSUSULTRA:
|
||||
return reefnet_sensusultra_parser_create(parser, devdata->clock.devtime, devdata->clock.systime);
|
||||
|
||||
case DEVICE_TYPE_OCEANIC_VTPRO:
|
||||
return oceanic_vtpro_parser_create(parser);
|
||||
|
||||
case DEVICE_TYPE_OCEANIC_VEO250:
|
||||
return oceanic_veo250_parser_create(parser, devdata->devinfo.model);
|
||||
|
||||
case DEVICE_TYPE_OCEANIC_ATOM2:
|
||||
return oceanic_atom2_parser_create(parser, devdata->devinfo.model);
|
||||
|
||||
case DEVICE_TYPE_MARES_DARWIN:
|
||||
return mares_darwin_parser_create(parser, devdata->devinfo.model);
|
||||
|
||||
case DEVICE_TYPE_MARES_NEMO:
|
||||
case DEVICE_TYPE_MARES_PUCK:
|
||||
return mares_nemo_parser_create(parser, devdata->devinfo.model);
|
||||
|
||||
case DEVICE_TYPE_MARES_ICONHD:
|
||||
return mares_iconhd_parser_create(parser, devdata->devinfo.model);
|
||||
|
||||
case DEVICE_TYPE_HW_OSTC:
|
||||
return hw_ostc_parser_create(parser NOT_FROG);
|
||||
|
||||
#ifdef LIBDIVECOMPUTER_SUPPORTS_FROG
|
||||
case DEVICE_TYPE_HW_FROG:
|
||||
return hw_ostc_parser_create(parser, 1);
|
||||
#endif
|
||||
|
||||
case DEVICE_TYPE_CRESSI_EDY:
|
||||
case DEVICE_TYPE_ZEAGLE_N2ITION3:
|
||||
return cressi_edy_parser_create(parser, devdata->devinfo.model);
|
||||
|
||||
case DEVICE_TYPE_ATOMICS_COBALT:
|
||||
return atomics_cobalt_parser_create(parser);
|
||||
|
||||
default:
|
||||
return PARSER_STATUS_ERROR;
|
||||
}
|
||||
return dc_parser_new(parser, devdata->device);
|
||||
}
|
||||
|
||||
static int parse_gasmixes(device_data_t *devdata, struct dive *dive, parser_t *parser, int ngases)
|
||||
static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t *parser, int ngases)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ngases; i++) {
|
||||
int rc;
|
||||
gasmix_t gasmix = {0};
|
||||
dc_gasmix_t gasmix = {0};
|
||||
int o2, he;
|
||||
|
||||
rc = parser_get_field(parser, FIELD_TYPE_GASMIX, i, &gasmix);
|
||||
if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED)
|
||||
rc = dc_parser_get_field(parser, DC_FIELD_GASMIX, i, &gasmix);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED)
|
||||
return rc;
|
||||
|
||||
if (i >= MAX_CYLINDERS)
|
||||
|
@ -132,10 +64,10 @@ static int parse_gasmixes(device_data_t *devdata, struct dive *dive, parser_t *p
|
|||
dive->cylinder[i].gasmix.o2.permille = o2;
|
||||
dive->cylinder[i].gasmix.he.permille = he;
|
||||
}
|
||||
return PARSER_STATUS_SUCCESS;
|
||||
return DC_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void handle_event(struct dive *dive, struct sample *sample, parser_sample_value_t value)
|
||||
static void handle_event(struct dive *dive, struct sample *sample, dc_sample_value_t value)
|
||||
{
|
||||
int type, time;
|
||||
static const char *events[] = {
|
||||
|
@ -173,7 +105,7 @@ static void handle_event(struct dive *dive, struct sample *sample, parser_sample
|
|||
}
|
||||
|
||||
void
|
||||
sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata)
|
||||
sample_cb(dc_sample_type_t type, dc_sample_value_t value, void *userdata)
|
||||
{
|
||||
int i;
|
||||
struct dive **divep = userdata;
|
||||
|
@ -181,40 +113,40 @@ sample_cb(parser_sample_type_t type, parser_sample_value_t value, void *userdata
|
|||
struct sample *sample;
|
||||
|
||||
/*
|
||||
* We fill in the "previous" sample - except for SAMPLE_TYPE_TIME,
|
||||
* We fill in the "previous" sample - except for DC_SAMPLE_TIME,
|
||||
* which creates a new one.
|
||||
*/
|
||||
sample = dive->samples ? dive->sample+dive->samples-1 : NULL;
|
||||
|
||||
switch (type) {
|
||||
case SAMPLE_TYPE_TIME:
|
||||
case DC_SAMPLE_TIME:
|
||||
sample = prepare_sample(divep);
|
||||
sample->time.seconds = value.time;
|
||||
finish_sample(*divep);
|
||||
break;
|
||||
case SAMPLE_TYPE_DEPTH:
|
||||
case DC_SAMPLE_DEPTH:
|
||||
sample->depth.mm = value.depth * 1000 + 0.5;
|
||||
break;
|
||||
case SAMPLE_TYPE_PRESSURE:
|
||||
case DC_SAMPLE_PRESSURE:
|
||||
sample->cylinderindex = value.pressure.tank;
|
||||
sample->cylinderpressure.mbar = value.pressure.value * 1000 + 0.5;
|
||||
break;
|
||||
case SAMPLE_TYPE_TEMPERATURE:
|
||||
case DC_SAMPLE_TEMPERATURE:
|
||||
sample->temperature.mkelvin = (value.temperature + 273.15) * 1000 + 0.5;
|
||||
break;
|
||||
case SAMPLE_TYPE_EVENT:
|
||||
case DC_SAMPLE_EVENT:
|
||||
handle_event(dive, sample, value);
|
||||
break;
|
||||
case SAMPLE_TYPE_RBT:
|
||||
case DC_SAMPLE_RBT:
|
||||
printf(" <rbt>%u</rbt>\n", value.rbt);
|
||||
break;
|
||||
case SAMPLE_TYPE_HEARTBEAT:
|
||||
case DC_SAMPLE_HEARTBEAT:
|
||||
printf(" <heartbeat>%u</heartbeat>\n", value.heartbeat);
|
||||
break;
|
||||
case SAMPLE_TYPE_BEARING:
|
||||
case DC_SAMPLE_BEARING:
|
||||
printf(" <bearing>%u</bearing>\n", value.bearing);
|
||||
break;
|
||||
case SAMPLE_TYPE_VENDOR:
|
||||
case DC_SAMPLE_VENDOR:
|
||||
printf(" <vendor type=\"%u\" size=\"%u\">", value.vendor.type, value.vendor.size);
|
||||
for (i = 0; i < value.vendor.size; ++i)
|
||||
printf("%02X", ((unsigned char *) value.vendor.data)[i]);
|
||||
|
@ -238,10 +170,10 @@ static void dev_info(device_data_t *devdata, const char *fmt, ...)
|
|||
|
||||
static int import_dive_number = 0;
|
||||
|
||||
static int parse_samples(device_data_t *devdata, struct dive **divep, parser_t *parser)
|
||||
static int parse_samples(device_data_t *devdata, struct dive **divep, dc_parser_t *parser)
|
||||
{
|
||||
// Parse the sample data.
|
||||
return parser_samples_foreach(parser, sample_cb, divep);
|
||||
return dc_parser_samples_foreach(parser, sample_cb, divep);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -275,31 +207,31 @@ static int dive_cb(const unsigned char *data, unsigned int size,
|
|||
void *userdata)
|
||||
{
|
||||
int rc;
|
||||
parser_t *parser = NULL;
|
||||
dc_parser_t *parser = NULL;
|
||||
device_data_t *devdata = userdata;
|
||||
dc_datetime_t dt = {0};
|
||||
struct tm tm;
|
||||
struct dive *dive;
|
||||
|
||||
rc = create_parser(devdata, &parser);
|
||||
if (rc != PARSER_STATUS_SUCCESS) {
|
||||
dev_info(devdata, "Unable to create parser for %s", devdata->name);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dev_info(devdata, "Unable to create parser for %s %s", devdata->vendor, devdata->product);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = parser_set_data(parser, data, size);
|
||||
if (rc != PARSER_STATUS_SUCCESS) {
|
||||
rc = dc_parser_set_data(parser, data, size);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dev_info(devdata, "Error registering the data");
|
||||
parser_destroy(parser);
|
||||
dc_parser_destroy(parser);
|
||||
return rc;
|
||||
}
|
||||
|
||||
import_dive_number++;
|
||||
dive = alloc_dive();
|
||||
rc = parser_get_datetime(parser, &dt);
|
||||
if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
|
||||
rc = dc_parser_get_datetime(parser, &dt);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
dev_info(devdata, "Error parsing the datetime");
|
||||
parser_destroy (parser);
|
||||
dc_parser_destroy(parser);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -315,49 +247,49 @@ static int dive_cb(const unsigned char *data, unsigned int size,
|
|||
dev_info(devdata, "Dive %d: %s %d %04d", import_dive_number,
|
||||
monthname(tm.tm_mon), tm.tm_mday, year(tm.tm_year));
|
||||
unsigned int divetime = 0;
|
||||
rc = parser_get_field (parser, FIELD_TYPE_DIVETIME, 0, &divetime);
|
||||
if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
|
||||
rc = dc_parser_get_field (parser, DC_FIELD_DIVETIME, 0, &divetime);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
dev_info(devdata, "Error parsing the divetime");
|
||||
parser_destroy(parser);
|
||||
dc_parser_destroy(parser);
|
||||
return rc;
|
||||
}
|
||||
dive->duration.seconds = divetime;
|
||||
|
||||
// Parse the maxdepth.
|
||||
double maxdepth = 0.0;
|
||||
rc = parser_get_field(parser, FIELD_TYPE_MAXDEPTH, 0, &maxdepth);
|
||||
if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
|
||||
rc = dc_parser_get_field(parser, DC_FIELD_MAXDEPTH, 0, &maxdepth);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
dev_info(devdata, "Error parsing the maxdepth");
|
||||
parser_destroy(parser);
|
||||
dc_parser_destroy(parser);
|
||||
return rc;
|
||||
}
|
||||
dive->maxdepth.mm = maxdepth * 1000 + 0.5;
|
||||
|
||||
// Parse the gas mixes.
|
||||
unsigned int ngases = 0;
|
||||
rc = parser_get_field(parser, FIELD_TYPE_GASMIX_COUNT, 0, &ngases);
|
||||
if (rc != PARSER_STATUS_SUCCESS && rc != PARSER_STATUS_UNSUPPORTED) {
|
||||
rc = dc_parser_get_field(parser, DC_FIELD_GASMIX_COUNT, 0, &ngases);
|
||||
if (rc != DC_STATUS_SUCCESS && rc != DC_STATUS_UNSUPPORTED) {
|
||||
dev_info(devdata, "Error parsing the gas mix count");
|
||||
parser_destroy(parser);
|
||||
dc_parser_destroy(parser);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = parse_gasmixes(devdata, dive, parser, ngases);
|
||||
if (rc != PARSER_STATUS_SUCCESS) {
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dev_info(devdata, "Error parsing the gas mix");
|
||||
parser_destroy(parser);
|
||||
dc_parser_destroy(parser);
|
||||
return rc;
|
||||
}
|
||||
|
||||
// Initialize the sample data.
|
||||
rc = parse_samples(devdata, &dive, parser);
|
||||
if (rc != PARSER_STATUS_SUCCESS) {
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dev_info(devdata, "Error parsing the samples");
|
||||
parser_destroy(parser);
|
||||
dc_parser_destroy(parser);
|
||||
return rc;
|
||||
}
|
||||
|
||||
parser_destroy(parser);
|
||||
dc_parser_destroy(parser);
|
||||
|
||||
/* If we already saw this dive, abort. */
|
||||
if (find_dive(dive, devdata))
|
||||
|
@ -368,112 +300,41 @@ static int dive_cb(const unsigned char *data, unsigned int size,
|
|||
}
|
||||
|
||||
|
||||
static device_status_t import_device_data(device_t *device, device_data_t *devicedata)
|
||||
static dc_status_t import_device_data(dc_device_t *device, device_data_t *devicedata)
|
||||
{
|
||||
return device_foreach(device, dive_cb, devicedata);
|
||||
return dc_device_foreach(device, dive_cb, devicedata);
|
||||
}
|
||||
|
||||
static device_status_t device_open(const char *devname,
|
||||
device_type_t type,
|
||||
device_t **device)
|
||||
static dc_status_t device_open(const char *devname,
|
||||
dc_descriptor_t *descriptor,
|
||||
dc_device_t **device)
|
||||
{
|
||||
switch (type) {
|
||||
case DEVICE_TYPE_SUUNTO_SOLUTION:
|
||||
return suunto_solution_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_SUUNTO_EON:
|
||||
return suunto_eon_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_SUUNTO_VYPER:
|
||||
return suunto_vyper_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_SUUNTO_VYPER2:
|
||||
return suunto_vyper2_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_SUUNTO_D9:
|
||||
return suunto_d9_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_UWATEC_ALADIN:
|
||||
return uwatec_aladin_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_UWATEC_MEMOMOUSE:
|
||||
return uwatec_memomouse_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_UWATEC_SMART:
|
||||
return uwatec_smart_device_open(device);
|
||||
|
||||
case DEVICE_TYPE_REEFNET_SENSUS:
|
||||
return reefnet_sensus_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_REEFNET_SENSUSPRO:
|
||||
return reefnet_sensuspro_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_REEFNET_SENSUSULTRA:
|
||||
return reefnet_sensusultra_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_OCEANIC_VTPRO:
|
||||
return oceanic_vtpro_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_OCEANIC_VEO250:
|
||||
return oceanic_veo250_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_OCEANIC_ATOM2:
|
||||
return oceanic_atom2_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_MARES_DARWIN:
|
||||
return mares_darwin_device_open(device, devname, 0); /// last parameter is model type (taken from example), 0 seems to be standard, 1 is DARWIN_AIR => Darwin Air wont work if this is fixed here?
|
||||
|
||||
case DEVICE_TYPE_MARES_NEMO:
|
||||
return mares_nemo_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_MARES_PUCK:
|
||||
return mares_puck_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_MARES_ICONHD:
|
||||
return mares_iconhd_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_HW_OSTC:
|
||||
return hw_ostc_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_CRESSI_EDY:
|
||||
return cressi_edy_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_ZEAGLE_N2ITION3:
|
||||
return zeagle_n2ition3_device_open(device, devname);
|
||||
|
||||
case DEVICE_TYPE_ATOMICS_COBALT:
|
||||
return atomics_cobalt_device_open(device);
|
||||
|
||||
default:
|
||||
return DEVICE_STATUS_ERROR;
|
||||
}
|
||||
return dc_device_open(device, descriptor, devname);
|
||||
}
|
||||
|
||||
|
||||
static void event_cb(device_t *device, device_event_t event, const void *data, void *userdata)
|
||||
static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
|
||||
{
|
||||
const device_progress_t *progress = data;
|
||||
const device_devinfo_t *devinfo = data;
|
||||
const device_clock_t *clock = data;
|
||||
const dc_event_progress_t *progress = data;
|
||||
const dc_event_devinfo_t *devinfo = data;
|
||||
const dc_event_clock_t *clock = data;
|
||||
device_data_t *devdata = userdata;
|
||||
|
||||
switch (event) {
|
||||
case DEVICE_EVENT_WAITING:
|
||||
case DC_EVENT_WAITING:
|
||||
dev_info(devdata, "Event: waiting for user action");
|
||||
break;
|
||||
case DEVICE_EVENT_PROGRESS:
|
||||
case DC_EVENT_PROGRESS:
|
||||
update_progressbar(&devdata->progress,
|
||||
(double) progress->current / (double) progress->maximum);
|
||||
break;
|
||||
case DEVICE_EVENT_DEVINFO:
|
||||
devdata->devinfo = *devinfo;
|
||||
case DC_EVENT_DEVINFO:
|
||||
dev_info(devdata, "model=%u (0x%08x), firmware=%u (0x%08x), serial=%u (0x%08x)",
|
||||
devinfo->model, devinfo->model,
|
||||
devinfo->firmware, devinfo->firmware,
|
||||
devinfo->serial, devinfo->serial);
|
||||
break;
|
||||
case DEVICE_EVENT_CLOCK:
|
||||
devdata->clock = *clock;
|
||||
case DC_EVENT_CLOCK:
|
||||
dev_info(devdata, "Event: systime=%"PRId64", devtime=%u\n",
|
||||
(uint64_t)clock->systime, clock->devtime);
|
||||
break;
|
||||
|
@ -492,36 +353,37 @@ cancel_cb(void *userdata)
|
|||
|
||||
static const char *do_libdivecomputer_import(device_data_t *data)
|
||||
{
|
||||
device_t *device = NULL;
|
||||
device_status_t rc;
|
||||
dc_device_t *device = NULL;
|
||||
dc_status_t rc;
|
||||
|
||||
import_dive_number = 0;
|
||||
rc = device_open(data->devname, data->type, &device);
|
||||
if (rc != DEVICE_STATUS_SUCCESS)
|
||||
return "Unable to open %s (%s)";
|
||||
rc = device_open(data->devname, data->descriptor, &device);
|
||||
if (rc != DC_STATUS_SUCCESS)
|
||||
return "Unable to open %s %s (%s)";
|
||||
data->device = device;
|
||||
|
||||
// Register the event handler.
|
||||
int events = DEVICE_EVENT_WAITING | DEVICE_EVENT_PROGRESS | DEVICE_EVENT_DEVINFO | DEVICE_EVENT_CLOCK;
|
||||
rc = device_set_events(device, events, event_cb, data);
|
||||
if (rc != DEVICE_STATUS_SUCCESS) {
|
||||
device_close(device);
|
||||
int events = DC_EVENT_WAITING | DC_EVENT_PROGRESS | DC_EVENT_DEVINFO | DC_EVENT_CLOCK;
|
||||
rc = dc_device_set_events(device, events, event_cb, data);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dc_device_close(device);
|
||||
return "Error registering the event handler.";
|
||||
}
|
||||
|
||||
// Register the cancellation handler.
|
||||
rc = device_set_cancel(device, cancel_cb, data);
|
||||
if (rc != DEVICE_STATUS_SUCCESS) {
|
||||
device_close(device);
|
||||
rc = dc_device_set_cancel(device, cancel_cb, data);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dc_device_close(device);
|
||||
return "Error registering the cancellation handler.";
|
||||
}
|
||||
|
||||
rc = import_device_data(device, data);
|
||||
if (rc != DEVICE_STATUS_SUCCESS) {
|
||||
device_close(device);
|
||||
if (rc != DC_STATUS_SUCCESS) {
|
||||
dc_device_close(device);
|
||||
return "Dive data import error";
|
||||
}
|
||||
|
||||
device_close(device);
|
||||
dc_device_close(device);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -548,42 +410,6 @@ GError *do_import(device_data_t *data)
|
|||
if (pthread_join(pthread, &retval) < 0)
|
||||
retval = "Odd pthread error return";
|
||||
if (retval)
|
||||
return error(retval, data->name, data->devname);
|
||||
return error(retval, data->vendor, data->product, data->devname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Taken from 'example.c' in libdivecomputer.
|
||||
*
|
||||
* I really wish there was some way to just have
|
||||
* libdivecomputer tell us what devices it supports,
|
||||
* rather than have the application have to know..
|
||||
*/
|
||||
struct device_list device_list[] = {
|
||||
{ "Suunto Solution", DEVICE_TYPE_SUUNTO_SOLUTION },
|
||||
{ "Suunto Eon", DEVICE_TYPE_SUUNTO_EON },
|
||||
{ "Suunto Vyper", DEVICE_TYPE_SUUNTO_VYPER },
|
||||
{ "Suunto Vyper Air", DEVICE_TYPE_SUUNTO_VYPER2 },
|
||||
{ "Suunto D9", DEVICE_TYPE_SUUNTO_D9 },
|
||||
{ "Uwatec Aladin", DEVICE_TYPE_UWATEC_ALADIN },
|
||||
{ "Uwatec Memo Mouse", DEVICE_TYPE_UWATEC_MEMOMOUSE },
|
||||
{ "Uwatec Smart", DEVICE_TYPE_UWATEC_SMART },
|
||||
{ "ReefNet Sensus", DEVICE_TYPE_REEFNET_SENSUS },
|
||||
{ "ReefNet Sensus Pro", DEVICE_TYPE_REEFNET_SENSUSPRO },
|
||||
{ "ReefNet Sensus Ultra",DEVICE_TYPE_REEFNET_SENSUSULTRA },
|
||||
{ "Oceanic VT Pro", DEVICE_TYPE_OCEANIC_VTPRO },
|
||||
{ "Oceanic Veo250", DEVICE_TYPE_OCEANIC_VEO250 },
|
||||
{ "Oceanic Atom 2", DEVICE_TYPE_OCEANIC_ATOM2 },
|
||||
{ "Mares Darwin, M1, M2, Airlab", DEVICE_TYPE_MARES_DARWIN },
|
||||
{ "Mares Nemo, Excel, Apneist", DEVICE_TYPE_MARES_NEMO },
|
||||
{ "Mares Puck, Nemo Air, Nemo Wide", DEVICE_TYPE_MARES_PUCK },
|
||||
{ "Mares Icon HD", DEVICE_TYPE_MARES_ICONHD },
|
||||
{ "OSTC", DEVICE_TYPE_HW_OSTC },
|
||||
#ifdef LIBDIVECOMPUTER_SUPPORTS_FROG
|
||||
{ "OSTC Frog", DEVICE_TYPE_HW_FROG },
|
||||
#endif
|
||||
{ "Cressi Edy", DEVICE_TYPE_CRESSI_EDY },
|
||||
{ "Zeagle N2iTiON 3", DEVICE_TYPE_ZEAGLE_N2ITION3 },
|
||||
{ "Atomics Cobalt", DEVICE_TYPE_ATOMICS_COBALT },
|
||||
{ NULL }
|
||||
};
|
||||
|
|
|
@ -2,17 +2,9 @@
|
|||
#define LIBDIVECOMPUTER_H
|
||||
|
||||
/* libdivecomputer */
|
||||
#include <device.h>
|
||||
#include <suunto.h>
|
||||
#include <reefnet.h>
|
||||
#include <uwatec.h>
|
||||
#include <oceanic.h>
|
||||
#include <mares.h>
|
||||
#include <hw.h>
|
||||
#include <cressi.h>
|
||||
#include <zeagle.h>
|
||||
#include <atomics.h>
|
||||
#include <utils.h>
|
||||
#include <libdivecomputer/device.h>
|
||||
#include <libdivecomputer/parser.h>
|
||||
#include <libdivecomputer/utils.h>
|
||||
|
||||
/* handling uemis Zurich SDA files */
|
||||
#include "uemis.h"
|
||||
|
@ -20,20 +12,13 @@
|
|||
/* don't forget to include the UI toolkit specific display-XXX.h first
|
||||
to get the definition of progressbar_t */
|
||||
typedef struct device_data_t {
|
||||
device_type_t type;
|
||||
const char *name, *devname;
|
||||
dc_descriptor_t *descriptor;
|
||||
const char *vendor, *product, *devname;
|
||||
dc_device_t *device;
|
||||
progressbar_t progress;
|
||||
device_devinfo_t devinfo;
|
||||
device_clock_t clock;
|
||||
int preexisting;
|
||||
} device_data_t;
|
||||
|
||||
struct device_list {
|
||||
const char *name;
|
||||
device_type_t type;
|
||||
};
|
||||
|
||||
extern struct device_list device_list[];
|
||||
extern GError *do_import(device_data_t *data);
|
||||
|
||||
#endif
|
||||
|
|
5
macos.c
5
macos.c
|
@ -98,10 +98,9 @@ void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar,
|
|||
gtk_widget_hide (menubar);
|
||||
gtk_osxapplication_set_menu_bar(osx_app, GTK_MENU_SHELL(menubar));
|
||||
|
||||
sep = gtk_ui_manager_get_widget(ui_manager, "/MainMenu/FileMenu/Separator3");
|
||||
gtk_widget_destroy(sep);
|
||||
sep = gtk_ui_manager_get_widget(ui_manager, "/MainMenu/FileMenu/Separator2");
|
||||
gtk_widget_destroy(sep);
|
||||
if (sep)
|
||||
gtk_widget_destroy(sep);
|
||||
|
||||
menu_item = gtk_ui_manager_get_widget(ui_manager, "/MainMenu/FileMenu/Quit");
|
||||
gtk_widget_hide (menu_item);
|
||||
|
|
2
main.c
2
main.c
|
@ -190,7 +190,7 @@ void update_dive(struct dive *new_dive)
|
|||
}
|
||||
if (new_dive) {
|
||||
show_dive_info(new_dive);
|
||||
show_dive_equipment(new_dive);
|
||||
show_dive_equipment(new_dive, W_IDX_PRIMARY);
|
||||
show_dive_stats(new_dive);
|
||||
}
|
||||
buffered_dive = new_dive;
|
||||
|
|
|
@ -647,6 +647,7 @@ static int uddf_fill_sample(struct sample *sample, const char *name, int len, ch
|
|||
return MATCH(".divetime", sampletime, &sample->time) ||
|
||||
MATCH(".depth", depth, &sample->depth) ||
|
||||
MATCH(".temperature", temperature, &sample->temperature) ||
|
||||
MATCH(".tankpressure", pressure, &sample->cylinderpressure) ||
|
||||
0;
|
||||
}
|
||||
|
||||
|
@ -1099,6 +1100,10 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf)
|
|||
return;
|
||||
if (MATCH(".location", utf8_string, &dive->location))
|
||||
return;
|
||||
if (MATCH(".suit", utf8_string, &dive->suit))
|
||||
return;
|
||||
if (MATCH(".divesuit", utf8_string, &dive->suit))
|
||||
return;
|
||||
if (MATCH(".notes", utf8_string, &dive->notes))
|
||||
return;
|
||||
if (MATCH(".divemaster", utf8_string, &dive->divemaster))
|
||||
|
|
18
print.c
18
print.c
|
@ -196,6 +196,22 @@ static void begin_print(GtkPrintOperation *operation, gpointer user_data)
|
|||
{
|
||||
}
|
||||
|
||||
static GtkWidget *print_dialog(GtkPrintOperation *operation, gpointer user_data)
|
||||
{
|
||||
GtkWidget *vbox, *hbox, *label;
|
||||
gtk_print_operation_set_custom_tab_label(operation, "Dive details");
|
||||
|
||||
vbox = gtk_vbox_new(TRUE, 5);
|
||||
label = gtk_label_new("Print Dive details");
|
||||
gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
|
||||
gtk_widget_show_all(vbox);
|
||||
return vbox;
|
||||
}
|
||||
|
||||
static void print_dialog_apply(GtkPrintOperation *operation, GtkWidget *widget, gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static GtkPrintSettings *settings = NULL;
|
||||
|
||||
void do_print(void)
|
||||
|
@ -210,6 +226,8 @@ void do_print(void)
|
|||
gtk_print_operation_set_print_settings(print, settings);
|
||||
pages = (dive_table.nr + 5) / 6;
|
||||
gtk_print_operation_set_n_pages(print, pages);
|
||||
g_signal_connect(print, "create-custom-widget", G_CALLBACK(print_dialog), NULL);
|
||||
g_signal_connect(print, "custom-widget-apply", G_CALLBACK(print_dialog_apply), NULL);
|
||||
g_signal_connect(print, "begin_print", G_CALLBACK(begin_print), NULL);
|
||||
g_signal_connect(print, "draw_page", G_CALLBACK(draw_page), NULL);
|
||||
res = gtk_print_operation_run(print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
|
||||
|
|
27
profile.c
27
profile.c
|
@ -1074,16 +1074,18 @@ static void fill_missing_tank_pressures(struct plot_info *pi, pr_track_t **track
|
|||
/* there may be multiple segments - so
|
||||
* let's assemble the length */
|
||||
nlist = list;
|
||||
pt = list->pressure_time;
|
||||
while (!nlist->end) {
|
||||
nlist = nlist->next;
|
||||
if (!nlist) {
|
||||
/* oops - we have no end pressure,
|
||||
* so this means this is a tank without
|
||||
* gas consumption information */
|
||||
break;
|
||||
if (list) {
|
||||
pt = list->pressure_time;
|
||||
while (!nlist->end) {
|
||||
nlist = nlist->next;
|
||||
if (!nlist) {
|
||||
/* oops - we have no end pressure,
|
||||
* so this means this is a tank without
|
||||
* gas consumption information */
|
||||
break;
|
||||
}
|
||||
pt += nlist->pressure_time;
|
||||
}
|
||||
pt += nlist->pressure_time;
|
||||
}
|
||||
if (!nlist) {
|
||||
/* just continue without calculating
|
||||
|
@ -1380,12 +1382,15 @@ void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, stru
|
|||
int nr = dive->samples;
|
||||
|
||||
if (!nr) {
|
||||
/* The dive has no samples, so create a few fake ones. This assumes an
|
||||
ascent/descent rate of 9 m/min, which is just below the limit for FAST. */
|
||||
int duration = dive->duration.seconds;
|
||||
int maxdepth = dive->maxdepth.mm;
|
||||
int asc_desc_time = dive->maxdepth.mm*60/9000;
|
||||
sample = fake;
|
||||
fake[1].time.seconds = duration * 0.05;
|
||||
fake[1].time.seconds = asc_desc_time;
|
||||
fake[1].depth.mm = maxdepth;
|
||||
fake[2].time.seconds = duration * 0.95;
|
||||
fake[2].time.seconds = duration - asc_desc_time;
|
||||
fake[2].depth.mm = maxdepth;
|
||||
fake[3].time.seconds = duration * 1.00;
|
||||
nr = 4;
|
||||
|
|
|
@ -183,6 +183,7 @@ static void save_overview(FILE *f, struct dive *dive)
|
|||
show_utf8(f, dive->divemaster, " <divemaster>","</divemaster>\n");
|
||||
show_utf8(f, dive->buddy, " <buddy>","</buddy>\n");
|
||||
show_utf8(f, dive->notes, " <notes>","</notes>\n");
|
||||
show_utf8(f, dive->suit, " <suit>","</suit>\n");
|
||||
}
|
||||
|
||||
static void save_cylinder_info(FILE *f, struct dive *dive)
|
||||
|
|
55
statistics.c
55
statistics.c
|
@ -91,6 +91,18 @@ static void process_dive(struct dive *dp, stats_t *stats)
|
|||
stats->max_depth.mm = dp->maxdepth.mm;
|
||||
if (stats->min_depth.mm == 0 || dp->maxdepth.mm < stats->min_depth.mm)
|
||||
stats->min_depth.mm = dp->maxdepth.mm;
|
||||
if (dp->watertemp.mkelvin) {
|
||||
if (stats->min_temp == 0 || dp->watertemp.mkelvin < stats->min_temp)
|
||||
stats->min_temp = dp->watertemp.mkelvin;
|
||||
if (dp->watertemp.mkelvin > stats->max_temp)
|
||||
stats->max_temp = dp->watertemp.mkelvin;
|
||||
stats->combined_temp += get_temp_units(dp->watertemp.mkelvin, &unit);
|
||||
stats->combined_count++;
|
||||
}
|
||||
|
||||
/* Maybe we should drop zero-duration dives */
|
||||
if (!dp->duration.seconds)
|
||||
return;
|
||||
stats->avg_depth.mm = (1.0 * old_tt * stats->avg_depth.mm +
|
||||
dp->duration.seconds * dp->meandepth.mm) / stats->total_time.seconds;
|
||||
if (dp->sac > 2800) { /* less than .1 cuft/min (2800ml/min) is bogus */
|
||||
|
@ -103,14 +115,6 @@ static void process_dive(struct dive *dp, stats_t *stats)
|
|||
stats->min_sac.mliter = dp->sac;
|
||||
stats->total_sac_time = sac_time;
|
||||
}
|
||||
if (dp->watertemp.mkelvin) {
|
||||
if (stats->min_temp == 0 || dp->watertemp.mkelvin < stats->min_temp)
|
||||
stats->min_temp = dp->watertemp.mkelvin;
|
||||
if (dp->watertemp.mkelvin > stats->max_temp)
|
||||
stats->max_temp = dp->watertemp.mkelvin;
|
||||
stats->combined_temp += get_temp_units(dp->watertemp.mkelvin, &unit);
|
||||
stats->combined_count++;
|
||||
}
|
||||
}
|
||||
|
||||
static void process_all_dives(struct dive *dive, struct dive **prev_dive)
|
||||
|
@ -138,25 +142,22 @@ static void process_all_dives(struct dive *dive, struct dive **prev_dive)
|
|||
}
|
||||
}
|
||||
|
||||
void process_selected_dives(GList *selected_dives, GtkTreeModel *model)
|
||||
/* make sure we skip the selected summary entries */
|
||||
void process_selected_dives(void)
|
||||
{
|
||||
struct dive *dp;
|
||||
unsigned int i;
|
||||
GtkTreeIter iter;
|
||||
GtkTreePath *path;
|
||||
struct dive *dive;
|
||||
unsigned int i, nr;
|
||||
|
||||
memset(&stats_selection, 0, sizeof(stats_selection));
|
||||
stats_selection.selection_size = amount_selected;
|
||||
|
||||
for (i = 0; i < amount_selected; ++i) {
|
||||
GValue value = {0, };
|
||||
path = g_list_nth_data(selected_dives, i);
|
||||
if (gtk_tree_model_get_iter(model, &iter, path)) {
|
||||
gtk_tree_model_get_value(model, &iter, 0, &value);
|
||||
dp = get_dive(g_value_get_int(&value));
|
||||
nr = 0;
|
||||
for_each_dive(i, dive) {
|
||||
if (dive->selected) {
|
||||
process_dive(dive, &stats_selection);
|
||||
nr++;
|
||||
}
|
||||
process_dive(dp, &stats_selection);
|
||||
}
|
||||
stats_selection.selection_size = nr;
|
||||
}
|
||||
|
||||
static void set_label(GtkWidget *w, const char *fmt, ...)
|
||||
|
@ -266,14 +267,11 @@ static void show_single_dive_stats(struct dive *dive)
|
|||
static void show_total_dive_stats(struct dive *dive)
|
||||
{
|
||||
double value;
|
||||
int decimals;
|
||||
int decimals, seconds;
|
||||
const char *unit;
|
||||
stats_t *stats_ptr;
|
||||
|
||||
if (amount_selected < 2)
|
||||
stats_ptr = &stats;
|
||||
else
|
||||
stats_ptr = &stats_selection;
|
||||
stats_ptr = &stats_selection;
|
||||
|
||||
set_label(stats_w.selection_size, "%d", stats_ptr->selection_size);
|
||||
if (stats_ptr->min_temp) {
|
||||
|
@ -287,7 +285,10 @@ static void show_total_dive_stats(struct dive *dive)
|
|||
set_label(stats_w.max_temp, "%.1f %s", value, unit);
|
||||
}
|
||||
set_label(stats_w.total_time, get_time_string(stats_ptr->total_time.seconds, 0));
|
||||
set_label(stats_w.avg_time, get_time_string(stats_ptr->total_time.seconds / stats_ptr->selection_size, 0));
|
||||
seconds = stats_ptr->total_time.seconds;
|
||||
if (stats_ptr->selection_size)
|
||||
seconds /= stats_ptr->selection_size;
|
||||
set_label(stats_w.avg_time, get_time_string(seconds, 0));
|
||||
set_label(stats_w.longest_time, get_time_string(stats_ptr->longest_time.seconds, 0));
|
||||
set_label(stats_w.shortest_time, get_time_string(stats_ptr->shortest_time.seconds, 0));
|
||||
value = get_depth_units(stats_ptr->max_depth.mm, &decimals, &unit);
|
||||
|
|
|
@ -64,6 +64,21 @@
|
|||
</buddy>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="Equipment/Suit != ''">
|
||||
<suit>
|
||||
<xsl:value-of select="Equipment/Suit"/>
|
||||
</suit>
|
||||
<xsl:value-of select="Equipment/Suit"/>
|
||||
</xsl:if>
|
||||
|
||||
<xsl:if test="Equipment/Weight != ''">
|
||||
<weightsystem>
|
||||
<xsl:attribute name="weight">
|
||||
<xsl:value-of select="Equipment/Weight"/>
|
||||
</xsl:attribute>
|
||||
</weightsystem>
|
||||
</xsl:if>
|
||||
|
||||
<notes>
|
||||
<xsl:if test="DiveActivity != ''">
|
||||
Diveactivity: <xsl:value-of select="DiveActivity"/>
|
||||
|
@ -73,15 +88,9 @@ Divetype: <xsl:value-of select="DiveType"/>
|
|||
</xsl:if>
|
||||
<xsl:if test="Equipment/Visibility != ''">
|
||||
Visibility: <xsl:value-of select="Equipment/Visibility"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="Equipment/Suit != ''">
|
||||
Suit: <xsl:value-of select="Equipment/Suit"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="Equipment/Gloves != ''">
|
||||
Gloves: <xsl:value-of select="Equipment/Gloves"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="Equipment/Weight != ''">
|
||||
Weight: <xsl:value-of select="Equipment/Weight"/>
|
||||
</xsl:if>
|
||||
<xsl:if test="Comment != ''">
|
||||
Comment: <xsl:value-of select="Comment"/>
|
||||
|
|
Loading…
Reference in a new issue