Imrpove the nickname handling

We now store the model information together with the deviceid and nickname
in order to be able to check if we have a record for any dive computer
with the same model (as that now triggers our nickname dialog).

This changes the format of the config entries for nicknames - the best
solution might be to just delete those and start again.

What is still missing is the code to store the nicknames in the XML file.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
Dirk Hohndel 2012-12-21 21:00:06 -08:00
parent 8d2abc05f6
commit 50aa6d1afa
3 changed files with 124 additions and 52 deletions

2
dive.h
View file

@ -529,7 +529,7 @@ extern void flush_divelist(struct dive *dive);
extern void set_dc_nickname(struct dive *dive); extern void set_dc_nickname(struct dive *dive);
extern const char *get_dc_nickname(uint32_t deviceid); extern const char *get_dc_nickname(uint32_t deviceid);
extern void remember_dc(uint32_t deviceid, const char *nickname, gboolean change_conf); extern void remember_dc(uint32_t deviceid, const char *model, const char *nickname, gboolean change_conf);
#define DIVE_ERROR_PARSE 1 #define DIVE_ERROR_PARSE 1

113
gtk-gui.c
View file

@ -41,6 +41,7 @@ struct preferences prefs = {
struct dcnicknamelist { struct dcnicknamelist {
const char *nickname; const char *nickname;
const char *model;
uint32_t deviceid; uint32_t deviceid;
struct dcnicknamelist *next; struct dcnicknamelist *next;
}; };
@ -1204,7 +1205,7 @@ void init_ui(int *argcp, char ***argvp)
conf_value = subsurface_get_conf("dc_nicknames", PREF_STRING); conf_value = subsurface_get_conf("dc_nicknames", PREF_STRING);
nicknamestring = strdup(""); nicknamestring = strdup("");
if (conf_value) { if (conf_value) {
char *next_token, *nickname; char *next_token, *nickname, *model;
uint32_t deviceid; uint32_t deviceid;
int len; int len;
next_token = strdup(conf_value); next_token = strdup(conf_value);
@ -1212,16 +1213,35 @@ void init_ui(int *argcp, char ***argvp)
while ((next_token = g_utf8_strchr(next_token, len, '{')) != NULL) { while ((next_token = g_utf8_strchr(next_token, len, '{')) != NULL) {
/* replace the '{' so we keep looking in case any test fails */ /* replace the '{' so we keep looking in case any test fails */
*next_token = '('; *next_token = '(';
/* the next 8 chars are the deviceid, after that we have the utf8 nickname */ /* the next 8 chars are the deviceid, after that we have the model
* and the utf8 nickname (if set) */
if (sscanf(next_token, "(%8x,", &deviceid) > 0) { if (sscanf(next_token, "(%8x,", &deviceid) > 0) {
char *namestart, *nameend; char *namestart, *nameend, *tupleend;
namestart = g_utf8_strchr(next_token, len, ','); namestart = g_utf8_strchr(next_token, len, ',');
nameend = g_utf8_strchr(next_token, len, '}'); /* we know that namestart isn't NULL based on the sscanf succeeding */
if (!namestart || !nameend) len = strlen(namestart + 1);
continue; nameend = g_utf8_strchr(namestart + 1, len, ',');
tupleend = g_utf8_strchr(namestart + 1, len, '}');
if (!nameend && !tupleend)
/* the config entry is messed up - bail */
break;
if (!nameend || tupleend < nameend)
nameend = tupleend;
*nameend = '\0'; *nameend = '\0';
nickname = strdup(namestart + 1); model = strdup(namestart + 1);
remember_dc(deviceid, nickname, FALSE); if (tupleend == nameend) {
/* no nickname */
nickname = strdup("");
} else {
namestart = nameend + 1;
len = strlen(namestart);
nameend = g_utf8_strchr(namestart, len, '}');
if (!nameend)
break;
*nameend = '\0';
nickname = strdup(namestart);
}
remember_dc(deviceid, model, nickname, FALSE);
next_token = nameend + 1; next_token = nameend + 1;
}; };
} }
@ -2027,13 +2047,30 @@ const char *get_dc_nickname(uint32_t deviceid)
{ {
struct dcnicknamelist *known = nicknamelist; struct dcnicknamelist *known = nicknamelist;
while (known) { while (known) {
if (known->deviceid == deviceid) if (known->deviceid == deviceid) {
if (known->nickname && *known->nickname)
return known->nickname; return known->nickname;
else
return known->model;
}
known = known->next; known = known->next;
} }
return NULL; return NULL;
} }
/* do we have a DIFFERENT divecomputer of the same model? */
static gboolean dc_model_exists(struct divecomputer *dc)
{
struct dcnicknamelist *known = nicknamelist;
while (known) {
if (known->model && dc->model && !strcmp(known->model, dc->model) &&
known->deviceid != dc->deviceid)
return TRUE;
known = known->next;
}
return FALSE;
}
/* no curly braces or commas, please */ /* no curly braces or commas, please */
static char *cleanedup_nickname(const char *nickname, int len) static char *cleanedup_nickname(const char *nickname, int len)
{ {
@ -2061,37 +2098,59 @@ static char *cleanedup_nickname(const char *nickname, int len)
return clean; return clean;
} }
void remember_dc(uint32_t deviceid, const char *nickname, gboolean change_conf) void remember_dc(uint32_t deviceid, const char *model, const char *nickname, gboolean change_conf)
{ {
if (!get_dc_nickname(deviceid)) { if (!get_dc_nickname(deviceid)) {
char buffer[160]; char buffer[160];
struct dcnicknamelist *nn_entry = malloc(sizeof(struct dcnicknamelist)); struct dcnicknamelist *nn_entry = malloc(sizeof(struct dcnicknamelist));
nn_entry->deviceid = deviceid; nn_entry->deviceid = deviceid;
nn_entry->model = model;
/* make sure there are no curly braces or commas in the string and that /* make sure there are no curly braces or commas in the string and that
* it will fit in the buffer */ * it will fit in the buffer */
nn_entry->nickname = cleanedup_nickname(nickname, sizeof(buffer) - 12); nn_entry->nickname = cleanedup_nickname(nickname, sizeof(buffer) - 13 - strlen(model));
nn_entry->next = nicknamelist; nn_entry->next = nicknamelist;
nicknamelist = nn_entry; nicknamelist = nn_entry;
snprintf(buffer, sizeof(buffer), "{%08x,%s}", deviceid, nn_entry->nickname); if (*nickname != '\0')
snprintf(buffer, sizeof(buffer), "{%08x,%s,%s}", deviceid, model, nn_entry->nickname);
else
snprintf(buffer, sizeof(buffer), "{%08x,%s}", deviceid, model);
nicknamestring = realloc(nicknamestring, strlen(nicknamestring) + strlen(buffer) + 1); nicknamestring = realloc(nicknamestring, strlen(nicknamestring) + strlen(buffer) + 1);
strcat(nicknamestring, buffer); strcat(nicknamestring, buffer);
if (change_conf) if (change_conf)
subsurface_set_conf("dc_nicknames", PREF_STRING, nicknamestring); subsurface_set_conf("dc_nicknames", PREF_STRING, nicknamestring);
} }
#if defined(NICKNAME_DEBUG)
struct dcnicknamelist *nn_entry = nicknamelist;
fprintf(debugfile, "nicknames:\n");
while (nn_entry) {
fprintf(debugfile, "id %8x model %s nickname %s\n", nn_entry->deviceid, nn_entry->model,
nn_entry->nickname && *nn_entry->nickname ? nn_entry->nickname : "(none)");
nn_entry = nn_entry->next;
}
fprintf(debugfile, "----------\n");
#endif
} }
void set_dc_nickname(struct dive *dive) void set_dc_nickname(struct dive *dive)
{ {
GtkWidget *dialog, *vbox, *entry, *frame, *label; GtkWidget *dialog, *vbox, *entry, *frame, *label;
char nickname[160] = ""; char nickname[160] = "";
char dialogtext[1024];
const char *name = nickname; const char *name = nickname;
struct divecomputer *dc = &dive->dc;
if (!dive) if (!dive)
return; return;
while (dc) {
/* we should only do this if we already have a different dive computer #if NICKNAME_DEBUG & 16
* with the same model -- TBI */ fprintf(debugfile, "set_dc_nickname for model %s deviceid %8x\n", dc->model ? : "", dc->deviceid);
if (get_dc_nickname(dive->dc.deviceid) == NULL) { #endif
if (get_dc_nickname(dc->deviceid) == NULL) {
if (!dc_model_exists(dc)) {
/* just remember the dive computer without setting a nickname */
if (dc->model)
remember_dc(dc->deviceid, dc->model, "", TRUE);
} else {
dialog = gtk_dialog_new_with_buttons( dialog = gtk_dialog_new_with_buttons(
_("Dive Computer Nickname"), _("Dive Computer Nickname"),
GTK_WINDOW(main_window), GTK_WINDOW(main_window),
@ -2100,11 +2159,17 @@ void set_dc_nickname(struct dive *dive)
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
NULL); NULL);
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
label = gtk_label_new(_("Subsurface can use a nickname for your dive computer.\n" snprintf(dialogtext, sizeof(dialogtext),
_("You already have a dive computer of model %s\n"
"Subsurface can maintain a nickname for this device to "
"distinguish it from the existing one. "
"The default is the model and device ID as shown below.\n" "The default is the model and device ID as shown below.\n"
"If you don't want to name this dive computer click " "If you don't want to name this dive computer click "
"'Cancel' and Subsurface will simply display its model " "'Cancel' and Subsurface will simply display its model "
"as nickname.")); "as its name (which may mean that you cannot tell the two "
"dive computers apart in the logs."),
dc->model ? dc->model : "(unset)");
label = gtk_label_new(dialogtext);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
frame = gtk_frame_new(_("Nickname")); frame = gtk_frame_new(_("Nickname"));
@ -2112,15 +2177,17 @@ void set_dc_nickname(struct dive *dive)
entry = gtk_entry_new(); entry = gtk_entry_new();
gtk_container_add(GTK_CONTAINER(frame), entry); gtk_container_add(GTK_CONTAINER(frame), entry);
gtk_entry_set_max_length(GTK_ENTRY(entry), 68); gtk_entry_set_max_length(GTK_ENTRY(entry), 68);
snprintf(nickname, sizeof(nickname), "%s (%08x)", dive->dc.model, dive->dc.deviceid); snprintf(nickname, sizeof(nickname), "%s (%08x)", dc->model, dc->deviceid);
gtk_entry_set_text(GTK_ENTRY(entry), nickname); gtk_entry_set_text(GTK_ENTRY(entry), nickname);
gtk_widget_show_all(dialog); gtk_widget_show_all(dialog);
if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
if (strcmp(dive->dc.model, gtk_entry_get_text(GTK_ENTRY(entry)))) if (strcmp(dc->model, gtk_entry_get_text(GTK_ENTRY(entry))))
name = cleanedup_nickname(gtk_entry_get_text(GTK_ENTRY(entry)), name = cleanedup_nickname(gtk_entry_get_text(GTK_ENTRY(entry)), sizeof(nickname));
sizeof(nickname));
} }
gtk_widget_destroy(dialog); gtk_widget_destroy(dialog);
remember_dc(dive->dc.deviceid, name, TRUE); remember_dc(dc->deviceid, dc->model, name, TRUE);
}
}
dc = dc->next;
} }
} }

15
main.c
View file

@ -129,6 +129,10 @@ void report_dives(gboolean is_imported, gboolean prefer_imported)
* first one */ * first one */
if (preexisting < dive_table.nr && dive_table.dives[preexisting]->downloaded) if (preexisting < dive_table.nr && dive_table.dives[preexisting]->downloaded)
set_dc_nickname(dive_table.dives[preexisting]); set_dc_nickname(dive_table.dives[preexisting]);
else
/* they aren't downloaded, so record / check all new ones */
for (i = preexisting; i < dive_table.nr; i++)
set_dc_nickname(dive_table.dives[i]);
/* This does the right thing for -1: NULL */ /* This does the right thing for -1: NULL */
last = get_dive(preexisting-1); last = get_dive(preexisting-1);
@ -251,11 +255,6 @@ int main(int argc, char **argv)
textdomain("subsurface"); textdomain("subsurface");
output_units = SI_units; output_units = SI_units;
subsurface_command_line_init(&argc, &argv);
parse_xml_init();
init_ui(&argc, &argv);
#if DEBUGFILE > 1 #if DEBUGFILE > 1
debugfile = stderr; debugfile = stderr;
#elif defined(DEBUGFILE) #elif defined(DEBUGFILE)
@ -265,6 +264,12 @@ int main(int argc, char **argv)
(debugfile = g_fopen(debugfilename, "w")) == NULL) (debugfile = g_fopen(debugfilename, "w")) == NULL)
printf("oh boy, can't create debugfile"); printf("oh boy, can't create debugfile");
#endif #endif
subsurface_command_line_init(&argc, &argv);
parse_xml_init();
init_ui(&argc, &argv);
for (i = 1; i < argc; i++) { for (i = 1; i < argc; i++) {
const char *a = argv[i]; const char *a = argv[i];