]> git.tdb.fi Git - ext/subsurface.git/commitdiff
Allow date based grouping
authorDirk Hohndel <dirk@hohndel.org>
Wed, 8 Aug 2012 16:35:38 +0000 (09:35 -0700)
committerDirk Hohndel <dirk@hohndel.org>
Mon, 13 Aug 2012 20:04:56 +0000 (13:04 -0700)
This is the very first rough cut. It switches things over to a tree model
so we can have date based summary nodes.

It uses a DIVE_INDEX of -1 for summary nodes to easily tell them apart
from actual dives. All the data functions are changed so the summary
nodes only show the date they cover.

The commit also adds a couple of debug functions to be able to easily peek
into the model from the debugger.

Lots of things left to do. There is no longer a first dive selected when
starting subsurface. Sorting by columns other than date is messed up. We
almost certainly want month and year summary entries as well.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
divelist.c

index 21f343f7f0d2d0f6d98685eacd5a65be460c961e..8899d74297d267a6d2585a263457480e2fa95d0b 100644 (file)
@@ -24,7 +24,7 @@
 struct DiveList {
        GtkWidget    *tree_view;
        GtkWidget    *container_widget;
-       GtkListStore *model;
+       GtkTreeStore *model;
        GtkTreeViewColumn *nr, *date, *stars, *depth, *duration, *location;
        GtkTreeViewColumn *temperature, *cylinder, *nitrox, *sac, *otu;
        int changed;
@@ -52,6 +52,26 @@ enum {
        DIVELIST_COLUMNS
 };
 
+#ifdef DEBUG_MODEL
+static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
+                               GtkTreeIter *iter, gpointer data)
+{
+       char *location;
+       int idx, nr, rating, depth;
+
+       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;
+}
+
+static void dump_model(GtkListStore *store)
+{
+       gtk_tree_model_foreach(GTK_TREE_MODEL(store), dump_model_entry, NULL);
+}
+#endif
+
 static GList *selected_dives;
 
 static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model)
@@ -77,6 +97,8 @@ static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model)
                path = g_list_nth_data(selected_dives, 0);
                if (gtk_tree_model_get_iter(model, &iter, path)) {
                        gtk_tree_model_get_value(model, &iter, DIVE_INDEX, &value);
+                       /* an index of -1 should mean select all dives from that day
+                        * ===> still needs to be implemented */
                        selected_dive = g_value_get_int(&value);
                        repaint_dive();
                }
@@ -109,13 +131,17 @@ static void star_data_func(GtkTreeViewColumn *col,
                           GtkTreeIter *iter,
                           gpointer data)
 {
-       int nr_stars;
+       int nr_stars, idx;
        char buffer[40];
 
-       gtk_tree_model_get(model, iter, DIVE_RATING, &nr_stars, -1);
-       if (nr_stars < 0 || nr_stars > 5)
-               nr_stars = 0;
-       snprintf(buffer, sizeof(buffer), "%s", star_strings[nr_stars]);
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_RATING, &nr_stars, -1);
+       if (idx == -1) {
+               *buffer = '\0';
+       } else {
+               if (nr_stars < 0 || nr_stars > 5)
+                       nr_stars = 0;
+               snprintf(buffer, sizeof(buffer), "%s", star_strings[nr_stars]);
+       }
        g_object_set(renderer, "text", buffer, NULL);
 }
 
@@ -125,23 +151,30 @@ static void date_data_func(GtkTreeViewColumn *col,
                           GtkTreeIter *iter,
                           gpointer data)
 {
-       int val;
+       int val, idx;
        struct tm *tm;
        time_t when;
        char buffer[40];
 
-       gtk_tree_model_get(model, iter, DIVE_DATE, &val, -1);
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DATE, &val, -1);
 
        /* 2038 problem */
        when = val;
 
        tm = gmtime(&when);
-       snprintf(buffer, sizeof(buffer),
-               "%s, %s %d, %d %02d:%02d",
-               weekday(tm->tm_wday),
-               monthname(tm->tm_mon),
-               tm->tm_mday, tm->tm_year + 1900,
-               tm->tm_hour, tm->tm_min);
+       if (idx == -1)
+               snprintf(buffer, sizeof(buffer),
+                       "%s, %s %d, %d",
+                       weekday(tm->tm_wday),
+                       monthname(tm->tm_mon),
+                       tm->tm_mday, tm->tm_year + 1900);
+       else
+               snprintf(buffer, sizeof(buffer),
+                       "%s, %s %d, %d %02d:%02d",
+                       weekday(tm->tm_wday),
+                       monthname(tm->tm_mon),
+                       tm->tm_mday, tm->tm_year + 1900,
+                       tm->tm_hour, tm->tm_min);
        g_object_set(renderer, "text", buffer, NULL);
 }
 
@@ -151,34 +184,37 @@ static void depth_data_func(GtkTreeViewColumn *col,
                            GtkTreeIter *iter,
                            gpointer data)
 {
-       int depth, integer, frac, len;
+       int depth, integer, frac, len, idx;
        char buffer[40];
 
-       gtk_tree_model_get(model, iter, DIVE_DEPTH, &depth, -1);
-
-       switch (output_units.length) {
-       case METERS:
-               /* To tenths of meters */
-               depth = (depth + 49) / 100;
-               integer = depth / 10;
-               frac = depth % 10;
-               if (integer < 20)
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DEPTH, &depth, -1);
+
+       if (idx == -1) {
+               *buffer = '\0';
+       } else {
+               switch (output_units.length) {
+               case METERS:
+                       /* To tenths of meters */
+                       depth = (depth + 49) / 100;
+                       integer = depth / 10;
+                       frac = depth % 10;
+                       if (integer < 20)
+                               break;
+                       if (frac >= 5)
+                               integer++;
+                       frac = -1;
                        break;
-               if (frac >= 5)
-                       integer++;
-               frac = -1;
-               break;
-       case FEET:
-               integer = mm_to_feet(depth) + 0.5;
-               frac = -1;
-               break;
-       default:
-               return;
+               case FEET:
+                       integer = mm_to_feet(depth) + 0.5;
+                       frac = -1;
+                       break;
+               default:
+                       return;
+               }
+               len = snprintf(buffer, sizeof(buffer), "%d", integer);
+               if (frac >= 0)
+                       len += snprintf(buffer+len, sizeof(buffer)-len, ".%d", frac);
        }
-       len = snprintf(buffer, sizeof(buffer), "%d", integer);
-       if (frac >= 0)
-               len += snprintf(buffer+len, sizeof(buffer)-len, ".%d", frac);
-
        g_object_set(renderer, "text", buffer, NULL);
 }
 
@@ -188,11 +224,14 @@ static void duration_data_func(GtkTreeViewColumn *col,
                               GtkTreeIter *iter,
                               gpointer data)
 {
-       unsigned int sec;
+       unsigned int sec, idx;
        char buffer[16];
 
-       gtk_tree_model_get(model, iter, DIVE_DURATION, &sec, -1);
-       snprintf(buffer, sizeof(buffer), "%d:%02d", sec / 60, sec % 60);
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DURATION, &sec, -1);
+       if (idx == -1)
+               *buffer = '\0';
+       else
+               snprintf(buffer, sizeof(buffer), "%d:%02d", sec / 60, sec % 60);
 
        g_object_set(renderer, "text", buffer, NULL);
 }
@@ -203,13 +242,13 @@ static void temperature_data_func(GtkTreeViewColumn *col,
                                  GtkTreeIter *iter,
                                  gpointer data)
 {
-       int value;
+       int value, idx;
        char buffer[80];
 
-       gtk_tree_model_get(model, iter, DIVE_TEMPERATURE, &value, -1);
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_TEMPERATURE, &value, -1);
 
        *buffer = 0;
-       if (value) {
+       if (idx != -1 && value) {
                double deg;
                switch (output_units.temperature) {
                case CELSIUS:
@@ -227,6 +266,23 @@ static void temperature_data_func(GtkTreeViewColumn *col,
        g_object_set(renderer, "text", buffer, NULL);
 }
 
+static void nr_data_func(GtkTreeViewColumn *col,
+                          GtkCellRenderer *renderer,
+                          GtkTreeModel *model,
+                          GtkTreeIter *iter,
+                          gpointer data)
+{
+       int idx, nr;
+       char buffer[40];
+
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, -1);
+       if (idx == -1)
+               *buffer = '\0';
+       else
+               snprintf(buffer, sizeof(buffer), "%d", nr);
+       g_object_set(renderer, "text", buffer, NULL);
+}
+
 /*
  * Get "maximal" dive gas for a dive.
  * Rules:
@@ -309,6 +365,10 @@ static void nitrox_data_func(GtkTreeViewColumn *col,
        struct dive *dive;
 
        gtk_tree_model_get(model, iter, DIVE_INDEX, &index, -1);
+       if (index == -1) {
+               *buffer = '\0';
+               goto exit;
+       }
        dive = get_dive(index);
        get_dive_gas(dive, &o2, &he, &o2low);
        o2 = (o2 + 5) / 10;
@@ -324,7 +384,7 @@ static void nitrox_data_func(GtkTreeViewColumn *col,
                        snprintf(buffer, sizeof(buffer), "%d" UTF8_ELLIPSIS "%d", o2low, o2);
        else
                strcpy(buffer, "air");
-
+exit:
        g_object_set(renderer, "text", buffer, NULL);
 }
 
@@ -335,16 +395,16 @@ static void sac_data_func(GtkTreeViewColumn *col,
                          GtkTreeIter *iter,
                          gpointer data)
 {
-       int value;
+       int value, idx;
        const char *fmt;
        char buffer[16];
        double sac;
 
-       gtk_tree_model_get(model, iter, DIVE_SAC, &value, -1);
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_SAC, &value, -1);
 
-       if (!value) {
-               g_object_set(renderer, "text", "", NULL);
-               return;
+       if (idx == -1 || !value) {
+               *buffer = '\0';
+               goto exit;
        }
 
        sac = value / 1000.0;
@@ -358,7 +418,7 @@ static void sac_data_func(GtkTreeViewColumn *col,
                break;
        }
        snprintf(buffer, sizeof(buffer), fmt, sac);
-
+exit:
        g_object_set(renderer, "text", buffer, NULL);
 }
 
@@ -369,17 +429,15 @@ static void otu_data_func(GtkTreeViewColumn *col,
                          GtkTreeIter *iter,
                          gpointer data)
 {
-       int value;
+       int value, idx;
        char buffer[16];
 
-       gtk_tree_model_get(model, iter, DIVE_OTU, &value, -1);
-
-       if (!value) {
-               g_object_set(renderer, "text", "", NULL);
-               return;
-       }
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_OTU, &value, -1);
 
-       snprintf(buffer, sizeof(buffer), "%d", value);
+       if (idx == -1 || !value)
+               *buffer = '\0';
+       else
+               snprintf(buffer, sizeof(buffer), "%d", value);
 
        g_object_set(renderer, "text", buffer, NULL);
 }
@@ -514,7 +572,7 @@ static void fill_one_dive(struct dive *dive,
        get_cylinder(dive, &cylinder);
        get_location(dive, &location);
 
-       gtk_list_store_set(GTK_LIST_STORE(model), iter,
+       gtk_tree_store_set(GTK_TREE_STORE(model), iter,
                DIVE_NR, dive->number,
                DIVE_LOCATION, location,
                DIVE_CYLINDER, cylinder,
@@ -529,12 +587,14 @@ static gboolean set_one_dive(GtkTreeModel *model,
                             GtkTreeIter *iter,
                             gpointer data)
 {
-       GValue value = {0, };
+       int idx;
        struct dive *dive;
 
        /* Get the dive number */
-       gtk_tree_model_get_value(model, iter, DIVE_INDEX, &value);
-       dive = get_dive(g_value_get_int(&value));
+       gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1);
+       if (idx == -1)
+               return TRUE;
+       dive = get_dive(idx);
        if (!dive)
                return TRUE;
        if (data && dive != data)
@@ -582,27 +642,79 @@ void update_dive_list_col_visibility(void)
        return;
 }
 
+static int new_day(struct dive *dive, struct dive **last_dive, time_t *tm_date)
+{
+       if (!last_dive)
+               return TRUE;
+       if (!*last_dive) {
+               *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;
+       } else {
+               struct dive *ldive = *last_dive;
+               struct tm tm1, tm2;
+               (void) gmtime_r(&dive->when, &tm1);
+               (void) gmtime_r(&ldive->when, &tm2);
+               if (tm1.tm_year != tm2.tm_year ||
+                   tm1.tm_mon != tm2.tm_mon ||
+                   tm1.tm_mday != tm2.tm_mday) {
+                       *last_dive = dive;
+                       if (tm_date) {
+                               tm1.tm_sec = 0;
+                               tm1.tm_min = 0;
+                               tm1.tm_hour = 0;
+                               *tm_date = mktime(&tm1);
+                       }
+                       return TRUE;
+               }
+       }
+       return FALSE;
+
+}
+
 static void fill_dive_list(void)
 {
        int i;
-       GtkTreeIter iter;
-       GtkListStore *store;
+       GtkTreeIter iter, parent_iter, *parent = NULL;
+       GtkTreeStore *store;
+       struct dive *last_dive = NULL;
+       time_t dive_date;
 
-       store = GTK_LIST_STORE(dive_list.model);
+       store = GTK_TREE_STORE(dive_list.model);
 
        i = dive_table.nr;
        while (--i >= 0) {
                struct dive *dive = dive_table.dives[i];
 
+               if (new_day(dive, &last_dive, &dive_date))
+               {
+                       gtk_tree_store_append(store, &parent_iter, NULL);
+                       parent = &parent_iter;
+                       gtk_tree_store_set(store, parent,
+                               DIVE_INDEX, -1,
+                               DIVE_NR, -1,
+                               DIVE_DATE, dive_date,
+                               DIVE_LOCATION, "",
+                               DIVE_TEMPERATURE, 0,
+                               DIVE_SAC, 0,
+                               -1);
+               }
                update_cylinder_related_info(dive);
-               gtk_list_store_append(store, &iter);
-               gtk_list_store_set(store, &iter,
+               gtk_tree_store_append(store, &iter, parent);
+               gtk_tree_store_set(store, &iter,
                        DIVE_INDEX, i,
                        DIVE_NR, dive->number,
                        DIVE_DATE, dive->when,
                        DIVE_DEPTH, dive->maxdepth,
                        DIVE_DURATION, dive->duration.seconds,
-                       DIVE_LOCATION, "location",
+                       DIVE_LOCATION, dive->location,
+                       DIVE_RATING, dive->rating,
                        DIVE_TEMPERATURE, dive->watertemp.mkelvin,
                        DIVE_SAC, 0,
                        -1);
@@ -618,7 +730,7 @@ static void fill_dive_list(void)
 
 void dive_list_update_dives(void)
 {
-       gtk_list_store_clear(GTK_LIST_STORE(dive_list.model));
+       gtk_tree_store_clear(GTK_TREE_STORE(dive_list.model));
        fill_dive_list();
        repaint_dive();
 }
@@ -630,7 +742,7 @@ static struct divelist_column {
        unsigned int flags;
        int *visible;
 } dl_column[] = {
-       [DIVE_NR] = { "#", NULL, NULL, ALIGN_RIGHT | UNSORTABLE },
+       [DIVE_NR] = { "#", nr_data_func, NULL, ALIGN_RIGHT | UNSORTABLE },
        [DIVE_DATE] = { "Date", date_data_func, NULL, ALIGN_LEFT },
        [DIVE_RATING] = { UTF8_BLACKSTAR, star_data_func, NULL, ALIGN_LEFT },
        [DIVE_DEPTH] = { "ft", depth_data_func, NULL, ALIGN_RIGHT },
@@ -653,7 +765,7 @@ static GtkTreeViewColumn *divelist_column(struct DiveList *dl, struct divelist_c
        unsigned int flags = col->flags;
        int *visible = col->visible;
        GtkWidget *tree_view = dl->tree_view;
-       GtkListStore *model = dl->model;
+       GtkTreeStore *model = dl->model;
        GtkTreeViewColumn *ret;
 
        if (visible && !*visible)
@@ -684,7 +796,9 @@ static void row_activated_cb(GtkTreeView *tree_view,
        if (!gtk_tree_model_get_iter(model, &iter, path))
                return;
        gtk_tree_model_get(model, &iter, DIVE_INDEX, &index, -1);
-       edit_dive_info(get_dive(index));
+       /* an index of -1 is special for the "group by date" entries */
+       if (index != -1)
+               edit_dive_info(get_dive(index));
 }
 
 void add_dive_cb(GtkWidget *menuitem, gpointer data)
@@ -734,7 +848,7 @@ GtkWidget *dive_list_create(void)
 {
        GtkTreeSelection  *selection;
 
-       dive_list.model = gtk_list_store_new(DIVELIST_COLUMNS,
+       dive_list.model = gtk_tree_store_new(DIVELIST_COLUMNS,
                                G_TYPE_INT,                     /* index */
                                G_TYPE_INT,                     /* nr */
                                G_TYPE_INT,                     /* Date */