Improve tree model implementation

We now support three hierarchy levels: day, month, and year. Each
indicated by a negative DIVE_INDEX for -1 to -3. This allows a nice
compact overview when doing date based sorting (the default).

As indicated in the previous commit, things still go wrong with sorting by
other columns as the entries are only sorted within each day, not globally
across the whole dive list.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Dirk Hohndel 2012-08-13 13:09:40 -07:00
parent 1f3813eb3d
commit 5f1e41de43

View file

@ -52,6 +52,12 @@ enum {
DIVELIST_COLUMNS DIVELIST_COLUMNS
}; };
/* magic numbers that indicate (as negative values) model entries that
* are summary entries for day / month / year */
#define NEW_DAY 1
#define NEW_MON 2
#define NEW_YR 3
#ifdef DEBUG_MODEL #ifdef DEBUG_MODEL
static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path, static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data) GtkTreeIter *iter, gpointer data)
@ -77,7 +83,6 @@ static GList *selected_dives;
static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model) static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model)
{ {
GtkTreeIter iter; GtkTreeIter iter;
GValue value = {0, };
GtkTreePath *path; GtkTreePath *path;
int nr_selected = gtk_tree_selection_count_selected_rows(selection); int nr_selected = gtk_tree_selection_count_selected_rows(selection);
@ -96,10 +101,23 @@ static void selection_cb(GtkTreeSelection *selection, GtkTreeModel *model)
amount_selected = 1; amount_selected = 1;
path = g_list_nth_data(selected_dives, 0); path = g_list_nth_data(selected_dives, 0);
if (gtk_tree_model_get_iter(model, &iter, path)) { if (gtk_tree_model_get_iter(model, &iter, path)) {
gtk_tree_model_get_value(model, &iter, DIVE_INDEX, &value); gtk_tree_model_get(model, &iter, DIVE_INDEX, &selected_dive, -1);
/* an index of -1 should mean select all dives from that day /* a negative index means we picked a summary entry;
* ===> still needs to be implemented */ expand that entry and use first real child instead */
selected_dive = g_value_get_int(&value); while (selected_dive < 0) {
GtkTreeIter parent;
GtkTreePath *tpath;
memcpy(&parent, &iter, sizeof(parent));
tpath = gtk_tree_model_get_path(model, &parent);
if (!gtk_tree_model_iter_children(model, &iter, &parent))
/* we should never have a parent without child */
return;
if(gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath))
gtk_tree_view_collapse_row(GTK_TREE_VIEW(dive_list.tree_view), tpath);
else
gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE);
gtk_tree_model_get(model, &iter, DIVE_INDEX, &selected_dive, -1);
}
repaint_dive(); repaint_dive();
} }
return; return;
@ -135,7 +153,7 @@ static void star_data_func(GtkTreeViewColumn *col,
char buffer[40]; char buffer[40];
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_RATING, &nr_stars, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_RATING, &nr_stars, -1);
if (idx == -1) { if (idx < 0) {
*buffer = '\0'; *buffer = '\0';
} else { } else {
if (nr_stars < 0 || nr_stars > 5) if (nr_stars < 0 || nr_stars > 5)
@ -162,19 +180,32 @@ static void date_data_func(GtkTreeViewColumn *col,
when = val; when = val;
tm = gmtime(&when); tm = gmtime(&when);
if (idx == -1) switch(idx) {
case -NEW_DAY:
snprintf(buffer, sizeof(buffer), snprintf(buffer, sizeof(buffer),
"%s, %s %d, %d", "%s, %s %d, %d",
weekday(tm->tm_wday), weekday(tm->tm_wday),
monthname(tm->tm_mon), monthname(tm->tm_mon),
tm->tm_mday, tm->tm_year + 1900); tm->tm_mday, tm->tm_year + 1900);
else break;
case -NEW_MON:
snprintf(buffer, sizeof(buffer),
"%s %d",
monthname(tm->tm_mon),
tm->tm_year + 1900);
break;
case -NEW_YR:
snprintf(buffer, sizeof(buffer),
"%d", tm->tm_year + 1900);
break;
default:
snprintf(buffer, sizeof(buffer), snprintf(buffer, sizeof(buffer),
"%s, %s %d, %d %02d:%02d", "%s, %s %d, %d %02d:%02d",
weekday(tm->tm_wday), weekday(tm->tm_wday),
monthname(tm->tm_mon), monthname(tm->tm_mon),
tm->tm_mday, tm->tm_year + 1900, tm->tm_mday, tm->tm_year + 1900,
tm->tm_hour, tm->tm_min); tm->tm_hour, tm->tm_min);
}
g_object_set(renderer, "text", buffer, NULL); g_object_set(renderer, "text", buffer, NULL);
} }
@ -189,7 +220,7 @@ static void depth_data_func(GtkTreeViewColumn *col,
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DEPTH, &depth, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DEPTH, &depth, -1);
if (idx == -1) { if (idx < 0) {
*buffer = '\0'; *buffer = '\0';
} else { } else {
switch (output_units.length) { switch (output_units.length) {
@ -224,11 +255,12 @@ static void duration_data_func(GtkTreeViewColumn *col,
GtkTreeIter *iter, GtkTreeIter *iter,
gpointer data) gpointer data)
{ {
unsigned int sec, idx; unsigned int sec;
int idx;
char buffer[16]; char buffer[16];
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DURATION, &sec, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_DURATION, &sec, -1);
if (idx == -1) if (idx < 0)
*buffer = '\0'; *buffer = '\0';
else else
snprintf(buffer, sizeof(buffer), "%d:%02d", sec / 60, sec % 60); snprintf(buffer, sizeof(buffer), "%d:%02d", sec / 60, sec % 60);
@ -248,7 +280,7 @@ static void temperature_data_func(GtkTreeViewColumn *col,
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_TEMPERATURE, &value, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_TEMPERATURE, &value, -1);
*buffer = 0; *buffer = 0;
if (idx != -1 && value) { if (idx >= 0 && value) {
double deg; double deg;
switch (output_units.temperature) { switch (output_units.temperature) {
case CELSIUS: case CELSIUS:
@ -276,7 +308,7 @@ static void nr_data_func(GtkTreeViewColumn *col,
char buffer[40]; char buffer[40];
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, -1);
if (idx == -1) if (idx < 0)
*buffer = '\0'; *buffer = '\0';
else else
snprintf(buffer, sizeof(buffer), "%d", nr); snprintf(buffer, sizeof(buffer), "%d", nr);
@ -360,16 +392,16 @@ static void nitrox_data_func(GtkTreeViewColumn *col,
GtkTreeIter *iter, GtkTreeIter *iter,
gpointer data) gpointer data)
{ {
int index, o2, he, o2low; int idx, o2, he, o2low;
char buffer[80]; char buffer[80];
struct dive *dive; struct dive *dive;
gtk_tree_model_get(model, iter, DIVE_INDEX, &index, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1);
if (index == -1) { if (idx < 0) {
*buffer = '\0'; *buffer = '\0';
goto exit; goto exit;
} }
dive = get_dive(index); dive = get_dive(idx);
get_dive_gas(dive, &o2, &he, &o2low); get_dive_gas(dive, &o2, &he, &o2low);
o2 = (o2 + 5) / 10; o2 = (o2 + 5) / 10;
he = (he + 5) / 10; he = (he + 5) / 10;
@ -402,7 +434,7 @@ static void sac_data_func(GtkTreeViewColumn *col,
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_SAC, &value, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_SAC, &value, -1);
if (idx == -1 || !value) { if (idx < 0 || !value) {
*buffer = '\0'; *buffer = '\0';
goto exit; goto exit;
} }
@ -434,7 +466,7 @@ static void otu_data_func(GtkTreeViewColumn *col,
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_OTU, &value, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_OTU, &value, -1);
if (idx == -1 || !value) if (idx < 0 || !value)
*buffer = '\0'; *buffer = '\0';
else else
snprintf(buffer, sizeof(buffer), "%d", value); snprintf(buffer, sizeof(buffer), "%d", value);
@ -592,8 +624,8 @@ static gboolean set_one_dive(GtkTreeModel *model,
/* Get the dive number */ /* Get the dive number */
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1); gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, -1);
if (idx == -1) if (idx < 0)
return TRUE; return FALSE;
dive = get_dive(idx); dive = get_dive(idx);
if (!dive) if (!dive)
return TRUE; return TRUE;
@ -642,11 +674,21 @@ void update_dive_list_col_visibility(void)
return; return;
} }
static int new_day(struct dive *dive, struct dive **last_dive, time_t *tm_date) static int new_date(struct dive *dive, struct dive **last_dive, const int flag, time_t *tm_date)
{ {
if (!last_dive) if (!last_dive)
return TRUE; return TRUE;
if (!*last_dive) { if (*last_dive) {
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 || flag > NEW_MON) &&
(tm1.tm_mday == tm2.tm_mday || flag > NEW_DAY))
return FALSE;
}
if (flag == NEW_DAY)
*last_dive = dive; *last_dive = dive;
if (tm_date) { if (tm_date) {
struct tm *tm1 = gmtime(&dive->when); struct tm *tm1 = gmtime(&dive->when);
@ -656,32 +698,12 @@ static int new_day(struct dive *dive, struct dive **last_dive, time_t *tm_date)
*tm_date = mktime(tm1); *tm_date = mktime(tm1);
} }
return TRUE; 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) static void fill_dive_list(void)
{ {
int i; int i, j;
GtkTreeIter iter, parent_iter, *parent = NULL; GtkTreeIter iter, parent_iter[NEW_YR + 2], *parents[NEW_YR + 2] = {NULL, };
GtkTreeStore *store; GtkTreeStore *store;
struct dive *last_dive = NULL; struct dive *last_dive = NULL;
time_t dive_date; time_t dive_date;
@ -692,21 +714,23 @@ static void fill_dive_list(void)
while (--i >= 0) { while (--i >= 0) {
struct dive *dive = dive_table.dives[i]; struct dive *dive = dive_table.dives[i];
if (new_day(dive, &last_dive, &dive_date)) for (j = NEW_YR; j >= NEW_DAY; j--) {
if (new_date(dive, &last_dive, j, &dive_date))
{ {
gtk_tree_store_append(store, &parent_iter, NULL); gtk_tree_store_append(store, &parent_iter[j], parents[j+1]);
parent = &parent_iter; parents[j] = &parent_iter[j];
gtk_tree_store_set(store, parent, gtk_tree_store_set(store, parents[j],
DIVE_INDEX, -1, DIVE_INDEX, -j,
DIVE_NR, -1, DIVE_NR, -j,
DIVE_DATE, dive_date, DIVE_DATE, dive_date,
DIVE_LOCATION, "", DIVE_LOCATION, "",
DIVE_TEMPERATURE, 0, DIVE_TEMPERATURE, 0,
DIVE_SAC, 0, DIVE_SAC, 0,
-1); -1);
} }
}
update_cylinder_related_info(dive); update_cylinder_related_info(dive);
gtk_tree_store_append(store, &iter, parent); gtk_tree_store_append(store, &iter, parents[NEW_DAY]);
gtk_tree_store_set(store, &iter, gtk_tree_store_set(store, &iter,
DIVE_INDEX, i, DIVE_INDEX, i,
DIVE_NR, dive->number, DIVE_NR, dive->number,
@ -796,8 +820,8 @@ static void row_activated_cb(GtkTreeView *tree_view,
if (!gtk_tree_model_get_iter(model, &iter, path)) if (!gtk_tree_model_get_iter(model, &iter, path))
return; return;
gtk_tree_model_get(model, &iter, DIVE_INDEX, &index, -1); gtk_tree_model_get(model, &iter, DIVE_INDEX, &index, -1);
/* an index of -1 is special for the "group by date" entries */ /* a negative index is special for the "group by date" entries */
if (index != -1) if (index >= 0)
edit_dive_info(get_dive(index)); edit_dive_info(get_dive(index));
} }