summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Dirk Hohndel <dirk@hohndel.org>2012-12-12 20:26:29 -1000
committerGravatar Dirk Hohndel <dirk@hohndel.org>2012-12-13 21:33:30 -1000
commit713a4fcff6a580aab4a5036a5c3603ebce7ee830 (patch)
treeb47b4bd29cc692b1dfaa6890d108b422d1066ffa
parentaba65736eb8cb85fa9bfa953095eab21f0668904 (diff)
downloadsubsurface-713a4fcff6a580aab4a5036a5c3603ebce7ee830.tar.gz
Add the ability to set a nickname for a dive computer
We maintain a list of dive computers that we know about (by deviceid) and their nicknames in our config. If the user downloads dive from a dive computer that we haven't seen before, we give them the option to set a nickname for that dive computer. That nickname is displayed in the profile (and stored in the XML file, assuming it is not the same as the model). This implementation attempts to make sure that it correctly deals with utf8 nicknames. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
-rw-r--r--dive.h4
-rw-r--r--gtk-gui.c137
-rw-r--r--main.c10
-rw-r--r--parse-xml.c2
-rw-r--r--profile.c5
-rw-r--r--save-xml.c2
6 files changed, 158 insertions, 2 deletions
diff --git a/dive.h b/dive.h
index 7927512b7..d504790ae 100644
--- a/dive.h
+++ b/dive.h
@@ -266,6 +266,7 @@ struct event {
struct divecomputer {
timestamp_t when;
const char *model;
+ const char *nickname;
uint32_t deviceid, diveid;
int samples, alloc_samples;
struct sample *sample;
@@ -524,6 +525,9 @@ extern int edit_multi_dive_info(struct dive *single_dive);
extern void dive_list_update_dives(void);
extern void flush_divelist(struct dive *dive);
+extern void set_dc_nickname(struct dive *dive);
+extern void remember_dc(uint32_t deviceid, const char *nickname, gboolean change_conf);
+
#define DIVE_ERROR_PARSE 1
const char *weekday(int wday);
diff --git a/gtk-gui.c b/gtk-gui.c
index 59e62948c..18a022c9d 100644
--- a/gtk-gui.c
+++ b/gtk-gui.c
@@ -39,6 +39,14 @@ struct preferences prefs = {
FALSE
};
+struct dcnicknamelist {
+ const char *nickname;
+ uint32_t deviceid;
+ struct dcnicknamelist *next;
+};
+static struct dcnicknamelist *nicknamelist;
+char *nicknamestring;
+
static GtkWidget *dive_profile;
static const char *default_dive_computer_vendor;
static const char *default_dive_computer_product;
@@ -1178,6 +1186,33 @@ void init_ui(int *argcp, char ***argvp)
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);
+ conf_value = subsurface_get_conf("dc_nicknames", PREF_STRING);
+ nicknamestring = strdup("");
+ if (conf_value) {
+ char *next_token, *nickname;
+ uint32_t deviceid;
+ int len;
+ next_token = strdup(conf_value);
+ len = strlen(next_token);
+ while ((next_token = g_utf8_strchr(next_token, len, '{')) != NULL) {
+ /* replace the '{' so we keep looking in case any test fails */
+ *next_token = '(';
+ /* the next 8 chars are the deviceid, after that we have the utf8 nickname */
+ if (sscanf(next_token, "(%8x,", &deviceid) > 0) {
+ char *namestart, *nameend;
+ namestart = g_utf8_strchr(next_token, len, ',');
+ nameend = g_utf8_strchr(next_token, len, '}');
+ if (!namestart || !nameend)
+ continue;
+ *nameend = '\0';
+ nickname = strdup(namestart + 1);
+ remember_dc(deviceid, nickname, FALSE);
+ next_token = nameend + 1;
+ };
+ }
+ free((void *)conf_value);
+ free(next_token);
+ }
error_info_bar = NULL;
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_set_application_name ("subsurface");
@@ -1966,3 +2001,105 @@ void set_filename(const char *filename, gboolean force)
else
existing_filename = NULL;
}
+
+static const char *get_dc_nickname(uint32_t deviceid)
+{
+ struct dcnicknamelist *known = nicknamelist;
+ while (known) {
+ if (known->deviceid == deviceid)
+ return known->nickname;
+ known = known->next;
+ }
+ return NULL;
+}
+
+/* no curly braces or commas, please */
+static char *cleanedup_nickname(const char *nickname, int len)
+{
+ char *clean;
+ if (nickname) {
+ char *brace;
+
+ if (!g_utf8_validate(nickname, -1, NULL))
+ return strdup("");
+ brace = clean = strdup(nickname);
+ while (*brace) {
+ if (*brace == '{')
+ *brace = '(';
+ else if (*brace == '}')
+ *brace = ')';
+ else if (*brace == ',')
+ *brace = '.';
+ brace = g_utf8_next_char(brace);
+ if (*brace && g_utf8_next_char(brace) - clean >= len)
+ *brace = '\0';
+ }
+ } else {
+ clean = strdup("");
+ }
+ return clean;
+}
+
+void remember_dc(uint32_t deviceid, const char *nickname, gboolean change_conf)
+{
+ if (!get_dc_nickname(deviceid)) {
+ char buffer[80];
+ struct dcnicknamelist *nn_entry = malloc(sizeof(struct dcnicknamelist));
+ nn_entry->deviceid = deviceid;
+ /* make sure there are no curly braces or commas in the string and that
+ * it will fit in the buffer */
+ nn_entry->nickname = cleanedup_nickname(nickname, sizeof(buffer) - 12);
+ nn_entry->next = nicknamelist;
+ nicknamelist = nn_entry;
+ snprintf(buffer, 80, "{%08x,%s}", deviceid, nn_entry->nickname);
+ nicknamestring = realloc(nicknamestring, strlen(nicknamestring) + strlen(buffer) + 1);
+ strcat(nicknamestring, buffer);
+ if (change_conf)
+ subsurface_set_conf("dc_nicknames", PREF_STRING, nicknamestring);
+ }
+}
+
+void set_dc_nickname(struct dive *dive)
+{
+ GtkWidget *dialog, *vbox, *entry, *frame, *label;
+ char nickname[68];
+ const char *name;
+
+ if (!dive)
+ return;
+
+ if ((name = get_dc_nickname(dive->dc.deviceid)) != NULL) {
+ dive->dc.nickname = strdup(name);
+ } else {
+ dialog = gtk_dialog_new_with_buttons(
+ _("Dive Computer Nickname"),
+ GTK_WINDOW(main_window),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ NULL);
+ vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+ label = gtk_label_new(_("Subsurface can use a nickname for your dive computer.\n"
+ "The default is the model and device ID as shown below.\n"
+ "If you don't want to name this dive computer click "
+ "'Cancel' and Subsurface will simply display its model "
+ "as nickname."));
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
+ frame = gtk_frame_new(_("Nickname"));
+ gtk_box_pack_start(GTK_BOX(vbox), frame, FALSE, TRUE, 3);
+ entry = gtk_entry_new();
+ gtk_container_add(GTK_CONTAINER(frame), entry);
+ gtk_entry_set_max_length(GTK_ENTRY(entry), 68);
+ snprintf(nickname, 69, "%s (%08x)", dive->dc.model, dive->dc.deviceid);
+ gtk_entry_set_text(GTK_ENTRY(entry), nickname);
+ gtk_widget_show_all(dialog);
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ if (strcmp(dive->dc.model, gtk_entry_get_text(GTK_ENTRY(entry))))
+ dive->dc.nickname = cleanedup_nickname(gtk_entry_get_text(GTK_ENTRY(entry)),
+ sizeof(nickname));
+ }
+ gtk_widget_destroy(dialog);
+ remember_dc(dive->dc.deviceid, dive->dc.nickname, TRUE);
+ }
+}
diff --git a/main.c b/main.c
index b8d5079cc..44373faf6 100644
--- a/main.c
+++ b/main.c
@@ -124,6 +124,16 @@ void report_dives(gboolean is_imported, gboolean prefer_imported)
int preexisting = dive_table.preexisting;
struct dive *last;
+ /* set the nickname for the divecomputer for newly downloaded dives */
+ for (i = dive_table.preexisting; i < dive_table.nr; i++)
+ if (dive_table.dives[i]->downloaded) {
+ set_dc_nickname(dive_table.dives[i]);
+ } else {
+ struct divecomputer *dc = &dive_table.dives[i]->dc;
+ if (dc->nickname && *dc->nickname)
+ remember_dc(dc->deviceid, dc->nickname, TRUE);
+ }
+
/* This does the right thing for -1: NULL */
last = get_dive(preexisting-1);
diff --git a/parse-xml.c b/parse-xml.c
index 376860e6b..dd35379fb 100644
--- a/parse-xml.c
+++ b/parse-xml.c
@@ -625,6 +625,8 @@ static void try_to_fill_dc(struct divecomputer *dc, const char *name, char *buf)
return;
if (MATCH(".model", utf8_string, &dc->model))
return;
+ if (MATCH(".nickname", utf8_string, &dc->nickname))
+ return;
if (MATCH(".deviceid", hex_value, &dc->deviceid))
return;
if (MATCH(".diveid", hex_value, &dc->diveid))
diff --git a/profile.c b/profile.c
index c8571b8d5..984c5e2c9 100644
--- a/profile.c
+++ b/profile.c
@@ -1857,9 +1857,10 @@ void plot(struct graphics_context *gc, struct dive *dive, scale_mode_t scale)
cairo_stroke(gc->cr);
/* Put the dive computer name in the lower left corner */
- if (dc->model) {
+ if (dc->nickname || dc->model) {
static const text_render_options_t computer = {10, TIME_TEXT, LEFT, MIDDLE};
- plot_text(gc, &computer, 0, 1, "%s", dc->model);
+ plot_text(gc, &computer, 0, 1, "%s",
+ dc->nickname && *dc->nickname ? dc->nickname : dc->model);
}
if (PP_GRAPHS_ENABLED) {
diff --git a/save-xml.c b/save-xml.c
index fb9eb413a..0ec6f27d0 100644
--- a/save-xml.c
+++ b/save-xml.c
@@ -400,6 +400,8 @@ static void save_dc(FILE *f, struct dive *dive, struct divecomputer *dc)
fprintf(f, " <divecomputer");
if (dc->model)
show_utf8(f, dc->model, " model='", "'", 1);
+ if (dc->nickname && *dc->nickname)
+ show_utf8(f, dc->nickname, " nickname='", "'", 1);
if (dc->deviceid)
fprintf(f, " deviceid='%08x'", dc->deviceid);
if (dc->diveid)