summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--display.h5
-rw-r--r--dive.h57
-rw-r--r--divelist.c179
-rw-r--r--dives/test21.xml9
-rw-r--r--dives/test22.xml9
-rw-r--r--dives/test23.xml9
-rw-r--r--equipment.c19
-rw-r--r--file.c7
-rw-r--r--gtk-gui.c73
-rw-r--r--info.c24
-rw-r--r--libdivecomputer.c54
-rw-r--r--libdivecomputer.h2
-rw-r--r--main.c6
-rw-r--r--parse-xml.c66
-rw-r--r--print.c321
-rw-r--r--profile.c8
-rw-r--r--save-xml.c53
-rw-r--r--statistics.c2
-rw-r--r--uemis.h2
19 files changed, 755 insertions, 150 deletions
diff --git a/display.h b/display.h
index 5f99849b7..4e1511656 100644
--- a/display.h
+++ b/display.h
@@ -26,6 +26,11 @@ extern void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_are
extern void init_profile_background(struct graphics_context *gc);
extern void attach_tooltip(int x, int y, int w, int h, const char *text);
+struct options {
+ enum { PRETTY, TABLE } type;
+ gboolean print_profiles;
+};
+
extern char zoomed_plot;
#endif
diff --git a/dive.h b/dive.h
index ab854e37e..dffe75325 100644
--- a/dive.h
+++ b/dive.h
@@ -95,6 +95,7 @@ typedef struct {
extern gboolean cylinder_none(void *_data);
extern gboolean no_cylinders(cylinder_t *cyl);
extern gboolean cylinders_equal(cylinder_t *cyl1, cylinder_t *cyl2);
+extern void copy_cylinders(cylinder_t *cyl1, cylinder_t *cyl2);
extern gboolean no_weightsystems(weightsystem_t *ws);
extern gboolean weightsystems_equal(weightsystem_t *ws1, weightsystem_t *ws2);
@@ -234,8 +235,12 @@ struct event {
#define W_IDX_PRIMARY 0
#define W_IDX_SECONDARY 1
+typedef enum { TF_NONE, NO_TRIP, IN_TRIP, NUM_TRIPFLAGS } tripflag_t;
+extern const char *tripflag_names[NUM_TRIPFLAGS];
+
struct dive {
int number;
+ tripflag_t tripflag;
int selected;
time_t when;
char *location;
@@ -256,6 +261,58 @@ struct dive {
struct sample sample[];
};
+extern GList *dive_trip_list;
+extern gboolean autogroup;
+/* random threashold: three days without diving -> new trip
+ * this works very well for people who usually dive as part of a trip and don't
+ * regularly dive at a local facility; this is why trips are an optional feature */
+#define TRIP_THRESHOLD 3600*24*3
+
+#define UNGROUPED_DIVE(_dive) ((_dive)->tripflag == NO_TRIP)
+#define DIVE_IN_TRIP(_dive) ((_dive)->tripflag == IN_TRIP)
+#define NEXT_TRIP(_entry, _list) ((_entry) ? g_list_next(_entry) : (_list))
+#define PREV_TRIP(_entry, _list) ((_entry) ? g_list_previous(_entry) : g_list_last(_list))
+#define DIVE_TRIP(_trip) ((struct dive *)(_trip)->data)
+#define DIVE_FITS_TRIP(_dive, _dive_trip) ((_dive_trip)->when - TRIP_THRESHOLD <= (_dive)->when)
+
+static inline int dive_date_cmp(gconstpointer _a, gconstpointer _b) {
+ return ((struct dive *)(_a))->when - ((struct dive *)(_b))->when;
+}
+
+#define FIND_TRIP(_trip, _list) g_list_find_custom((_list), (_trip), dive_date_cmp)
+
+#ifdef DEBUG_TRIP
+static void dump_trip_list(void)
+{
+ GList *p = NULL;
+ int i=0;
+ while ((p = NEXT_TRIP(p, dive_trip_list))) {
+ struct tm *tm = gmtime(&DIVE_TRIP(p)->when);
+ printf("trip %d to \"%s\" on %04u-%02u-%02u\n", ++i, DIVE_TRIP(p)->location,
+ tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday);
+ }
+ printf("-----\n");
+}
+#endif
+
+/* insert the trip into the list - but ensure you don't have two trips
+ * for the same date; but if you have, make sure you don't keep the
+ * one with less information */
+static inline GList *insert_trip(struct dive *_trip, GList *_list)
+{
+ GList *result = FIND_TRIP(_trip, _list);
+ if (result) {
+ if (! DIVE_TRIP(result)->location)
+ DIVE_TRIP(result)->location = _trip->location;
+ } else {
+ result = g_list_insert_sorted((_list), (_trip), dive_date_cmp);
+ }
+#ifdef DEBUG_TRIP
+ dump_trip_list();
+#endif
+ return result;
+}
+
/*
* We keep our internal data in well-specified units, but
* the input and output may come in some random format. This
diff --git a/divelist.c b/divelist.c
index 30bd2d8e9..a773b6017 100644
--- a/divelist.c
+++ b/divelist.c
@@ -31,6 +31,10 @@ struct DiveList {
};
static struct DiveList dive_list;
+GList *dive_trip_list;
+gboolean autogroup = FALSE;
+
+const char *tripflag_names[NUM_TRIPFLAGS] = { "TF_NONE", "NOTRIP", "INTRIP" };
/*
* The dive list has the dive data in both string format (for showing)
@@ -54,19 +58,22 @@ enum {
DIVELIST_COLUMNS
};
-/* magic numbers that indicate (as negative values) model entries that
- * are summary entries for a divetrip */
-#define NEW_TRIP 1
-
#ifdef DEBUG_MODEL
static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
char *location;
- int idx, nr, rating, depth;
+ int idx, nr, duration;
+ struct dive *dive;
+
+ gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1);
+ printf("entry #%d : nr %d duration %d location %s ", idx, nr, duration, location);
+ dive = get_dive(idx);
+ if (dive)
+ printf("tripflag %d\n", dive->tripflag);
+ else
+ printf("without matching dive\n");
- gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_RATING, &rating, DIVE_DEPTH, &depth, DIVE_LOCATION, &location, -1);
- printf("entry #%d : nr %d rating %d depth %d location %s \n", idx, nr, rating, depth, location);
free(location);
return FALSE;
@@ -327,16 +334,14 @@ static void date_data_func(GtkTreeViewColumn *col,
when = val;
tm = gmtime(&when);
- switch(idx) {
- case -NEW_TRIP:
+ if (idx < 0) {
snprintf(buffer, sizeof(buffer),
"Trip %s, %s %d, %d (%d dive%s)",
weekday(tm->tm_wday),
monthname(tm->tm_mon),
tm->tm_mday, tm->tm_year + 1900,
nr, nr > 1 ? "s" : "");
- break;
- default:
+ } else {
snprintf(buffer, sizeof(buffer),
"%s, %s %d, %d %02d:%02d",
weekday(tm->tm_wday),
@@ -877,75 +882,102 @@ void update_dive_list_col_visibility(void)
return;
}
-/* random heuristic - not diving in three days implies new dive trip */
-#define TRIP_THRESHOLD 3600*24*3
-static int new_group(struct dive *dive, struct dive **last_dive, time_t *tm_date)
-{
- if (!last_dive)
- return TRUE;
- if (*last_dive) {
- struct dive *ldive = *last_dive;
- if (abs(dive->when - ldive->when) < TRIP_THRESHOLD) {
- *last_dive = dive;
- return FALSE;
- }
- }
- *last_dive = dive;
- if (tm_date) {
- struct tm *tm1 = gmtime(&dive->when);
- tm1->tm_sec = 0;
- tm1->tm_min = 0;
- tm1->tm_hour = 0;
- *tm_date = mktime(tm1);
- }
- return TRUE;
-}
-
static void fill_dive_list(void)
{
- int i, group_size;
- GtkTreeIter iter, parent_iter;
+ int i;
+ GtkTreeIter iter, parent_iter, *parent_ptr = NULL;
GtkTreeStore *liststore, *treestore;
- struct dive *last_dive = NULL;
- struct dive *last_trip_dive = NULL;
- const char *last_location = NULL;
- time_t dive_date;
+ struct dive *last_trip = NULL;
+ GList *trip;
+ struct dive *dive_trip = NULL;
+
+ /* if we have pre-existing trips, start on the last one */
+ trip = g_list_last(dive_trip_list);
treestore = GTK_TREE_STORE(dive_list.treemodel);
liststore = GTK_TREE_STORE(dive_list.listmodel);
i = dive_table.nr;
while (--i >= 0) {
- struct dive *dive = dive_table.dives[i];
-
- if (new_group(dive, &last_dive, &dive_date))
- {
- /* make sure we display the first date of the trip in previous summary */
- if (last_trip_dive)
- gtk_tree_store_set(treestore, &parent_iter,
- DIVE_NR, group_size,
- DIVE_DATE, last_trip_dive->when,
- DIVE_LOCATION, last_location,
- -1);
-
- gtk_tree_store_append(treestore, &parent_iter, NULL);
- gtk_tree_store_set(treestore, &parent_iter,
- DIVE_INDEX, -NEW_TRIP,
- DIVE_NR, 1,
- DIVE_TEMPERATURE, 0,
- DIVE_SAC, 0,
+ struct dive *dive = get_dive(i);
+
+ /* make sure we display the first date of the trip in previous summary */
+ if (dive_trip && parent_ptr) {
+ gtk_tree_store_set(treestore, parent_ptr,
+ DIVE_NR, dive_trip->number,
+ DIVE_DATE, dive_trip->when,
+ DIVE_LOCATION, dive_trip->location,
-1);
-
- group_size = 0;
- /* This might be NULL */
- last_location = dive->location;
}
- group_size++;
- last_trip_dive = dive;
- if (dive->location)
- last_location = dive->location;
+ /* the dive_trip info might have been killed by a previous UNGROUPED dive */
+ if (trip)
+ dive_trip = DIVE_TRIP(trip);
+ /* tripflag defines how dives are handled;
+ * TF_NONE "not handled yet" - create time based group if autogroup == TRUE
+ * NO_TRIP "set as no group" - simply leave at top level
+ * IN_TRIP "use the trip with the largest trip time (when) that is <= this dive"
+ */
+ if (UNGROUPED_DIVE(dive)) {
+ /* first dives that go to the top level */
+ parent_ptr = NULL;
+ dive_trip = NULL;
+ } else if (autogroup && !DIVE_IN_TRIP(dive)) {
+ if ( ! dive_trip || ! DIVE_FITS_TRIP(dive, dive_trip)) {
+ /* allocate new trip - all fields default to 0
+ and get filled in further down */
+ dive_trip = alloc_dive();
+ dive_trip_list = insert_trip(dive_trip, dive_trip_list);
+ trip = FIND_TRIP(dive_trip, dive_trip_list);
+ }
+ } else { /* either the dive has a trip or we aren't creating trips */
+ if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) {
+ GList *last_trip = trip;
+ trip = PREV_TRIP(trip, dive_trip_list);
+ if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) {
+ /* we could get here if there are no trips in the XML file
+ * and we aren't creating trips, either.
+ * Otherwise we need to create a new trip */
+ if (autogroup) {
+ dive_trip = alloc_dive();
+ dive_trip_list = insert_trip(dive_trip, dive_trip_list);
+ trip = FIND_TRIP(dive_trip, dive_trip_list);
+ } else {
+ /* let's go back to the last valid trip */
+ trip = last_trip;
+ }
+ } else {
+ dive_trip = trip->data;
+ dive_trip->number = 0;
+ }
+ }
+ }
+ /* update dive_trip to include this dive, increase number of dives in
+ the trip and update location if necessary */
+ if (dive_trip) {
+ dive->tripflag = IN_TRIP;
+ dive_trip->number++;
+ dive_trip->when = dive->when;
+ if (!dive_trip->location && dive->location)
+ dive_trip->location = dive->location;
+ if (dive_trip != last_trip) {
+ last_trip = dive_trip;
+ /* create trip entry */
+ gtk_tree_store_append(treestore, &parent_iter, NULL);
+ parent_ptr = &parent_iter;
+ /* a duration of 0 (and negative index) identifies a group */
+ gtk_tree_store_set(treestore, parent_ptr,
+ DIVE_INDEX, -1,
+ DIVE_NR, dive_trip->number,
+ DIVE_DATE, dive_trip->when,
+ DIVE_LOCATION, dive_trip->location,
+ DIVE_DURATION, 0,
+ -1);
+ }
+ }
+
+ /* store dive */
update_cylinder_related_info(dive);
- gtk_tree_store_append(treestore, &iter, &parent_iter);
+ gtk_tree_store_append(treestore, &iter, parent_ptr);
gtk_tree_store_set(treestore, &iter,
DIVE_INDEX, i,
DIVE_NR, dive->number,
@@ -974,13 +1006,12 @@ static void fill_dive_list(void)
}
/* make sure we display the first date of the trip in previous summary */
- if (last_trip_dive)
- gtk_tree_store_set(treestore, &parent_iter,
- DIVE_NR, group_size,
- DIVE_DATE, last_trip_dive->when,
- DIVE_LOCATION, last_location,
+ if (parent_ptr && dive_trip)
+ gtk_tree_store_set(treestore, parent_ptr,
+ DIVE_NR, dive_trip->number,
+ DIVE_DATE, dive_trip->when,
+ DIVE_LOCATION, dive_trip->location,
-1);
-
update_dive_list_units();
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dive_list.model), &iter)) {
GtkTreeSelection *selection;
diff --git a/dives/test21.xml b/dives/test21.xml
new file mode 100644
index 000000000..5f5f6c981
--- /dev/null
+++ b/dives/test21.xml
@@ -0,0 +1,9 @@
+<dives>
+<program name='subsurface' version='1'></program>
+<trip date='2011-12-02' />
+<dive number='20' tripflag='INTRIP' date='2011-12-02' time='14:00:00' duration='30:00 min'>
+ <depth max='20.0 m' mean='15.0 m' />
+ <location>20th test dive - this should be in a trip with same location</location>
+ <notes>We are testing that the location of the dive is picked up in the trip if the trip has no location</notes>
+</dive>
+</dives>
diff --git a/dives/test22.xml b/dives/test22.xml
new file mode 100644
index 000000000..a61032327
--- /dev/null
+++ b/dives/test22.xml
@@ -0,0 +1,9 @@
+<dives>
+<program name='subsurface' version='1'></program>
+<trip date='2011-12-02' location='trip location' />
+<dive number='21' tripflag='INTRIP' date='2011-12-02' time='15:00:00' duration='30:00 min'>
+ <depth max='20.0 m' mean='15.0 m' />
+ <location>21st test dive - this should be in a trip with a trip location</location>
+ <notes>We are testing that the location of the dive is not picked up in the trip if the trip has a location</notes>
+</dive>
+</dives>
diff --git a/dives/test23.xml b/dives/test23.xml
new file mode 100644
index 000000000..c61ad2db9
--- /dev/null
+++ b/dives/test23.xml
@@ -0,0 +1,9 @@
+<dives>
+<program name='subsurface' version='1'></program>
+<trip date='2011-12-02' location='trip location' />
+<dive number='22' tripflag='NOTRIP' date='2011-12-09' time='6:00:00' duration='30:00 min'>
+ <depth max='20.0 m' mean='15.0 m' />
+ <location>22nd test dive - this should not be in a trip</location>
+ <notes>We are testing that the NOTRIP flag works</notes>
+</dive>
+</dives>
diff --git a/equipment.c b/equipment.c
index 43bb29d59..d676fc05d 100644
--- a/equipment.c
+++ b/equipment.c
@@ -461,13 +461,11 @@ gboolean description_equal(const char *desc1, const char *desc2)
}
/* when checking for the same cylinder we want the size and description to match
- but don't compare the start and end pressures */
+ but don't compare the start and end pressures, nor the Nitrox/He values */
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);
}
@@ -481,6 +479,21 @@ gboolean cylinders_equal(cylinder_t *cyl1, cylinder_t *cyl2)
return TRUE;
}
+/* copy size and description of all cylinders from cyl1 to cyl2 */
+void copy_cylinders(cylinder_t *cyl1, cylinder_t *cyl2)
+{
+ int i;
+
+ for (i = 0; i < MAX_CYLINDERS; i++) {
+ cyl2[i].type.size.mliter = cyl1[i].type.size.mliter;
+ cyl2[i].type.workingpressure.mbar = cyl1[i].type.workingpressure.mbar;
+ if (cyl1[i].type.description)
+ cyl2[i].type.description = strdup(cyl1[i].type.description);
+ else
+ cyl2[i].type.description = NULL;
+ }
+}
+
static gboolean weightsystem_none(void *_data)
{
weightsystem_t *ws = _data;
diff --git a/file.c b/file.c
index e0163909e..da498995c 100644
--- a/file.c
+++ b/file.c
@@ -8,6 +8,11 @@
#include "dive.h"
#include "file.h"
+/* Crazy windows sh*t */
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
static int readfile(const char *filename, struct memblock *mem)
{
int ret, fd;
@@ -17,7 +22,7 @@ static int readfile(const char *filename, struct memblock *mem)
mem->buffer = NULL;
mem->size = 0;
- fd = open(filename, O_RDONLY);
+ fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return fd;
ret = fstat(fd, &st);
diff --git a/gtk-gui.c b/gtk-gui.c
index 9bd4f131d..7db777ab9 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -98,7 +98,7 @@ void report_error(GError* error)
{
return;
}
-
+
if (error_info_bar == NULL)
{
error_count = 1;
@@ -108,11 +108,11 @@ void report_error(GError* error)
g_signal_connect(error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL);
gtk_info_bar_set_message_type(GTK_INFO_BAR(error_info_bar),
GTK_MESSAGE_ERROR);
-
+
error_label = gtk_label_new(error->message);
GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(error_info_bar));
gtk_container_add(GTK_CONTAINER(container), error_label);
-
+
gtk_box_pack_start(GTK_BOX(main_vbox), error_info_bar, FALSE, FALSE, 0);
gtk_widget_show_all(main_vbox);
}
@@ -151,7 +151,7 @@ static void file_open(GtkWidget *w, gpointer data)
GSList *filenames, *fn_glist;
char *filename;
filenames = fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
-
+
GError *error = NULL;
while(filenames != NULL) {
filename = filenames->data;
@@ -162,7 +162,7 @@ static void file_open(GtkWidget *w, gpointer data)
g_error_free(error);
error = NULL;
}
-
+
g_free(filename);
filenames = g_slist_next(filenames);
}
@@ -172,10 +172,43 @@ static void file_open(GtkWidget *w, gpointer data)
gtk_widget_destroy(dialog);
}
+/* return the path and the file component contained in the full path */
+static char *path_and_file(char *pathin, char **fileout) {
+ char *slash = pathin, *next;
+ char *result;
+ size_t len, n;
+
+ if (! pathin) {
+ *fileout = strdup("");
+ return strdup("");
+ }
+ while ((next = strpbrk(slash + 1, "\\/")))
+ slash = next;
+ if (pathin != slash)
+ slash++;
+ *fileout = strdup(slash);
+
+ /* strndup(pathin, slash - pathin) */
+ n = slash - pathin;
+ len = strlen(pathin);
+ if (n < len)
+ len = n;
+
+ result = (char *)malloc(len + 1);
+ if (!result)
+ return 0;
+
+ result[len] = '\0';
+ return (char *)memcpy(result, pathin, len);
+}
+
static void file_save_as(GtkWidget *w, gpointer data)
{
GtkWidget *dialog;
char *filename = NULL;
+ char *current_file;
+ char *current_dir;
+
dialog = gtk_file_chooser_dialog_new("Save File As",
GTK_WINDOW(main_window),
GTK_FILE_CHOOSER_ACTION_SAVE,
@@ -184,7 +217,13 @@ static void file_save_as(GtkWidget *w, gpointer data)
NULL);
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE);
- gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), existing_filename);
+ current_dir = path_and_file(existing_filename, &current_file);
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), current_dir);
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), current_file);
+
+ free(current_dir);
+ free(current_file);
+
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
}
@@ -223,7 +262,7 @@ static gboolean ask_save_changes()
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)));
+ char *label_text = (char*) malloc(sizeof(char) * (93 + 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);
@@ -389,6 +428,7 @@ OPTIONCALLBACK(temperature_toggle, visible_cols.temperature)
OPTIONCALLBACK(totalweight_toggle, visible_cols.totalweight)
OPTIONCALLBACK(suit_toggle, visible_cols.suit)
OPTIONCALLBACK(cylinder_toggle, visible_cols.cylinder)
+OPTIONCALLBACK(autogroup_toggle, autogroup)
static void event_toggle(GtkWidget *w, gpointer _data)
{
@@ -484,8 +524,22 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(suit_toggle), NULL);
+ frame = gtk_frame_new("Divelist Font");
+ gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), frame, FALSE, FALSE, 5);
+
font = gtk_font_button_new_with_font(divelist_font);
- gtk_box_pack_start(GTK_BOX(vbox), font, FALSE, FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(frame),font);
+
+ frame = gtk_frame_new("Misc. Options");
+ 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("Automatically group dives in trips");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), autogroup);
+ gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6);
+ g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(autogroup_toggle), NULL);
gtk_widget_show_all(dialog);
result = gtk_dialog_run(GTK_DIALOG(dialog));
@@ -514,6 +568,7 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
subsurface_set_conf("SAC", PREF_BOOL, BOOL_TO_PTR(visible_cols.sac));
subsurface_set_conf("OTU", PREF_BOOL, BOOL_TO_PTR(visible_cols.otu));
subsurface_set_conf("divelist_font", PREF_STRING, divelist_font);
+ subsurface_set_conf("autogroup", PREF_BOOL, BOOL_TO_PTR(autogroup));
/* Flush the changes out to the system */
subsurface_flush_conf();
@@ -803,6 +858,8 @@ void init_ui(int *argcp, char ***argvp)
divelist_font = subsurface_get_conf("divelist_font", PREF_STRING);
+ autogroup = PTR_TO_BOOL(subsurface_get_conf("autogroup", PREF_BOOL));
+
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);
diff --git a/info.c b/info.c
index 8db606344..d9379ac68 100644
--- a/info.c
+++ b/info.c
@@ -1,7 +1,7 @@
/* info.c */
-/* creates the UI for the info frame -
+/* creates the UI for the info frame -
* controlled through the following interfaces:
- *
+ *
* void show_dive_info(struct dive *dive)
*
* called from gtk-ui:
@@ -482,7 +482,7 @@ void update_equipment_data(struct dive *dive, struct dive *master)
if ( ! cylinders_equal(remember_cyl, master->cylinder) &&
(no_cylinders(dive->cylinder) ||
cylinders_equal(dive->cylinder, remember_cyl)))
- memcpy(dive->cylinder, master->cylinder, CYL_BYTES);
+ copy_cylinders(master->cylinder, dive->cylinder);
if (! weightsystems_equal(remember_ws, master->weightsystem) &&
(no_weightsystems(dive->weightsystem) ||
weightsystems_equal(dive->weightsystem, remember_ws)))
@@ -496,6 +496,7 @@ int edit_multi_dive_info(struct dive *single_dive)
GtkWidget *dialog, *vbox;
struct dive_info info;
struct dive *master;
+ gboolean multi;
dialog = gtk_dialog_new_with_buttons("Dive Info",
GTK_WINDOW(main_window),
@@ -508,7 +509,22 @@ int edit_multi_dive_info(struct dive *single_dive)
master = single_dive;
if (!master)
master = current_dive;
- dive_info_widget(vbox, master, &info, !single_dive);
+
+ /* See if we should use multi dive mode */
+ multi = FALSE;
+ if (!single_dive) {
+ int i;
+ struct dive *dive;
+
+ for_each_dive(i, dive) {
+ if (dive != master && dive->selected) {
+ multi = TRUE;
+ break;
+ }
+ }
+ }
+
+ dive_info_widget(vbox, master, &info, multi);
show_dive_equipment(master, W_IDX_SECONDARY);
save_equipment_data(master);
gtk_widget_show_all(dialog);
diff --git a/libdivecomputer.c b/libdivecomputer.c
index e362d1d2b..d96d2769f 100644
--- a/libdivecomputer.c
+++ b/libdivecomputer.c
@@ -305,13 +305,6 @@ static dc_status_t import_device_data(dc_device_t *device, device_data_t *device
return dc_device_foreach(device, dive_cb, devicedata);
}
-static dc_status_t device_open(const char *devname,
- dc_descriptor_t *descriptor,
- dc_device_t **device)
-{
- return dc_device_open(device, descriptor, devname);
-}
-
static void event_cb(dc_device_t *device, dc_event_type_t event, const void *data, void *userdata)
{
@@ -351,42 +344,53 @@ cancel_cb(void *userdata)
return import_thread_cancelled;
}
-static const char *do_libdivecomputer_import(device_data_t *data)
+static const char *do_device_import(device_data_t *data)
{
- dc_device_t *device = NULL;
dc_status_t rc;
-
- import_dive_number = 0;
- rc = device_open(data->devname, data->descriptor, &device);
- if (rc != DC_STATUS_SUCCESS)
- return "Unable to open %s %s (%s)";
- data->device = device;
+ dc_device_t *device = data->device;
// Register the event handler.
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);
+ if (rc != DC_STATUS_SUCCESS)
return "Error registering the event handler.";
- }
// Register the cancellation handler.
rc = dc_device_set_cancel(device, cancel_cb, data);
- if (rc != DC_STATUS_SUCCESS) {
- dc_device_close(device);
+ if (rc != DC_STATUS_SUCCESS)
return "Error registering the cancellation handler.";
- }
rc = import_device_data(device, data);
- if (rc != DC_STATUS_SUCCESS) {
- dc_device_close(device);
+ if (rc != DC_STATUS_SUCCESS)
return "Dive data import error";
- }
- dc_device_close(device);
+ /* All good */
return NULL;
}
+static const char *do_libdivecomputer_import(device_data_t *data)
+{
+ dc_status_t rc;
+ const char *err;
+
+ import_dive_number = 0;
+ data->device = NULL;
+ data->context = NULL;
+
+ rc = dc_context_new(&data->context);
+ if (rc != DC_STATUS_SUCCESS)
+ return "Unable to create libdivecomputer context";
+
+ err = "Unable to open %s %s (%s)";
+ rc = dc_device_open(&data->device, data->context, data->descriptor, data->devname);
+ if (rc == DC_STATUS_SUCCESS) {
+ err = do_device_import(data);
+ dc_device_close(data->device);
+ }
+ dc_context_free(data->context);
+ return err;
+}
+
static void *pthread_wrapper(void *_data)
{
device_data_t *data = _data;
diff --git a/libdivecomputer.h b/libdivecomputer.h
index 8d77a25be..6430c8448 100644
--- a/libdivecomputer.h
+++ b/libdivecomputer.h
@@ -4,7 +4,6 @@
/* libdivecomputer */
#include <libdivecomputer/device.h>
#include <libdivecomputer/parser.h>
-#include <libdivecomputer/utils.h>
/* handling uemis Zurich SDA files */
#include "uemis.h"
@@ -15,6 +14,7 @@ typedef struct device_data_t {
dc_descriptor_t *descriptor;
const char *vendor, *product, *devname;
dc_device_t *device;
+ dc_context_t *context;
progressbar_t progress;
int preexisting;
} device_data_t;
diff --git a/main.c b/main.c
index 8e579f88c..2489473b9 100644
--- a/main.c
+++ b/main.c
@@ -172,7 +172,7 @@ static void parse_argument(const char *arg)
if (strncmp(arg, "-psn_", 5) == 0) {
return;
}
- /* fallthrough */
+ /* fallthrough */
default:
fprintf(stderr, "Bad argument '%s'\n", arg);
exit(1);
@@ -217,7 +217,7 @@ int main(int argc, char **argv)
parse_xml_init();
init_ui(&argc, &argv);
-
+
for (i = 1; i < argc; i++) {
const char *a = argv[i];
@@ -227,7 +227,7 @@ int main(int argc, char **argv)
}
GError *error = NULL;
parse_file(a, &error);
-
+
if (error != NULL)
{
report_error(error);
diff --git a/parse-xml.c b/parse-xml.c
index 173314dd4..5159a334f 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -39,6 +39,11 @@ void record_dive(struct dive *dive)
dive_table.nr = nr+1;
}
+void record_trip(struct dive *trip)
+{
+ dive_trip_list = insert_trip(trip, dive_trip_list);
+}
+
static void delete_dive_renumber(struct dive **dives, int i, int nr)
{
struct dive *dive = dives[i];
@@ -156,7 +161,7 @@ const struct units IMPERIAL_units = {
/*
* Dive info as it is being built up..
*/
-static struct dive *cur_dive;
+static struct dive *cur_dive, *cur_trip = NULL;
static struct sample *cur_sample;
static struct {
int active;
@@ -535,6 +540,17 @@ static void get_index(char *buffer, void *_i)
free(buffer);
}
+static void get_tripflag(char *buffer, void *_tf)
+{
+ tripflag_t *tf = _tf;
+ tripflag_t i;
+
+ *tf = TF_NONE;
+ for (i = NO_TRIP; i < NUM_TRIPFLAGS; i++)
+ if(! strcmp(buffer, tripflag_names[i]))
+ *tf = i;
+}
+
static void centibar(char *buffer, void *_pressure)
{
pressure_t *pressure = _pressure;
@@ -1062,6 +1078,8 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf)
if (MATCH(".number", get_index, &dive->number))
return;
+ if (MATCH(".tripflag", get_tripflag, &dive->tripflag))
+ return;
if (MATCH(".date", divedate, &dive->when))
return;
if (MATCH(".time", divetime, &dive->when))
@@ -1138,6 +1156,27 @@ static void try_to_fill_dive(struct dive **divep, const char *name, char *buf)
nonmatch("dive", name, buf);
}
+/* We're in the top-level trip xml. Try to convert whatever value to a trip value */
+static void try_to_fill_trip(struct dive **divep, const char *name, char *buf)
+{
+ int len = strlen(name);
+
+ start_match("trip", name, buf);
+
+ struct dive *dive = *divep;
+
+ if (MATCH(".date", divedate, &dive->when)) {
+ dive->when = utc_mktime(&cur_tm);
+ return;
+ }
+ if (MATCH(".location", utf8_string, &dive->location))
+ return;
+ if (MATCH(".notes", utf8_string, &dive->notes))
+ return;
+
+ nonmatch("trip", name, buf);
+}
+
/*
* File boundaries are dive boundaries. But sometimes there are
* multiple dives per file, so there can be other events too that
@@ -1162,6 +1201,22 @@ static void dive_end(void)
cur_ws_index = 0;
}
+static void trip_start(void)
+{
+ if (cur_trip)
+ return;
+ cur_trip = alloc_dive();
+ memset(&cur_tm, 0, sizeof(cur_tm));
+}
+
+static void trip_end(void)
+{
+ if (!cur_trip)
+ return;
+ record_trip(cur_trip);
+ cur_trip = NULL;
+}
+
static void event_start(void)
{
memset(&cur_event, 0, sizeof(cur_event));
@@ -1225,6 +1280,10 @@ static void entry(const char *name, int size, const char *raw)
try_to_fill_sample(cur_sample, name, buf);
return;
}
+ if (cur_trip) {
+ try_to_fill_trip(&cur_trip, name, buf);
+ return;
+ }
if (cur_dive) {
try_to_fill_dive(&cur_dive, name, buf);
return;
@@ -1350,6 +1409,7 @@ static struct nesting {
} nesting[] = {
{ "dive", dive_start, dive_end },
{ "Dive", dive_start, dive_end },
+ { "trip", trip_start, trip_end },
{ "sample", sample_start, sample_end },
{ "waypoint", sample_start, sample_end },
{ "SAMPLE", sample_start, sample_end },
@@ -1420,8 +1480,8 @@ void parse_xml_buffer(const char *url, const char *buffer, int size, GError **er
}
return;
}
- /* we assume that the last (or only) filename passed as argument is a
- * great filename to use as default when saving the dives */
+ /* we assume that the last (or only) filename passed as argument is a
+ * great filename to use as default when saving the dives */
set_filename(url);
reset_all();
dive_start();
diff --git a/print.c b/print.c
index 0bd3110a7..5a1a784b2 100644
--- a/print.c
+++ b/print.c
@@ -11,7 +11,19 @@
#define FONT_SMALL (FONT_NORMAL / 1.2)
#define FONT_LARGE (FONT_NORMAL * 1.2)
-static void set_font(PangoLayout *layout, PangoFontDescription *font, double size, int align)
+static struct options print_options;
+
+#define PRETTYOPTIONCALLBACK(name, option) \
+static void name(GtkWidget *w, gpointer data) \
+{ \
+ option = GTK_TOGGLE_BUTTON(w)->active; \
+}
+
+PRETTYOPTIONCALLBACK(print_profiles_toggle, print_options.print_profiles)
+
+
+static void set_font(PangoLayout *layout, PangoFontDescription *font,
+ double size, int align)
{
pango_font_description_set_size(font, size * PANGO_SCALE);
pango_layout_set_font_description(layout, font);
@@ -24,7 +36,8 @@ static void set_font(PangoLayout *layout, PangoFontDescription *font, double siz
* You know what? Maybe somebody can do a real Pango layout thing.
* This is hacky.
*/
-static void show_dive_text(struct dive *dive, cairo_t *cr, double w, double h, PangoFontDescription *font)
+static void show_dive_text(struct dive *dive, cairo_t *cr, double w,
+ double h, PangoFontDescription *font)
{
double depth;
const char *unit;
@@ -125,7 +138,103 @@ static void show_dive_text(struct dive *dive, cairo_t *cr, double w, double h, P
g_object_unref(layout);
}
-static void show_dive_profile(struct dive *dive, cairo_t *cr, double w, double h)
+static void show_table_header(cairo_t *cr, double w, double h,
+ PangoFontDescription *font)
+{
+ int len, width, height, maxwidth, maxheight;
+ PangoLayout *layout;
+ char buffer[160];
+
+ maxwidth = w * PANGO_SCALE;
+ maxheight = h * PANGO_SCALE * 0.9;
+
+ layout = pango_cairo_create_layout(cr);
+ pango_layout_set_width(layout, maxwidth);
+ pango_layout_set_height(layout, maxheight);
+
+ len = snprintf(buffer, sizeof(buffer),
+ "Dive# - Date - Depth - Time - Master"
+ " Buddy -- Location");
+
+ set_font(layout, font, FONT_LARGE, PANGO_ALIGN_LEFT);
+ pango_layout_set_text(layout, buffer, len);
+ pango_layout_get_size(layout, &width, &height);
+
+ //cairo_move_to(cr, 0, 0);
+ pango_cairo_show_layout(cr, layout);
+}
+
+static void show_dive_table(struct dive *dive, cairo_t *cr, double w,
+ double h, PangoFontDescription *font)
+{
+ double depth;
+ const char *unit;
+ int len, decimals, width, height, maxwidth, maxheight;
+ PangoLayout *layout;
+ struct tm *tm;
+ char buffer[160], divenr[20];
+
+ maxwidth = w * PANGO_SCALE;
+ maxheight = h * PANGO_SCALE * 0.9;
+
+ layout = pango_cairo_create_layout(cr);
+ pango_layout_set_width(layout, maxwidth);
+ pango_layout_set_height(layout, maxheight);
+
+ *divenr = 0;
+ if (dive->number)
+ snprintf(divenr, sizeof(divenr), "#%d -", dive->number);
+
+ depth = get_depth_units(dive->maxdepth.mm, &decimals, &unit);
+
+ tm = gmtime(&dive->when);
+ len = snprintf(buffer, sizeof(buffer),
+ "%s %s, %s %d, %d %dh%02d - %.*f %s - %d min - %s %s -- %s",
+ divenr,
+ weekday(tm->tm_wday),
+ monthname(tm->tm_mon),
+ tm->tm_mday, tm->tm_year + 1900,
+ tm->tm_hour, tm->tm_min,
+ decimals,
+ depth,
+ unit,
+ (dive->duration.seconds+59) / 60,
+ dive->divemaster ? : " ",
+ dive->buddy ? : " ",
+ dive->location ? : " "
+ );
+
+ set_font(layout, font, FONT_NORMAL, PANGO_ALIGN_LEFT);
+ pango_layout_set_text(layout, buffer, len);
+ pango_layout_get_size(layout, &width, &height);
+
+ cairo_move_to(cr, 0, 0);
+ pango_cairo_show_layout(cr, layout);
+
+ ///*
+ //* Show the dive notes
+ //*/
+ if (dive->notes) {
+ /* Move down by the size of the location (x2) */
+ height = height * 1.3;
+ cairo_translate(cr, 20, height / (double) PANGO_SCALE);
+ maxheight -= height;
+
+ /* Use the full width and remaining height for notes */
+ pango_layout_set_height(layout, maxheight);
+ pango_layout_set_width(layout, maxwidth);
+ pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR);
+ pango_layout_set_justify(layout, 1);
+ pango_layout_set_text(layout, dive->notes, -1);
+
+ cairo_move_to(cr, 0, 0);
+ pango_cairo_show_layout(cr, layout);
+ }
+ g_object_unref(layout);
+}
+
+static void show_dive_profile(struct dive *dive, cairo_t *cr, double w,
+ double h)
{
cairo_rectangle_int_t drawing_area = { w/20.0, h/20.0, w, h};
struct graphics_context gc = {
@@ -137,7 +246,8 @@ static void show_dive_profile(struct dive *dive, cairo_t *cr, double w, double h
cairo_restore(cr);
}
-static void print(int divenr, cairo_t *cr, double x, double y, double w, double h, PangoFontDescription *font)
+static void print(int divenr, cairo_t *cr, double x, double y, double w,
+ double h, PangoFontDescription *font)
{
struct dive *dive;
@@ -165,6 +275,70 @@ static void print(int divenr, cairo_t *cr, double x, double y, double w, double
cairo_restore(cr);
}
+static void print_pretty_table(int divenr, cairo_t *cr, double x, double y,
+ double w, double h, PangoFontDescription *font)
+{
+ struct dive *dive;
+
+ dive = get_dive(divenr);
+ if (!dive)
+ return;
+ cairo_save(cr);
+ cairo_translate(cr, x, y);
+
+ /* Plus 5% on all sides */
+ cairo_translate(cr, w/20, h/20);
+ w *= 0.9; h *= 0.9;
+
+ /* We actually want to scale the text and the lines now */
+ cairo_scale(cr, 0.5, 0.5);
+
+ show_dive_text(dive, cr, w*2, h*2, font);
+
+ cairo_restore(cr);
+}
+
+static void print_table_header(cairo_t *cr, double x, double y,
+ double w, double h, PangoFontDescription *font)
+{
+ cairo_save(cr);
+ cairo_translate(cr, x, y);
+
+ /* Plus 5% on all sides */
+ cairo_translate(cr, w/20, h/20);
+ w *= 0.9; h *= 0.9;
+
+ /* We actually want to scale the text and the lines now */
+ cairo_scale(cr, 0.5, 0.5);
+
+ show_table_header(cr, w*2, h*2, font);
+
+ cairo_restore(cr);
+}
+
+static void print_table(int divenr, cairo_t *cr, double x, double y,
+ double w, double h, PangoFontDescription *font)
+{
+ struct dive *dive;
+
+ dive = get_dive(divenr);
+ if (!dive)
+ return;
+ cairo_save(cr);
+ cairo_translate(cr, x, y);
+
+ /* Plus 5% on all sides */
+ cairo_translate(cr, w/20, h/20);
+ w *= 0.9; h *= 0.9;
+
+ /* We actually want to scale the text and the lines now */
+ cairo_scale(cr, 0.5, 0.5);
+
+ show_dive_table(dive, cr, w*2, h*2, font);
+
+ cairo_restore(cr);
+}
+
static void draw_page(GtkPrintOperation *operation,
GtkPrintContext *context,
gint page_nr,
@@ -192,44 +366,169 @@ static void draw_page(GtkPrintOperation *operation,
pango_font_description_free(font);
}
+static void draw_pretty_table(GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gint page_nr,
+ gpointer user_data)
+{
+ int nr;
+ cairo_t *cr;
+ double w, h;
+ PangoFontDescription *font;
+
+ cr = gtk_print_context_get_cairo_context(context);
+ font = pango_font_description_from_string("Sans");
+
+ w = gtk_print_context_get_width(context);
+ h = gtk_print_context_get_height(context)/15;
+
+ nr = page_nr*15;
+ int i;
+ for (i = 0; i < 15; i++) {
+ print_pretty_table(nr+i, cr, 0, 0+h*i, w, h, font);
+ }
+
+ pango_font_description_free(font);
+}
+
+static void draw_table(GtkPrintOperation *operation,
+ GtkPrintContext *context,
+ gint page_nr,
+ gpointer user_data)
+{
+ int nr;
+ int n_dive_per_page = 25;
+ cairo_t *cr;
+ double w, h;
+ PangoFontDescription *font;
+
+ cr = gtk_print_context_get_cairo_context(context);
+ font = pango_font_description_from_string("Sans");
+
+ w = gtk_print_context_get_width(context);
+ h = gtk_print_context_get_height(context)/(n_dive_per_page+1);
+
+ nr = page_nr*n_dive_per_page;
+ print_table_header(cr, 0, 0+h, w, h, font);
+ int i;
+ for (i = 0; i < n_dive_per_page; i++) {
+ print_table(nr+i, cr, 0, h*1.5+h*i, w, h, font);
+ }
+
+ pango_font_description_free(font);
+}
+
static void begin_print(GtkPrintOperation *operation, gpointer user_data)
{
+ int dives_per_page = 1;
+ if (print_options.type == PRETTY) {
+ if (print_options.print_profiles){
+ dives_per_page = 6;
+ } else {
+ dives_per_page = 15;
+ }
+ } else {
+ dives_per_page = 25;
+ }
+ int pages;
+ pages = (dive_table.nr + dives_per_page - 1) / dives_per_page;
+ gtk_print_operation_set_n_pages(operation, pages);
}
+static void update_print_window(GtkWidget *w) {
+ if (print_options.type == TABLE) {
+ // type == table - disable the profile option
+ gtk_widget_set_sensitive(w, FALSE);
+ } else {
+ // type == pretty - enable the profile option
+ gtk_widget_set_sensitive(w, TRUE);
+ }
+}
+
+#define OPTIONCALLBACK(name, type, value) \
+static void name(GtkWidget *w, gpointer data) \
+{\
+ if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) \
+ print_options.type = value; \
+ update_print_window(data); \
+}
+
+OPTIONCALLBACK(set_pretty, type, PRETTY)
+OPTIONCALLBACK(set_table, type, TABLE)
+
static GtkWidget *print_dialog(GtkPrintOperation *operation, gpointer user_data)
{
- GtkWidget *vbox, *hbox, *label;
+ GtkWidget *vbox, *button, *radio1, *radio2, *frame, *box;
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);
+
+ frame = gtk_frame_new("Print type");
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 1);
+
+ box = gtk_hbox_new(FALSE, 2);
+ gtk_container_add(GTK_CONTAINER(frame), box);
+
+ radio1 = gtk_radio_button_new_with_label (NULL, "Pretty print");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio1),
+ print_options.type == PRETTY);
+ radio2 = gtk_radio_button_new_with_label_from_widget (
+ GTK_RADIO_BUTTON (radio1), "Table print");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio2),
+ print_options.type == TABLE);
+ gtk_box_pack_start (GTK_BOX (box), radio1, TRUE, TRUE, 0);
+ gtk_box_pack_start (GTK_BOX (box), radio2, TRUE, TRUE, 0);
+
+
+ frame = gtk_frame_new("Print options");
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, FALSE, 1);
+
+ box = gtk_hbox_new(FALSE, 3);
+ gtk_container_add(GTK_CONTAINER(frame), box);
+
+ button = gtk_check_button_new_with_label("Show profiles");
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), print_options.print_profiles);
+ gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 2);
+ g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(print_profiles_toggle), NULL);
+
+ g_signal_connect(radio1, "toggled", G_CALLBACK(set_pretty), button);
+ g_signal_connect(radio2, "toggled", G_CALLBACK(set_table), button);
+
gtk_widget_show_all(vbox);
return vbox;
}
static void print_dialog_apply(GtkPrintOperation *operation, GtkWidget *widget, gpointer user_data)
{
+ if (print_options.type == PRETTY) {
+ if (print_options.print_profiles){
+ g_signal_connect(operation, "draw_page",
+ G_CALLBACK(draw_page), NULL);
+ } else {
+ g_signal_connect(operation, "draw_page",
+ G_CALLBACK(draw_pretty_table), NULL);
+ }
+ } else {
+ g_signal_connect(operation, "draw_page",
+ G_CALLBACK(draw_table), NULL);
+ }
}
static GtkPrintSettings *settings = NULL;
void do_print(void)
{
- int pages;
GtkPrintOperation *print;
GtkPrintOperationResult res;
repaint_dive();
print = gtk_print_operation_new();
+ gtk_print_operation_set_unit(print, GTK_UNIT_POINTS);
if (settings != NULL)
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,
GTK_WINDOW(main_window), NULL);
if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
diff --git a/profile.c b/profile.c
index 3ad11c0d0..d4e88c02c 100644
--- a/profile.c
+++ b/profile.c
@@ -1,5 +1,5 @@
/* profile.c */
-/* creates all the necessary data for drawing the dive profile
+/* creates all the necessary data for drawing the dive profile
* uses cairo to draw it
*/
#include <stdio.h>
@@ -899,7 +899,7 @@ static velocity_t velocity(int speed)
else if (speed < -25) /* -5ft/min */
v = SLOW;
else if (speed < 25) /* very hard to find data, but it appears that the recommendations
- for descent are usually about 2x ascent rate; still, we want
+ for descent are usually about 2x ascent rate; still, we want
stable to mean stable */
v = STABLE;
else if (speed < 152) /* between 5 and 30ft/min is considered slow */
@@ -955,7 +955,7 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi)
int past = -2;
while (i+past > 0 && entry[0].sec - entry[past].sec < 15)
past--;
- entry->velocity = velocity((entry[0].depth - entry[past].depth) /
+ entry->velocity = velocity((entry[0].depth - entry[past].depth) /
(entry[0].sec - entry[past].sec));
}
} else
@@ -967,7 +967,7 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi)
struct plot_data *entry = pi->entry +i;
analyze_plot_info_minmax(entry, pi->entry, pi->entry+nr);
}
-
+
return pi;
}
diff --git a/save-xml.c b/save-xml.c
index 37d6d062e..b797475e5 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -67,10 +67,9 @@ static void show_pressure(FILE *f, pressure_t pressure, const char *pre, const c
* characters, but at least libxml2 doesn't like them. It doesn't even
* allow them quoted. So we just skip them and replace them with '?'.
*
- * Nothing else (and if we ever do this using attributes, we'd need to
- * quote the quotes we use too).
+ * If we do this for attributes, we need to quote the quotes we use too.
*/
-static void quote(FILE *f, const char *text)
+static void quote(FILE *f, const char *text, int is_attribute)
{
const char *p = text;
@@ -97,6 +96,16 @@ static void quote(FILE *f, const char *text)
case '&':
escape = "&amp;";
break;
+ case '\'':
+ if (!is_attribute)
+ continue;
+ escape = "&apos;";
+ break;
+ case '\"':
+ if (!is_attribute)
+ continue;
+ escape = "&quot;";
+ break;
}
fwrite(text, (p - text - 1), 1, f);
if (!escape)
@@ -106,7 +115,7 @@ static void quote(FILE *f, const char *text)
}
}
-static void show_utf8(FILE *f, const char *text, const char *pre, const char *post)
+static void show_utf8(FILE *f, const char *text, const char *pre, const char *post, int is_attribute)
{
int len;
@@ -121,7 +130,7 @@ static void show_utf8(FILE *f, const char *text, const char *pre, const char *po
len--;
/* FIXME! Quoting! */
fputs(pre, f);
- quote(f, text);
+ quote(f, text, is_attribute);
fputs(post, f);
}
@@ -171,7 +180,7 @@ static void show_location(FILE *f, struct dive *dive)
}
prefix = buffer;
}
- show_utf8(f, dive->location, prefix,"</location>\n");
+ show_utf8(f, dive->location, prefix,"</location>\n", 0);
}
static void save_overview(FILE *f, struct dive *dive)
@@ -180,10 +189,10 @@ static void save_overview(FILE *f, struct dive *dive)
save_temperatures(f, dive);
show_duration(f, dive->surfacetime, " <surfacetime>", "</surfacetime>\n");
show_location(f, 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");
+ show_utf8(f, dive->divemaster, " <divemaster>","</divemaster>\n", 0);
+ show_utf8(f, dive->buddy, " <buddy>","</buddy>\n", 0);
+ show_utf8(f, dive->notes, " <notes>","</notes>\n", 0);
+ show_utf8(f, dive->suit, " <suit>","</suit>\n", 0);
}
static void save_cylinder_info(FILE *f, struct dive *dive)
@@ -262,7 +271,7 @@ static void save_one_event(FILE *f, struct event *ev)
show_index(f, ev->type, "type='", "'");
show_index(f, ev->flags, "flags='", "'");
show_index(f, ev->value, "value='", "'");
- show_utf8(f, ev->name, " name='", "'");
+ show_utf8(f, ev->name, " name='", "'", 1);
fprintf(f, " />\n");
}
@@ -275,6 +284,18 @@ static void save_events(FILE *f, struct event *ev)
}
}
+static void save_trip(FILE *f, struct dive *trip)
+{
+ struct tm *tm = gmtime(&trip->when);
+
+ fprintf(f, "<trip");
+ fprintf(f, " date='%04u-%02u-%02u'",
+ tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
+ if (trip->location)
+ show_utf8(f, trip->location, " location=\'","\'", 1);
+ fprintf(f, " />\n");
+}
+
static void save_dive(FILE *f, struct dive *dive)
{
int i;
@@ -283,6 +304,8 @@ static void save_dive(FILE *f, struct dive *dive)
fputs("<dive", f);
if (dive->number)
fprintf(f, " number='%d'", dive->number);
+ if (dive->tripflag != TF_NONE)
+ fprintf(f, " tripflag='%s'", tripflag_names[dive->tripflag]);
if (dive->rating)
fprintf(f, " rating='%d'", dive->rating);
fprintf(f, " date='%04u-%02u-%02u'",
@@ -305,6 +328,8 @@ static void save_dive(FILE *f, struct dive *dive)
void save_dives(const char *filename)
{
int i;
+ GList *trip = NULL;
+
FILE *f = fopen(filename, "w");
if (!f)
@@ -314,6 +339,12 @@ void save_dives(const char *filename)
update_dive(current_dive);
fprintf(f, "<dives>\n<program name='subsurface' version='%d'></program>\n", VERSION);
+
+ /* save the trips */
+ while ((trip = NEXT_TRIP(trip, dive_trip_list)) != 0)
+ save_trip(f, trip->data);
+
+ /* save the dives */
for (i = 0; i < dive_table.nr; i++)
save_dive(f, get_dive(i));
fprintf(f, "</dives>\n");
diff --git a/statistics.c b/statistics.c
index b9d2c3b95..a53617337 100644
--- a/statistics.c
+++ b/statistics.c
@@ -211,7 +211,7 @@ static void show_single_dive_stats(struct dive *dive)
set_label(single_w.date, buf);
set_label(single_w.dive_time, "%d min", (dive->duration.seconds + 30) / 60);
if (prev_dive)
- set_label(single_w.surf_intv,
+ set_label(single_w.surf_intv,
get_time_string(dive->when - (prev_dive->when + prev_dive->duration.seconds), 4));
else
set_label(single_w.surf_intv, "unknown");
diff --git a/uemis.h b/uemis.h
index 29a168f5d..ba9a23402 100644
--- a/uemis.h
+++ b/uemis.h
@@ -28,7 +28,7 @@ typedef struct {
uint16_t consumption; // (units unclear)
uint8_t rgt; // (remaining gas time in minutes)
uint8_t cns;
- uint8_t flags[8];
+ uint8_t flags[8];
} __attribute((packed)) uemis_sample_t;
#endif /* DIVE_H */