Add dive tags and support invalid dives

This started out as a way to keep dives in the dive list but being able to
mark them as 'invalid' so they wouldn't be visible (with an option to
disable that feature).

Now it supports an (at this point, fixed) set of tags that can be assigned
to a dive with 'invalid' being just one of them (but one that is special
as it gets some additional support for hiding such dive and marking dives
as (in)valid from the divelist).

[Dirk Hohndel: merged with the latest code and minor changes for coding
	       style and consistency. Ensure divelist is marked as
	       modified when changing 'invalid' tag]

Signed-Off-By: Jozef Ivanecký (dodo.sk@gmail.com)
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Ďoďo 2013-04-09 17:54:36 +02:00 committed by Dirk Hohndel
parent 68545465ba
commit ed3f67bc33
9 changed files with 198 additions and 5 deletions

13
dive.h
View file

@ -28,6 +28,18 @@
#define SEAWATER_SALINITY 10300
#define FRESHWATER_SALINITY 10000
/* Dive types definition */
#define DTYPE_INVALID 1
#define DTYPE_BOAT 2
#define DTYPE_SHORE 4
#define DTYPE_DRIFT 8
#define DTYPE_DEEP 16
#define DTYPE_CAVERN 32
#define DTYPE_ICE 64
#define DTYPE_WRECK 128
#define DTYPE_CAVE 256
#define DTYPE_ALTITUDE 512
#define DTYPE_POOL 1024
/*
* Some silly typedefs to make our units very explicit.
@ -342,6 +354,7 @@ struct dive {
pressure_t surface_pressure;
duration_t duration;
int salinity; // kg per 10000 l
int dive_tags;
struct divecomputer dc;
};

View file

@ -715,7 +715,10 @@ static void fill_dive_list(void)
i = dive_table.nr;
while (--i >= 0) {
struct dive *dive = get_dive(i);
dive_trip_t *trip = dive->divetrip;
dive_trip_t *trip;
if ((dive->dive_tags & DTYPE_INVALID) && !prefs.display_invalid_dives)
continue;
trip = dive->divetrip;
if (!trip) {
parent_ptr = NULL;
@ -1061,6 +1064,42 @@ static void save_as_cb(GtkWidget *menuitem, struct dive *dive)
}
}
static void invalid_dives_cb(GtkWidget *menuitem, GtkTreePath *path)
{
int i;
int changed = 0;
struct dive *dive;
if (!amount_selected)
return;
/* walk the dive list in chronological order */
for_each_dive(i, dive) {
dive = get_dive(i);
if (!dive)
continue;
if (!dive->selected)
continue;
/* now swap the invalid tag if just 1 dive was selected
* otherwise set all to invalid */
if(amount_selected == 1) {
if (dive->dive_tags & DTYPE_INVALID)
dive->dive_tags &= ~DTYPE_INVALID;
else
dive->dive_tags |= DTYPE_INVALID;
changed = 1;
} else {
if (! dive->dive_tags & DTYPE_INVALID) {
dive->dive_tags |= DTYPE_INVALID;
changed = 1;
}
}
}
if (changed) {
dive_list_update_dives();
mark_divelist_changed(TRUE);
}
}
static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view)
{
gtk_tree_view_expand_all(tree_view);
@ -1626,7 +1665,7 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
} else {
dive = get_dive(idx);
/* if we right click on selected dive(s), edit or delete those */
/* if we right click on selected dive(s), edit, delete or tag them as invalid */
if (dive->selected) {
if (amount_selected == 1) {
deletelabel = _(deletesinglelabel);
@ -1642,6 +1681,17 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
g_signal_connect(menuitem, "activate", G_CALLBACK(save_as_cb), dive);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
if (amount_selected == 1) {
if (dive->dive_tags & DTYPE_INVALID)
menuitem = gtk_menu_item_new_with_label(_("Mark valid"));
else
menuitem = gtk_menu_item_new_with_label(_("Mark invalid"));
} else {
menuitem = gtk_menu_item_new_with_label(_("Mark invalid"));
}
g_signal_connect(menuitem, "activate", G_CALLBACK(invalid_dives_cb), path);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
menuitem = gtk_menu_item_new_with_label(deletelabel);
g_signal_connect(menuitem, "activate", G_CALLBACK(delete_selected_dives_cb), path);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);

View file

@ -626,6 +626,7 @@ OPTIONCALLBACK(maxcns_toggle, prefs.visible_cols.maxcns)
OPTIONCALLBACK(sac_toggle, prefs.visible_cols.sac)
OPTIONCALLBACK(nitrox_toggle, prefs.visible_cols.nitrox)
OPTIONCALLBACK(temperature_toggle, prefs.visible_cols.temperature)
OPTIONCALLBACK(display_invalid_dives_toggle, prefs.display_invalid_dives)
OPTIONCALLBACK(totalweight_toggle, prefs.visible_cols.totalweight)
OPTIONCALLBACK(suit_toggle, prefs.visible_cols.suit)
OPTIONCALLBACK(cylinder_toggle, prefs.visible_cols.cylinder)
@ -852,6 +853,11 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
box = gtk_hbox_new(FALSE, 6);
gtk_container_add(GTK_CONTAINER(frame), box);
button = gtk_check_button_new_with_label(_("Display invalid dives"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), prefs.display_invalid_dives);
gtk_box_pack_end(GTK_BOX(box), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(display_invalid_dives_toggle), NULL);
frame = gtk_frame_new(_("Default XML Data File"));
gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5);
hbox = gtk_hbox_new(FALSE, 6);
@ -1073,6 +1079,7 @@ static void preferences_dialog(GtkWidget *w, gpointer data)
free((void *)provider);
#endif
save_preferences();
dive_list_update_dives();
} else if (result == GTK_RESPONSE_CANCEL) {
prefs = oldprefs;
set_gf(prefs.gflow, prefs.gfhigh);

75
info.c
View file

@ -606,6 +606,10 @@ static void save_dive_info_changes(struct dive *dive, struct dive *master, struc
if (old_text)
g_free(old_text);
}
if (dive->dive_tags != master->dive_tags) {
changed = 1;
dive->dive_tags = master->dive_tags;
}
if (changed) {
mark_divelist_changed(TRUE);
update_dive(dive);
@ -793,9 +797,18 @@ static gboolean base_data_cb(GtkWidget *w, GdkEvent *event, gpointer _data)
return FALSE;
}
void divetag_toggle_cb(GtkWidget *widget, gpointer data)
{
int DT = GPOINTER_TO_INT (data);
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
edit_dive.dive_tags |= DT;
else
edit_dive.dive_tags &= ~DT;
}
static void dive_info_widget(GtkWidget *obox, struct dive *dive, struct dive_info *info, gboolean multi)
{
GtkWidget *hbox, *frame, *equipment, *ibox, *box;
GtkWidget *hbox, *frame, *equipment, *ibox, *box, *button, *sbox, *framebox;
#if HAVE_OSM_GPS_MAP
GtkWidget *image;
#endif
@ -870,6 +883,66 @@ static void dive_info_widget(GtkWidget *obox, struct dive *dive, struct dive_inf
airtemp[0] = '\0';
info->airtemp = single_text_entry(hbox, buffer, airtemp);
frame = gtk_frame_new(_("Dive Type"));
gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 0);
framebox = gtk_vbox_new(FALSE, 3);
gtk_container_add(GTK_CONTAINER(frame), framebox);
sbox = gtk_hbox_new(FALSE, 6);
gtk_box_pack_start(GTK_BOX(framebox), sbox, TRUE, FALSE, 3);
/* 1st line */
button = gtk_check_button_new_with_label(_("Boat Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_BOAT);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_BOAT));
button = gtk_check_button_new_with_label(_("Shore Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_SHORE);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_SHORE));
button = gtk_check_button_new_with_label(_("Pool Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_POOL);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_POOL));
sbox = gtk_hbox_new(FALSE, 6);
gtk_box_pack_start(GTK_BOX(framebox), sbox, TRUE, FALSE, 3);
/* 2nd line */
button = gtk_check_button_new_with_label(_("Drift Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_DRIFT);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_DRIFT));
button = gtk_check_button_new_with_label(_("Deep Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_DEEP);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_DEEP));
button = gtk_check_button_new_with_label(_("Cavern Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_CAVERN);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_CAVERN));
sbox = gtk_hbox_new(FALSE, 6);
gtk_box_pack_start(GTK_BOX(framebox), sbox, TRUE, FALSE, 3);
/* 3rd line */
button = gtk_check_button_new_with_label(_("Ice Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_ICE);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_ICE));
button = gtk_check_button_new_with_label(_("Wreck Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_WRECK);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_WRECK));
button = gtk_check_button_new_with_label(_("Cave Dive"));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), dive->dive_tags & DTYPE_CAVE);
gtk_box_pack_start(GTK_BOX(sbox), button, FALSE, FALSE, 6);
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(divetag_toggle_cb), GINT_TO_POINTER (DTYPE_CAVE));
/* only show notes if editing a single dive */
if (multi) {
info->notes = NULL;

View file

@ -1033,6 +1033,8 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf)
if (MATCH(".number", get_index, &dive->number))
return;
if (MATCH(".tags", get_index, &dive->dive_tags))
return;
if (MATCH(".tripflag", get_tripflag, &dive->tripflag))
return;
if (MATCH(".date", divedate, &dive->when))

1
pref.h
View file

@ -36,6 +36,7 @@ struct preferences {
int map_provider;
const char *divelist_font;
const char *default_filename;
short display_invalid_dives;
};
extern struct preferences prefs, default_prefs;

View file

@ -113,6 +113,7 @@ void save_preferences(void)
SAVE_STRING("default_filename", default_filename);
SAVE_INT("map_provider", map_provider);
SAVE_INT("display_invalid_dives", display_invalid_dives);
/* Flush the changes out to the system */
subsurface_flush_conf();
@ -204,6 +205,10 @@ void load_preferences(void)
prefs.default_filename = conf_value;
int_value = subsurface_get_conf_int("map_provider");
if(int_value >= 0)
if (int_value >= 0)
prefs.map_provider = int_value;
int_value = subsurface_get_conf_int("display_invalid_dives");
if (int_value >= 0)
prefs.display_invalid_dives = int_value;
}

View file

@ -451,6 +451,8 @@ void save_dive(FILE *f, struct dive *dive)
fprintf(f, " rating='%d'", dive->rating);
if (dive->visibility)
fprintf(f, " visibility='%d'", dive->visibility);
if (dive->dive_tags)
fprintf(f, " tags='%d'", dive->dive_tags);
show_date(f, dive->when);
fprintf(f, " duration='%u:%02u min'>\n",
FRACTION(dive->dc.duration.seconds, 60));

View file

@ -28,7 +28,8 @@ typedef struct {
*sac,
*otu,
*o2he,
*gas_used;
*gas_used,
*dive_type;
} single_stat_widget_t;
static single_stat_widget_t single_w;
@ -631,6 +632,38 @@ static void show_single_dive_stats(struct dive *dive)
} else {
set_label(single_w.gas_used, "");
}
/* Dive type */
if (dive->dive_tags) {
buf[0]=0;
if(dive->dive_tags & DTYPE_INVALID)
strcat(buf, " Invalid,");
if(dive->dive_tags & DTYPE_BOAT)
strcat(buf, " Boat,");
if(dive->dive_tags & DTYPE_SHORE)
strcat(buf, " Shore,");
if(dive->dive_tags & DTYPE_DRIFT)
strcat(buf, " Drift,");
if(dive->dive_tags & DTYPE_DEEP)
strcat(buf, " Deep,");
if(dive->dive_tags & DTYPE_CAVERN)
strcat(buf, " Cavern,");
if(dive->dive_tags & DTYPE_ICE)
strcat(buf, " Ice,");
if(dive->dive_tags & DTYPE_WRECK)
strcat(buf, " Wreck,");
if(dive->dive_tags & DTYPE_CAVE)
strcat(buf, " Cave,");
if(dive->dive_tags & DTYPE_ALTITUDE)
strcat(buf, " Altitude,");
if(dive->dive_tags & DTYPE_POOL)
strcat(buf, " Pool,");
if(strlen(buf) > 1)
buf[strlen(buf)-1] = 0;
}
else {
buf[0] = 0;
}
set_label(single_w.dive_type, buf);
}
/* this gets called when at least two but not all dives are selected */
@ -865,6 +898,12 @@ GtkWidget *single_stats_widget(void)
single_w.o2he = new_info_label_in_frame(hbox, "O" UTF8_SUBSCRIPT_2 " / He");
single_w.gas_used = new_info_label_in_frame(hbox, C_("Amount","Gas Used"));
/* fifth row */
hbox = gtk_hbox_new(FALSE, 3);
gtk_box_pack_start(GTK_BOX(framebox), hbox, TRUE, FALSE, 3);
single_w.dive_type = new_info_label_in_frame(hbox, _("Dive Type"));
return vbox;
}
@ -884,6 +923,7 @@ void clear_stats_widgets(void)
set_label(single_w.otu, "");
set_label(single_w.o2he, "");
set_label(single_w.gas_used, "");
set_label(single_w.dive_type, "");
set_label(stats_w.total_time,"");
set_label(stats_w.avg_time,"");
set_label(stats_w.shortest_time,"");