]> git.tdb.fi Git - ext/subsurface.git/commitdiff
Merge branch 'freediving-tweaks' of git://github.com/mguentner/subsurface
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Aug 2012 20:20:23 +0000 (13:20 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Aug 2012 20:20:23 +0000 (13:20 -0700)
Merge freediving tweaks (zoom in on short dives etc) from Maximilian
Güntner.

Trivial conflicts in display.h due to unrelated printing stuff just
happening to be added nearby.

* 'freediving-tweaks' of git://github.com/mguentner/subsurface:
  moved zoomed_plot to display.h
  plot the time with a fixed padding (leading zero)
  updated/corrected comment
  added "Zoom" button and improved scaling
  fixed indentation
  use increments that make sense for 600 seconds
  Plot shorter (apnea) dives with a reasonable scale

19 files changed:
display.h
dive.h
divelist.c
dives/test21.xml [new file with mode: 0644]
dives/test22.xml [new file with mode: 0644]
dives/test23.xml [new file with mode: 0644]
equipment.c
file.c
gtk-gui.c
info.c
libdivecomputer.c
libdivecomputer.h
main.c
parse-xml.c
print.c
profile.c
save-xml.c
statistics.c
uemis.h

index 5f99849b7b496a699c6c9431f042f5cb725287f8..4e1511656ad5d20b38948b8819a5ad25aefe5ee0 100644 (file)
--- 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 ab854e37e6c6d49bfe43b6533322cd9facd11c4f..dffe7532587ef28dd8e50e0e2543fb719549fa7f 100644 (file)
--- 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
index 30bd2d8e97b9024383e3e961457bae46ae06d356..a773b60179674084a2dfe251e5537bf37285e64d 100644 (file)
@@ -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 (file)
index 0000000..5f5f6c9
--- /dev/null
@@ -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 (file)
index 0000000..a610323
--- /dev/null
@@ -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 (file)
index 0000000..c61ad2d
--- /dev/null
@@ -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>
index 43bb29d593ae6009d81db0e291adf60af2f26a1c..d676fc05d60513469514a7f601161ac0f7eb109a 100644 (file)
@@ -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 e0163909e9160f59f1f74ea667e50ec52684ef30..da498995cc0c1522c802a86f4d34ae4522023702 100644 (file)
--- 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);
index 9bd4f131d83e086d142e42877eb242001a32dfbd..7db777ab92e4254fdb14644ad2ac2c9348387dc4 100644 (file)
--- 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 8db606344e7394ecbe44d5dbc961788d669c0dce..d9379ac68b200976f08c9afada59bd87f88bb736 100644 (file)
--- 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);
index e362d1d2ba9ad13f018c5007fb3443acd879b6ea..d96d2769f7391afb3bccebb64df1de5fd21a33e5 100644 (file)
@@ -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;
index 8d77a25beba9230e51e20be293960d9f28f048d3..6430c844841921bb0d85ae0142045546d498cfea 100644 (file)
@@ -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 8e579f88c067b78891967684cc80b1469714ffb0..2489473b9c2f9fe43f65c4ce0405fba3b79e7cc6 100644 (file)
--- 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);
index 173314dd42161ff28af7c7374bdf80e23ee6a706..5159a334f9153f65b010f0e1cf5c4845cebcf530 100644 (file)
@@ -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 0bd3110a7bc67d4fdab31ac483bc93230e7f1a66..5a1a784b2fe694ab7e782ae7c6f7ff11b617bf5b 100644 (file)
--- a/print.c
+++ b/print.c
 #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) {
index 3ad11c0d0e97e4273f150ec5190a6ec42753105b..d4e88c02c21c498293d87a87ebf0f7a853a13ea0 100644 (file)
--- 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;
 }
 
index 37d6d062eabf836f188b8cfc2bcd0b6feae0c6a4..b797475e5362441b49bfe5cbf87a7a64d4259ae9 100644 (file)
@@ -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");
index b9d2c3b95d19c57f96b2a353e274d9bb4304c301..a53617337fa712b8864a3fdc4aee20bd8b7f9682 100644 (file)
@@ -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 29a168f5d3449a04efd066b6803e50e78a3be086..ba9a234024dbaa50541c2a1024730364b1500ad5 100644 (file)
--- 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 */