mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
gtk-gui.c: Move the download dialog related code to a new file
A new file download-dialog.c now contains all code related to the download dialog, which was previously defined in gtk-gui.c. Also, a new file callbacks-gtk.h now has two macros OPTIONCALLBACK, UNITCALLBACK shared only between download-dialog.c and gtk-gui.c. Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
parent
ac376ea379
commit
c4ae58d589
5 changed files with 505 additions and 485 deletions
7
Makefile
7
Makefile
|
@ -132,7 +132,7 @@ MSGOBJS=$(addprefix share/locale/,$(MSGLANGS:.po=.UTF-8/LC_MESSAGES/subsurface.m
|
||||||
|
|
||||||
OBJS = main.o dive.o time.o profile.o info.o equipment.o divelist.o deco.o planner.o \
|
OBJS = main.o dive.o time.o profile.o info.o equipment.o divelist.o deco.o planner.o \
|
||||||
parse-xml.o save-xml.o libdivecomputer.o print.o uemis.o uemis-downloader.o \
|
parse-xml.o save-xml.o libdivecomputer.o print.o uemis.o uemis-downloader.o \
|
||||||
gtk-gui.o statistics.o file.o cochran.o device.o $(OSSUPPORT).o $(RESFILE)
|
gtk-gui.o statistics.o file.o cochran.o device.o download-dialog.o $(OSSUPPORT).o $(RESFILE)
|
||||||
|
|
||||||
$(NAME): $(OBJS) $(MSGOBJS)
|
$(NAME): $(OBJS) $(MSGOBJS)
|
||||||
$(CC) $(LDFLAGS) -o $(NAME) $(OBJS) $(LIBS)
|
$(CC) $(LDFLAGS) -o $(NAME) $(OBJS) $(LIBS)
|
||||||
|
@ -250,12 +250,15 @@ deco.o: deco.c dive.h
|
||||||
planner.o: planner.c dive.h divelist.h display-gtk.h
|
planner.o: planner.c dive.h divelist.h display-gtk.h
|
||||||
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) -c planner.c
|
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) -c planner.c
|
||||||
|
|
||||||
|
download-dialog.o: download-dialog.c dive.h divelist.h display-gtk.h callbacks-gtk.h
|
||||||
|
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) -c download-dialog.c
|
||||||
|
|
||||||
libdivecomputer.o: libdivecomputer.c dive.h display.h display-gtk.h libdivecomputer.h device.h
|
libdivecomputer.o: libdivecomputer.c dive.h display.h display-gtk.h libdivecomputer.h device.h
|
||||||
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) $(XML2CFLAGS) \
|
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) $(XML2CFLAGS) \
|
||||||
$(LIBDIVECOMPUTERCFLAGS) \
|
$(LIBDIVECOMPUTERCFLAGS) \
|
||||||
-c libdivecomputer.c
|
-c libdivecomputer.c
|
||||||
|
|
||||||
gtk-gui.o: gtk-gui.c dive.h display.h divelist.h display-gtk.h libdivecomputer.h device.h Makefile
|
gtk-gui.o: gtk-gui.c dive.h display.h divelist.h display-gtk.h libdivecomputer.h device.h callbacks-gtk.h Makefile
|
||||||
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) $(GCONF2CFLAGS) $(XML2CFLAGS) \
|
$(CC) $(CFLAGS) $(GTK2CFLAGS) $(GLIB2CFLAGS) $(GCONF2CFLAGS) $(XML2CFLAGS) \
|
||||||
$(LIBDIVECOMPUTERCFLAGS) \
|
$(LIBDIVECOMPUTERCFLAGS) \
|
||||||
-DVERSION_STRING='"v$(VERSION)"' \
|
-DVERSION_STRING='"v$(VERSION)"' \
|
||||||
|
|
17
callbacks-gtk.h
Normal file
17
callbacks-gtk.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#define UNITCALLBACK(name, type, value) \
|
||||||
|
static void name(GtkWidget *w, gpointer data) \
|
||||||
|
{ \
|
||||||
|
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) \
|
||||||
|
prefs.units.type = value; \
|
||||||
|
update_screen(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPTIONCALLBACK(name, option) \
|
||||||
|
static void name(GtkWidget *w, gpointer data) \
|
||||||
|
{ \
|
||||||
|
GtkWidget **entry = data; \
|
||||||
|
option = GTK_TOGGLE_BUTTON(w)->active; \
|
||||||
|
update_screen(); \
|
||||||
|
if (entry) \
|
||||||
|
gtk_widget_set_sensitive(*entry, option);\
|
||||||
|
}
|
|
@ -32,19 +32,24 @@ extern void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar,
|
||||||
extern void quit(GtkWidget *w, gpointer data);
|
extern void quit(GtkWidget *w, gpointer data);
|
||||||
extern gboolean on_delete(GtkWidget* w, gpointer data);
|
extern gboolean on_delete(GtkWidget* w, gpointer data);
|
||||||
|
|
||||||
extern int is_default_dive_computer_device(const char *name);
|
|
||||||
|
|
||||||
extern const char *divelist_font;
|
extern const char *divelist_font;
|
||||||
extern void set_divelist_font(const char *);
|
extern void set_divelist_font(const char *);
|
||||||
|
|
||||||
extern void import_files(GtkWidget *, gpointer);
|
extern void import_files(GtkWidget *, gpointer);
|
||||||
|
extern void update_screen(void);
|
||||||
extern void download_dialog(GtkWidget *, gpointer);
|
extern void download_dialog(GtkWidget *, gpointer);
|
||||||
|
extern int is_default_dive_computer_device(const char *);
|
||||||
|
extern int is_default_dive_computer(const char *, const char *);
|
||||||
extern void add_dive_cb(GtkWidget *, gpointer);
|
extern void add_dive_cb(GtkWidget *, gpointer);
|
||||||
extern void report_error(GError* error);
|
extern void report_error(GError* error);
|
||||||
extern int process_ui_events(void);
|
extern int process_ui_events(void);
|
||||||
extern void update_progressbar(progressbar_t *progress, double value);
|
extern void update_progressbar(progressbar_t *progress, double value);
|
||||||
extern void update_progressbar_text(progressbar_t *progress, const char *text);
|
extern void update_progressbar_text(progressbar_t *progress, const char *text);
|
||||||
|
|
||||||
|
extern const char *default_dive_computer_vendor;
|
||||||
|
extern const char *default_dive_computer_product;
|
||||||
|
extern const char *default_dive_computer_device;
|
||||||
|
|
||||||
// info.c
|
// info.c
|
||||||
enum {
|
enum {
|
||||||
MATCH_EXACT,
|
MATCH_EXACT,
|
||||||
|
|
474
download-dialog.c
Normal file
474
download-dialog.c
Normal file
|
@ -0,0 +1,474 @@
|
||||||
|
#include <libintl.h>
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
#include "dive.h"
|
||||||
|
#include "divelist.h"
|
||||||
|
#include "display.h"
|
||||||
|
#include "display-gtk.h"
|
||||||
|
#include "callbacks-gtk.h"
|
||||||
|
#include "libdivecomputer.h"
|
||||||
|
|
||||||
|
const char *default_dive_computer_vendor;
|
||||||
|
const char *default_dive_computer_product;
|
||||||
|
const char *default_dive_computer_device;
|
||||||
|
|
||||||
|
static gboolean force_download;
|
||||||
|
static gboolean prefer_downloaded;
|
||||||
|
|
||||||
|
OPTIONCALLBACK(force_toggle, force_download)
|
||||||
|
OPTIONCALLBACK(prefer_dl_toggle, prefer_downloaded)
|
||||||
|
|
||||||
|
struct product {
|
||||||
|
const char *product;
|
||||||
|
dc_descriptor_t *descriptor;
|
||||||
|
struct product *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vendor {
|
||||||
|
const char *vendor;
|
||||||
|
struct product *productlist;
|
||||||
|
struct vendor *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mydescriptor {
|
||||||
|
const char *vendor;
|
||||||
|
const char *product;
|
||||||
|
dc_family_t type;
|
||||||
|
unsigned int model;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct vendor *dc_list;
|
||||||
|
|
||||||
|
static void render_dc_vendor(GtkCellLayout *cell,
|
||||||
|
GtkCellRenderer *renderer,
|
||||||
|
GtkTreeModel *model,
|
||||||
|
GtkTreeIter *iter,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
const char *vendor;
|
||||||
|
|
||||||
|
gtk_tree_model_get(model, iter, 0, &vendor, -1);
|
||||||
|
g_object_set(renderer, "text", vendor, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void render_dc_product(GtkCellLayout *cell,
|
||||||
|
GtkCellRenderer *renderer,
|
||||||
|
GtkTreeModel *model,
|
||||||
|
GtkTreeIter *iter,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
dc_descriptor_t *descriptor = NULL;
|
||||||
|
const char *product;
|
||||||
|
|
||||||
|
gtk_tree_model_get(model, iter, 0, &descriptor, -1);
|
||||||
|
product = dc_descriptor_get_product(descriptor);
|
||||||
|
g_object_set(renderer, "text", product, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_default_dive_computer(const char *vendor, const char *product)
|
||||||
|
{
|
||||||
|
return default_dive_computer_vendor && !strcmp(vendor, default_dive_computer_vendor) &&
|
||||||
|
default_dive_computer_product && !strcmp(product, default_dive_computer_product);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_default_dive_computer_device(const char *name)
|
||||||
|
{
|
||||||
|
return default_dive_computer_device && !strcmp(name, default_dive_computer_device);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_default_dive_computer(const char *vendor, const char *product)
|
||||||
|
{
|
||||||
|
if (!vendor || !*vendor)
|
||||||
|
return;
|
||||||
|
if (!product || !*product)
|
||||||
|
return;
|
||||||
|
if (is_default_dive_computer(vendor, product))
|
||||||
|
return;
|
||||||
|
if (default_dive_computer_vendor)
|
||||||
|
free((void *)default_dive_computer_vendor);
|
||||||
|
if (default_dive_computer_product)
|
||||||
|
free((void *)default_dive_computer_product);
|
||||||
|
default_dive_computer_vendor = strdup(vendor);
|
||||||
|
default_dive_computer_product = strdup(product);
|
||||||
|
subsurface_set_conf("dive_computer_vendor", vendor);
|
||||||
|
subsurface_set_conf("dive_computer_product", product);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_default_dive_computer_device(const char *name)
|
||||||
|
{
|
||||||
|
if (!name || !*name)
|
||||||
|
return;
|
||||||
|
if (is_default_dive_computer_device(name))
|
||||||
|
return;
|
||||||
|
if (default_dive_computer_device)
|
||||||
|
free((void *)default_dive_computer_device);
|
||||||
|
default_dive_computer_device = strdup(name);
|
||||||
|
subsurface_set_conf("dive_computer_device", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dive_computer_selector_changed(GtkWidget *combo, gpointer data)
|
||||||
|
{
|
||||||
|
GtkWidget *import, *button;
|
||||||
|
|
||||||
|
import = gtk_widget_get_ancestor(combo, GTK_TYPE_DIALOG);
|
||||||
|
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(import), GTK_RESPONSE_ACCEPT);
|
||||||
|
gtk_widget_set_sensitive(button, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkListStore **product_model;
|
||||||
|
static void dive_computer_vendor_changed(GtkComboBox *vendorcombo, GtkComboBox *productcombo)
|
||||||
|
{
|
||||||
|
int vendor = gtk_combo_box_get_active(vendorcombo);
|
||||||
|
gtk_combo_box_set_model(productcombo, GTK_TREE_MODEL(product_model[vendor + 1]));
|
||||||
|
gtk_combo_box_set_active(productcombo, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkWidget *import_dive_computer(device_data_t *data, GtkDialog *dialog)
|
||||||
|
{
|
||||||
|
GError *error;
|
||||||
|
GtkWidget *vbox, *info, *container, *label, *button;
|
||||||
|
|
||||||
|
/* HACK to simply include the Uemis Zurich in the list */
|
||||||
|
if (! strcmp(data->vendor, "Uemis") && ! strcmp(data->product, "Zurich")) {
|
||||||
|
error = uemis_download(data->devname, &data->progress, data->dialog, data->force_download);
|
||||||
|
} else {
|
||||||
|
error = do_import(data);
|
||||||
|
}
|
||||||
|
if (!error)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
button = gtk_dialog_get_widget_for_response(dialog, GTK_RESPONSE_ACCEPT);
|
||||||
|
gtk_button_set_use_stock(GTK_BUTTON(button), 0);
|
||||||
|
gtk_button_set_label(GTK_BUTTON(button), _("Retry"));
|
||||||
|
|
||||||
|
vbox = gtk_dialog_get_content_area(dialog);
|
||||||
|
|
||||||
|
info = gtk_info_bar_new();
|
||||||
|
container = gtk_info_bar_get_content_area(GTK_INFO_BAR(info));
|
||||||
|
label = gtk_label_new(error->message);
|
||||||
|
gtk_container_add(GTK_CONTAINER(container), label);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), info, FALSE, FALSE, 0);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* create a list of lists and keep the elements sorted */
|
||||||
|
static void add_dc(const char *vendor, const char *product, dc_descriptor_t *descriptor)
|
||||||
|
{
|
||||||
|
struct vendor *dcl = dc_list;
|
||||||
|
struct vendor **dclp = &dc_list;
|
||||||
|
struct product *pl, **plp;
|
||||||
|
|
||||||
|
if (!vendor || !product)
|
||||||
|
return;
|
||||||
|
while (dcl && strcmp(dcl->vendor, vendor) < 0) {
|
||||||
|
dclp = &dcl->next;
|
||||||
|
dcl = dcl->next;
|
||||||
|
}
|
||||||
|
if (!dcl || strcmp(dcl->vendor, vendor)) {
|
||||||
|
dcl = calloc(sizeof(struct vendor), 1);
|
||||||
|
dcl->next = *dclp;
|
||||||
|
*dclp = dcl;
|
||||||
|
dcl->vendor = strdup(vendor);
|
||||||
|
}
|
||||||
|
/* we now have a pointer to the requested vendor */
|
||||||
|
plp = &dcl->productlist;
|
||||||
|
pl = *plp;
|
||||||
|
while (pl && strcmp(pl->product, product) < 0) {
|
||||||
|
plp = &pl->next;
|
||||||
|
pl = pl->next;
|
||||||
|
}
|
||||||
|
if (!pl || strcmp(pl->product, product)) {
|
||||||
|
pl = calloc(sizeof(struct product), 1);
|
||||||
|
pl->next = *plp;
|
||||||
|
*plp = pl;
|
||||||
|
pl->product = strdup(product);
|
||||||
|
}
|
||||||
|
/* one would assume that the vendor / product combinations are unique,
|
||||||
|
* but that is not the case. At the time of this writing, there are two
|
||||||
|
* flavors of the Oceanic OC1 - but looking at the code in libdivecomputer
|
||||||
|
* they are handled exactly the same, so we ignore this issue for now
|
||||||
|
*
|
||||||
|
if (pl->descriptor && memcmp(pl->descriptor, descriptor, sizeof(struct mydescriptor)))
|
||||||
|
printf("duplicate entry with different descriptor for %s - %s\n", vendor, product);
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
pl->descriptor = descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill the vendors and create and fill the respective product stores; return the longest product name
|
||||||
|
* and also the indices of the default vendor / product */
|
||||||
|
static int fill_computer_list(GtkListStore *vendorstore, GtkListStore ***productstore, int *vendor_index, int *product_index)
|
||||||
|
{
|
||||||
|
int i, j, numvendor, width = 10;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
dc_iterator_t *iterator = NULL;
|
||||||
|
dc_descriptor_t *descriptor = NULL;
|
||||||
|
struct mydescriptor *mydescriptor;
|
||||||
|
struct vendor *dcl;
|
||||||
|
struct product *pl;
|
||||||
|
GtkListStore **pstores;
|
||||||
|
|
||||||
|
dc_descriptor_iterator(&iterator);
|
||||||
|
while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) {
|
||||||
|
const char *vendor = dc_descriptor_get_vendor(descriptor);
|
||||||
|
const char *product = dc_descriptor_get_product(descriptor);
|
||||||
|
add_dc(vendor, product, descriptor);
|
||||||
|
if (product && strlen(product) > width)
|
||||||
|
width = strlen(product);
|
||||||
|
}
|
||||||
|
dc_iterator_free(iterator);
|
||||||
|
/* and add the Uemis Zurich which we are handling internally
|
||||||
|
THIS IS A HACK as we magically have a data structure here that
|
||||||
|
happens to match a data structure that is internal to libdivecomputer;
|
||||||
|
this WILL BREAK if libdivecomputer changes the dc_descriptor struct...
|
||||||
|
eventually the UEMIS code needs to move into libdivecomputer, I guess */
|
||||||
|
mydescriptor = malloc(sizeof(struct mydescriptor));
|
||||||
|
mydescriptor->vendor = "Uemis";
|
||||||
|
mydescriptor->product = "Zurich";
|
||||||
|
mydescriptor->type = DC_FAMILY_NULL;
|
||||||
|
mydescriptor->model = 0;
|
||||||
|
add_dc("Uemis", "Zurich", (dc_descriptor_t *)mydescriptor);
|
||||||
|
dcl = dc_list;
|
||||||
|
numvendor = 0;
|
||||||
|
while (dcl) {
|
||||||
|
numvendor++;
|
||||||
|
dcl = dcl->next;
|
||||||
|
}
|
||||||
|
/* we need an extra vendor for the empty one */
|
||||||
|
numvendor += 1;
|
||||||
|
dcl = dc_list;
|
||||||
|
i = 0;
|
||||||
|
*vendor_index = *product_index = -1;
|
||||||
|
if (*productstore)
|
||||||
|
free(*productstore);
|
||||||
|
pstores = *productstore = malloc(numvendor * sizeof(GtkListStore *));
|
||||||
|
while (dcl) {
|
||||||
|
gtk_list_store_append(vendorstore, &iter);
|
||||||
|
gtk_list_store_set(vendorstore, &iter,
|
||||||
|
0, dcl->vendor,
|
||||||
|
-1);
|
||||||
|
pl = dcl->productlist;
|
||||||
|
pstores[i + 1] = gtk_list_store_new(1, G_TYPE_POINTER);
|
||||||
|
j = 0;
|
||||||
|
while (pl) {
|
||||||
|
gtk_list_store_append(pstores[i + 1], &iter);
|
||||||
|
gtk_list_store_set(pstores[i + 1], &iter,
|
||||||
|
0, pl->descriptor,
|
||||||
|
-1);
|
||||||
|
if (is_default_dive_computer(dcl->vendor, pl->product)) {
|
||||||
|
*vendor_index = i;
|
||||||
|
*product_index = j;
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
pl = pl->next;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
dcl = dcl->next;
|
||||||
|
}
|
||||||
|
/* now add the empty product list in case no vendor is selected */
|
||||||
|
pstores[0] = gtk_list_store_new(1, G_TYPE_POINTER);
|
||||||
|
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkComboBox *dive_computer_selector(GtkWidget *vbox)
|
||||||
|
{
|
||||||
|
GtkWidget *hbox, *vendor_combo_box, *product_combo_box, *frame;
|
||||||
|
GtkListStore *vendor_model;
|
||||||
|
GtkCellRenderer *vendor_renderer, *product_renderer;
|
||||||
|
int vendor_default_index, product_default_index, width;
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new(FALSE, 6);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
||||||
|
|
||||||
|
vendor_model = gtk_list_store_new(1, G_TYPE_POINTER);
|
||||||
|
|
||||||
|
width = fill_computer_list(vendor_model, &product_model, &vendor_default_index, &product_default_index);
|
||||||
|
|
||||||
|
frame = gtk_frame_new(_("Dive computer vendor and product"));
|
||||||
|
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3);
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new(FALSE, 6);
|
||||||
|
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
||||||
|
|
||||||
|
vendor_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(vendor_model));
|
||||||
|
product_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(product_model[vendor_default_index + 1]));
|
||||||
|
|
||||||
|
g_signal_connect(G_OBJECT(vendor_combo_box), "changed", G_CALLBACK(dive_computer_vendor_changed), product_combo_box);
|
||||||
|
g_signal_connect(G_OBJECT(product_combo_box), "changed", G_CALLBACK(dive_computer_selector_changed), NULL);
|
||||||
|
gtk_box_pack_start(GTK_BOX(hbox), vendor_combo_box, FALSE, FALSE, 3);
|
||||||
|
gtk_box_pack_start(GTK_BOX(hbox), product_combo_box, FALSE, FALSE, 3);
|
||||||
|
|
||||||
|
vendor_renderer = gtk_cell_renderer_text_new();
|
||||||
|
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(vendor_combo_box), vendor_renderer, TRUE);
|
||||||
|
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(vendor_combo_box), vendor_renderer, render_dc_vendor, NULL, NULL);
|
||||||
|
|
||||||
|
product_renderer = gtk_cell_renderer_text_new();
|
||||||
|
gtk_cell_renderer_set_fixed_size(product_renderer, 10 * width, -1);
|
||||||
|
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(product_combo_box), product_renderer, TRUE);
|
||||||
|
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(product_combo_box), product_renderer, render_dc_product, NULL, NULL);
|
||||||
|
|
||||||
|
gtk_combo_box_set_active(GTK_COMBO_BOX(vendor_combo_box), vendor_default_index);
|
||||||
|
gtk_combo_box_set_active(GTK_COMBO_BOX(product_combo_box), product_default_index);
|
||||||
|
|
||||||
|
return GTK_COMBO_BOX(product_combo_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GtkComboBox *dc_device_selector(GtkWidget *vbox)
|
||||||
|
{
|
||||||
|
GtkWidget *hbox, *combo_box, *frame;
|
||||||
|
GtkListStore *model;
|
||||||
|
GtkCellRenderer *renderer;
|
||||||
|
int default_index;
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new(FALSE, 6);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
||||||
|
|
||||||
|
model = gtk_list_store_new(1, G_TYPE_STRING);
|
||||||
|
default_index = subsurface_fill_device_list(model);
|
||||||
|
|
||||||
|
frame = gtk_frame_new(_("Device or mount point"));
|
||||||
|
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3);
|
||||||
|
|
||||||
|
combo_box = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(model), 0);
|
||||||
|
gtk_container_add(GTK_CONTAINER(frame), combo_box);
|
||||||
|
|
||||||
|
renderer = gtk_cell_renderer_text_new();
|
||||||
|
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE);
|
||||||
|
|
||||||
|
if (default_index != -1)
|
||||||
|
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), default_index);
|
||||||
|
else
|
||||||
|
if (default_dive_computer_device)
|
||||||
|
gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo_box))),
|
||||||
|
default_dive_computer_device);
|
||||||
|
|
||||||
|
return GTK_COMBO_BOX(combo_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this prevents clicking the [x] button, while the import thread is still running */
|
||||||
|
static void download_dialog_delete(GtkWidget *w, gpointer data)
|
||||||
|
{
|
||||||
|
/* a no-op */
|
||||||
|
}
|
||||||
|
|
||||||
|
void download_dialog(GtkWidget *w, gpointer data)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
char *devname, *ns, *ne;
|
||||||
|
GtkWidget *dialog, *button, *hbox, *vbox, *label, *info = NULL;
|
||||||
|
GtkComboBox *computer, *device;
|
||||||
|
GtkTreeIter iter;
|
||||||
|
device_data_t devicedata = {
|
||||||
|
.devname = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
remember_tree_state();
|
||||||
|
dialog = gtk_dialog_new_with_buttons(_("Download From Dive Computer"),
|
||||||
|
GTK_WINDOW(main_window),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||||
|
NULL);
|
||||||
|
g_signal_connect(dialog, "delete-event", G_CALLBACK(download_dialog_delete), NULL);
|
||||||
|
|
||||||
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||||
|
label = gtk_label_new(_(" Please select dive computer and device. "));
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
|
||||||
|
computer = dive_computer_selector(vbox);
|
||||||
|
device = dc_device_selector(vbox);
|
||||||
|
hbox = gtk_hbox_new(FALSE, 6);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 3);
|
||||||
|
devicedata.progress.bar = gtk_progress_bar_new();
|
||||||
|
gtk_container_add(GTK_CONTAINER(hbox), devicedata.progress.bar);
|
||||||
|
|
||||||
|
force_download = FALSE;
|
||||||
|
button = gtk_check_button_new_with_label(_("Force download of all dives"));
|
||||||
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 6);
|
||||||
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(force_toggle), NULL);
|
||||||
|
|
||||||
|
prefer_downloaded = FALSE;
|
||||||
|
button = gtk_check_button_new_with_label(_("Always prefer downloaded dive"));
|
||||||
|
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
|
||||||
|
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 6);
|
||||||
|
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(prefer_dl_toggle), NULL);
|
||||||
|
|
||||||
|
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
|
||||||
|
if (!gtk_combo_box_get_active_iter(computer, &iter))
|
||||||
|
gtk_widget_set_sensitive(button, FALSE);
|
||||||
|
|
||||||
|
repeat:
|
||||||
|
gtk_widget_show_all(dialog);
|
||||||
|
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
||||||
|
switch (result) {
|
||||||
|
dc_descriptor_t *descriptor;
|
||||||
|
GtkTreeModel *model;
|
||||||
|
|
||||||
|
case GTK_RESPONSE_ACCEPT:
|
||||||
|
/* once the accept event is triggered the dialog becomes non-modal.
|
||||||
|
* lets re-set that */
|
||||||
|
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
|
||||||
|
if (info)
|
||||||
|
gtk_widget_destroy(info);
|
||||||
|
const char *vendor, *product;
|
||||||
|
|
||||||
|
if (!gtk_combo_box_get_active_iter(computer, &iter))
|
||||||
|
break;
|
||||||
|
|
||||||
|
model = gtk_combo_box_get_model(computer);
|
||||||
|
gtk_tree_model_get(model, &iter,
|
||||||
|
0, &descriptor,
|
||||||
|
-1);
|
||||||
|
|
||||||
|
vendor = dc_descriptor_get_vendor(descriptor);
|
||||||
|
product = dc_descriptor_get_product(descriptor);
|
||||||
|
|
||||||
|
devicedata.descriptor = descriptor;
|
||||||
|
devicedata.vendor = vendor;
|
||||||
|
devicedata.product = product;
|
||||||
|
set_default_dive_computer(vendor, product);
|
||||||
|
|
||||||
|
/* get the device name from the combo box entry and set as default */
|
||||||
|
devname = strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(device)))));
|
||||||
|
set_default_dive_computer_device(devname);
|
||||||
|
/* clear leading and trailing white space from the device name and also
|
||||||
|
* everything after (and including) the first '(' char. */
|
||||||
|
ns = devname;
|
||||||
|
while (*ns == ' ' || *ns == '\t')
|
||||||
|
ns++;
|
||||||
|
ne = ns;
|
||||||
|
while (*ne && *ne != '(')
|
||||||
|
ne++;
|
||||||
|
*ne = '\0';
|
||||||
|
if (ne > ns)
|
||||||
|
while (*(--ne) == ' ' || *ne == '\t')
|
||||||
|
*ne = '\0';
|
||||||
|
devicedata.devname = ns;
|
||||||
|
devicedata.dialog = GTK_DIALOG(dialog);
|
||||||
|
devicedata.force_download = force_download;
|
||||||
|
force_download = FALSE; /* when retrying we don't want to restart */
|
||||||
|
info = import_dive_computer(&devicedata, GTK_DIALOG(dialog));
|
||||||
|
free((void *)devname);
|
||||||
|
if (info)
|
||||||
|
goto repeat;
|
||||||
|
report_dives(TRUE, prefer_downloaded);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* it's possible that some dives were downloaded */
|
||||||
|
report_dives(TRUE, prefer_downloaded);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
restore_tree_state();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_progressbar(progressbar_t *progress, double value)
|
||||||
|
{
|
||||||
|
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress->bar), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_progressbar_text(progressbar_t *progress, const char *text)
|
||||||
|
{
|
||||||
|
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress->bar), text);
|
||||||
|
}
|
483
gtk-gui.c
483
gtk-gui.c
|
@ -18,6 +18,7 @@
|
||||||
#include "divelist.h"
|
#include "divelist.h"
|
||||||
#include "display.h"
|
#include "display.h"
|
||||||
#include "display-gtk.h"
|
#include "display-gtk.h"
|
||||||
|
#include "callbacks-gtk.h"
|
||||||
#include "uemis.h"
|
#include "uemis.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
|
@ -38,11 +39,6 @@ const char *default_filename;
|
||||||
char *nicknamestring;
|
char *nicknamestring;
|
||||||
|
|
||||||
static GtkWidget *dive_profile;
|
static GtkWidget *dive_profile;
|
||||||
static const char *default_dive_computer_vendor;
|
|
||||||
static const char *default_dive_computer_product;
|
|
||||||
static const char *default_dive_computer_device;
|
|
||||||
static gboolean force_download;
|
|
||||||
static gboolean prefer_downloaded;
|
|
||||||
|
|
||||||
GtkActionGroup *action_group;
|
GtkActionGroup *action_group;
|
||||||
|
|
||||||
|
@ -51,47 +47,6 @@ struct units *get_units()
|
||||||
return &prefs.units;
|
return &prefs.units;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_default_dive_computer(const char *vendor, const char *product)
|
|
||||||
{
|
|
||||||
return default_dive_computer_vendor && !strcmp(vendor, default_dive_computer_vendor) &&
|
|
||||||
default_dive_computer_product && !strcmp(product, default_dive_computer_product);
|
|
||||||
}
|
|
||||||
|
|
||||||
int is_default_dive_computer_device(const char *name)
|
|
||||||
{
|
|
||||||
return default_dive_computer_device && !strcmp(name, default_dive_computer_device);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_default_dive_computer(const char *vendor, const char *product)
|
|
||||||
{
|
|
||||||
if (!vendor || !*vendor)
|
|
||||||
return;
|
|
||||||
if (!product || !*product)
|
|
||||||
return;
|
|
||||||
if (is_default_dive_computer(vendor, product))
|
|
||||||
return;
|
|
||||||
if (default_dive_computer_vendor)
|
|
||||||
free((void *)default_dive_computer_vendor);
|
|
||||||
if (default_dive_computer_product)
|
|
||||||
free((void *)default_dive_computer_product);
|
|
||||||
default_dive_computer_vendor = strdup(vendor);
|
|
||||||
default_dive_computer_product = strdup(product);
|
|
||||||
subsurface_set_conf("dive_computer_vendor", vendor);
|
|
||||||
subsurface_set_conf("dive_computer_product", product);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void set_default_dive_computer_device(const char *name)
|
|
||||||
{
|
|
||||||
if (!name || !*name)
|
|
||||||
return;
|
|
||||||
if (is_default_dive_computer_device(name))
|
|
||||||
return;
|
|
||||||
if (default_dive_computer_device)
|
|
||||||
free((void *)default_dive_computer_device);
|
|
||||||
default_dive_computer_device = strdup(name);
|
|
||||||
subsurface_set_conf("dive_computer_device", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void repaint_dive(void)
|
void repaint_dive(void)
|
||||||
{
|
{
|
||||||
update_dive(current_dive);
|
update_dive(current_dive);
|
||||||
|
@ -457,21 +412,13 @@ static void create_radio(GtkWidget *vbox, const char *w_name, ...)
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_screen()
|
void update_screen()
|
||||||
{
|
{
|
||||||
update_dive_list_units();
|
update_dive_list_units();
|
||||||
repaint_dive();
|
repaint_dive();
|
||||||
update_dive_list_col_visibility();
|
update_dive_list_col_visibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UNITCALLBACK(name, type, value) \
|
|
||||||
static void name(GtkWidget *w, gpointer data) \
|
|
||||||
{ \
|
|
||||||
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) \
|
|
||||||
prefs.units.type = value; \
|
|
||||||
update_screen(); \
|
|
||||||
}
|
|
||||||
|
|
||||||
UNITCALLBACK(set_meter, length, METERS)
|
UNITCALLBACK(set_meter, length, METERS)
|
||||||
UNITCALLBACK(set_feet, length, FEET)
|
UNITCALLBACK(set_feet, length, FEET)
|
||||||
UNITCALLBACK(set_bar, pressure, BAR)
|
UNITCALLBACK(set_bar, pressure, BAR)
|
||||||
|
@ -483,16 +430,6 @@ UNITCALLBACK(set_fahrenheit, temperature, FAHRENHEIT)
|
||||||
UNITCALLBACK(set_kg, weight, KG)
|
UNITCALLBACK(set_kg, weight, KG)
|
||||||
UNITCALLBACK(set_lbs, weight, LBS)
|
UNITCALLBACK(set_lbs, weight, LBS)
|
||||||
|
|
||||||
#define OPTIONCALLBACK(name, option) \
|
|
||||||
static void name(GtkWidget *w, gpointer data) \
|
|
||||||
{ \
|
|
||||||
GtkWidget **entry = data; \
|
|
||||||
option = GTK_TOGGLE_BUTTON(w)->active; \
|
|
||||||
update_screen(); \
|
|
||||||
if (entry) \
|
|
||||||
gtk_widget_set_sensitive(*entry, option);\
|
|
||||||
}
|
|
||||||
|
|
||||||
OPTIONCALLBACK(otu_toggle, prefs.visible_cols.otu)
|
OPTIONCALLBACK(otu_toggle, prefs.visible_cols.otu)
|
||||||
OPTIONCALLBACK(maxcns_toggle, prefs.visible_cols.maxcns)
|
OPTIONCALLBACK(maxcns_toggle, prefs.visible_cols.maxcns)
|
||||||
OPTIONCALLBACK(sac_toggle, prefs.visible_cols.sac)
|
OPTIONCALLBACK(sac_toggle, prefs.visible_cols.sac)
|
||||||
|
@ -507,8 +444,6 @@ OPTIONCALLBACK(phe_toggle, prefs.pp_graphs.phe)
|
||||||
OPTIONCALLBACK(red_ceiling_toggle, prefs.profile_red_ceiling)
|
OPTIONCALLBACK(red_ceiling_toggle, prefs.profile_red_ceiling)
|
||||||
OPTIONCALLBACK(calc_ceiling_toggle, prefs.profile_calc_ceiling)
|
OPTIONCALLBACK(calc_ceiling_toggle, prefs.profile_calc_ceiling)
|
||||||
OPTIONCALLBACK(calc_ceiling_3m_toggle, prefs.calc_ceiling_3m_incr)
|
OPTIONCALLBACK(calc_ceiling_3m_toggle, prefs.calc_ceiling_3m_incr)
|
||||||
OPTIONCALLBACK(force_toggle, force_download)
|
|
||||||
OPTIONCALLBACK(prefer_dl_toggle, prefer_downloaded)
|
|
||||||
|
|
||||||
static gboolean gflow_edit(GtkWidget *w, GdkEvent *event, gpointer _data)
|
static gboolean gflow_edit(GtkWidget *w, GdkEvent *event, gpointer _data)
|
||||||
{
|
{
|
||||||
|
@ -1718,265 +1653,6 @@ int process_ui_events(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vendor {
|
|
||||||
const char *vendor;
|
|
||||||
struct product *productlist;
|
|
||||||
struct vendor *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct product {
|
|
||||||
const char *product;
|
|
||||||
dc_descriptor_t *descriptor;
|
|
||||||
struct product *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vendor *dc_list;
|
|
||||||
|
|
||||||
struct mydescriptor {
|
|
||||||
const char *vendor;
|
|
||||||
const char *product;
|
|
||||||
dc_family_t type;
|
|
||||||
unsigned int model;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* create a list of lists and keep the elements sorted */
|
|
||||||
static void add_dc(const char *vendor, const char *product, dc_descriptor_t *descriptor)
|
|
||||||
{
|
|
||||||
struct vendor *dcl = dc_list;
|
|
||||||
struct vendor **dclp = &dc_list;
|
|
||||||
struct product *pl, **plp;
|
|
||||||
|
|
||||||
if (!vendor || !product)
|
|
||||||
return;
|
|
||||||
while (dcl && strcmp(dcl->vendor, vendor) < 0) {
|
|
||||||
dclp = &dcl->next;
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
if (!dcl || strcmp(dcl->vendor, vendor)) {
|
|
||||||
dcl = calloc(sizeof(struct vendor), 1);
|
|
||||||
dcl->next = *dclp;
|
|
||||||
*dclp = dcl;
|
|
||||||
dcl->vendor = strdup(vendor);
|
|
||||||
}
|
|
||||||
/* we now have a pointer to the requested vendor */
|
|
||||||
plp = &dcl->productlist;
|
|
||||||
pl = *plp;
|
|
||||||
while (pl && strcmp(pl->product, product) < 0) {
|
|
||||||
plp = &pl->next;
|
|
||||||
pl = pl->next;
|
|
||||||
}
|
|
||||||
if (!pl || strcmp(pl->product, product)) {
|
|
||||||
pl = calloc(sizeof(struct product), 1);
|
|
||||||
pl->next = *plp;
|
|
||||||
*plp = pl;
|
|
||||||
pl->product = strdup(product);
|
|
||||||
}
|
|
||||||
/* one would assume that the vendor / product combinations are unique,
|
|
||||||
* but that is not the case. At the time of this writing, there are two
|
|
||||||
* flavors of the Oceanic OC1 - but looking at the code in libdivecomputer
|
|
||||||
* they are handled exactly the same, so we ignore this issue for now
|
|
||||||
*
|
|
||||||
if (pl->descriptor && memcmp(pl->descriptor, descriptor, sizeof(struct mydescriptor)))
|
|
||||||
printf("duplicate entry with different descriptor for %s - %s\n", vendor, product);
|
|
||||||
else
|
|
||||||
*/
|
|
||||||
pl->descriptor = descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fill the vendors and create and fill the respective product stores; return the longest product name
|
|
||||||
* and also the indices of the default vendor / product */
|
|
||||||
static int fill_computer_list(GtkListStore *vendorstore, GtkListStore ***productstore, int *vendor_index, int *product_index)
|
|
||||||
{
|
|
||||||
int i, j, numvendor, width = 10;
|
|
||||||
GtkTreeIter iter;
|
|
||||||
dc_iterator_t *iterator = NULL;
|
|
||||||
dc_descriptor_t *descriptor = NULL;
|
|
||||||
struct mydescriptor *mydescriptor;
|
|
||||||
struct vendor *dcl;
|
|
||||||
struct product *pl;
|
|
||||||
GtkListStore **pstores;
|
|
||||||
|
|
||||||
dc_descriptor_iterator(&iterator);
|
|
||||||
while (dc_iterator_next (iterator, &descriptor) == DC_STATUS_SUCCESS) {
|
|
||||||
const char *vendor = dc_descriptor_get_vendor(descriptor);
|
|
||||||
const char *product = dc_descriptor_get_product(descriptor);
|
|
||||||
add_dc(vendor, product, descriptor);
|
|
||||||
if (product && strlen(product) > width)
|
|
||||||
width = strlen(product);
|
|
||||||
}
|
|
||||||
dc_iterator_free(iterator);
|
|
||||||
/* and add the Uemis Zurich which we are handling internally
|
|
||||||
THIS IS A HACK as we magically have a data structure here that
|
|
||||||
happens to match a data structure that is internal to libdivecomputer;
|
|
||||||
this WILL BREAK if libdivecomputer changes the dc_descriptor struct...
|
|
||||||
eventually the UEMIS code needs to move into libdivecomputer, I guess */
|
|
||||||
mydescriptor = malloc(sizeof(struct mydescriptor));
|
|
||||||
mydescriptor->vendor = "Uemis";
|
|
||||||
mydescriptor->product = "Zurich";
|
|
||||||
mydescriptor->type = DC_FAMILY_NULL;
|
|
||||||
mydescriptor->model = 0;
|
|
||||||
add_dc("Uemis", "Zurich", (dc_descriptor_t *)mydescriptor);
|
|
||||||
dcl = dc_list;
|
|
||||||
numvendor = 0;
|
|
||||||
while (dcl) {
|
|
||||||
numvendor++;
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
/* we need an extra vendor for the empty one */
|
|
||||||
numvendor += 1;
|
|
||||||
dcl = dc_list;
|
|
||||||
i = 0;
|
|
||||||
*vendor_index = *product_index = -1;
|
|
||||||
if (*productstore)
|
|
||||||
free(*productstore);
|
|
||||||
pstores = *productstore = malloc(numvendor * sizeof(GtkListStore *));
|
|
||||||
while (dcl) {
|
|
||||||
gtk_list_store_append(vendorstore, &iter);
|
|
||||||
gtk_list_store_set(vendorstore, &iter,
|
|
||||||
0, dcl->vendor,
|
|
||||||
-1);
|
|
||||||
pl = dcl->productlist;
|
|
||||||
pstores[i + 1] = gtk_list_store_new(1, G_TYPE_POINTER);
|
|
||||||
j = 0;
|
|
||||||
while (pl) {
|
|
||||||
gtk_list_store_append(pstores[i + 1], &iter);
|
|
||||||
gtk_list_store_set(pstores[i + 1], &iter,
|
|
||||||
0, pl->descriptor,
|
|
||||||
-1);
|
|
||||||
if (is_default_dive_computer(dcl->vendor, pl->product)) {
|
|
||||||
*vendor_index = i;
|
|
||||||
*product_index = j;
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
pl = pl->next;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
dcl = dcl->next;
|
|
||||||
}
|
|
||||||
/* now add the empty product list in case no vendor is selected */
|
|
||||||
pstores[0] = gtk_list_store_new(1, G_TYPE_POINTER);
|
|
||||||
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
void render_dc_vendor(GtkCellLayout *cell,
|
|
||||||
GtkCellRenderer *renderer,
|
|
||||||
GtkTreeModel *model,
|
|
||||||
GtkTreeIter *iter,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
const char *vendor;
|
|
||||||
|
|
||||||
gtk_tree_model_get(model, iter, 0, &vendor, -1);
|
|
||||||
g_object_set(renderer, "text", vendor, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void render_dc_product(GtkCellLayout *cell,
|
|
||||||
GtkCellRenderer *renderer,
|
|
||||||
GtkTreeModel *model,
|
|
||||||
GtkTreeIter *iter,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
dc_descriptor_t *descriptor = NULL;
|
|
||||||
const char *product;
|
|
||||||
|
|
||||||
gtk_tree_model_get(model, iter, 0, &descriptor, -1);
|
|
||||||
product = dc_descriptor_get_product(descriptor);
|
|
||||||
g_object_set(renderer, "text", product, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dive_computer_selector_changed(GtkWidget *combo, gpointer data)
|
|
||||||
{
|
|
||||||
GtkWidget *import, *button;
|
|
||||||
|
|
||||||
import = gtk_widget_get_ancestor(combo, GTK_TYPE_DIALOG);
|
|
||||||
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(import), GTK_RESPONSE_ACCEPT);
|
|
||||||
gtk_widget_set_sensitive(button, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GtkListStore **product_model;
|
|
||||||
static void dive_computer_vendor_changed(GtkComboBox *vendorcombo, GtkComboBox *productcombo)
|
|
||||||
{
|
|
||||||
int vendor = gtk_combo_box_get_active(vendorcombo);
|
|
||||||
gtk_combo_box_set_model(productcombo, GTK_TREE_MODEL(product_model[vendor + 1]));
|
|
||||||
gtk_combo_box_set_active(productcombo, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GtkComboBox *dive_computer_selector(GtkWidget *vbox)
|
|
||||||
{
|
|
||||||
GtkWidget *hbox, *vendor_combo_box, *product_combo_box, *frame;
|
|
||||||
GtkListStore *vendor_model;
|
|
||||||
GtkCellRenderer *vendor_renderer, *product_renderer;
|
|
||||||
int vendor_default_index, product_default_index, width;
|
|
||||||
|
|
||||||
hbox = gtk_hbox_new(FALSE, 6);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
|
||||||
|
|
||||||
vendor_model = gtk_list_store_new(1, G_TYPE_POINTER);
|
|
||||||
|
|
||||||
width = fill_computer_list(vendor_model, &product_model, &vendor_default_index, &product_default_index);
|
|
||||||
|
|
||||||
frame = gtk_frame_new(_("Dive computer vendor and product"));
|
|
||||||
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3);
|
|
||||||
|
|
||||||
hbox = gtk_hbox_new(FALSE, 6);
|
|
||||||
gtk_container_add(GTK_CONTAINER(frame), hbox);
|
|
||||||
|
|
||||||
vendor_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(vendor_model));
|
|
||||||
product_combo_box = gtk_combo_box_new_with_model(GTK_TREE_MODEL(product_model[vendor_default_index + 1]));
|
|
||||||
|
|
||||||
g_signal_connect(G_OBJECT(vendor_combo_box), "changed", G_CALLBACK(dive_computer_vendor_changed), product_combo_box);
|
|
||||||
g_signal_connect(G_OBJECT(product_combo_box), "changed", G_CALLBACK(dive_computer_selector_changed), NULL);
|
|
||||||
gtk_box_pack_start(GTK_BOX(hbox), vendor_combo_box, FALSE, FALSE, 3);
|
|
||||||
gtk_box_pack_start(GTK_BOX(hbox), product_combo_box, FALSE, FALSE, 3);
|
|
||||||
|
|
||||||
vendor_renderer = gtk_cell_renderer_text_new();
|
|
||||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(vendor_combo_box), vendor_renderer, TRUE);
|
|
||||||
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(vendor_combo_box), vendor_renderer, render_dc_vendor, NULL, NULL);
|
|
||||||
|
|
||||||
product_renderer = gtk_cell_renderer_text_new();
|
|
||||||
gtk_cell_renderer_set_fixed_size(product_renderer, 10 * width, -1);
|
|
||||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(product_combo_box), product_renderer, TRUE);
|
|
||||||
gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(product_combo_box), product_renderer, render_dc_product, NULL, NULL);
|
|
||||||
|
|
||||||
gtk_combo_box_set_active(GTK_COMBO_BOX(vendor_combo_box), vendor_default_index);
|
|
||||||
gtk_combo_box_set_active(GTK_COMBO_BOX(product_combo_box), product_default_index);
|
|
||||||
|
|
||||||
return GTK_COMBO_BOX(product_combo_box);
|
|
||||||
}
|
|
||||||
|
|
||||||
static GtkComboBox *dc_device_selector(GtkWidget *vbox)
|
|
||||||
{
|
|
||||||
GtkWidget *hbox, *combo_box, *frame;
|
|
||||||
GtkListStore *model;
|
|
||||||
GtkCellRenderer *renderer;
|
|
||||||
int default_index;
|
|
||||||
|
|
||||||
hbox = gtk_hbox_new(FALSE, 6);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3);
|
|
||||||
|
|
||||||
model = gtk_list_store_new(1, G_TYPE_STRING);
|
|
||||||
default_index = subsurface_fill_device_list(model);
|
|
||||||
|
|
||||||
frame = gtk_frame_new(_("Device or mount point"));
|
|
||||||
gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3);
|
|
||||||
|
|
||||||
combo_box = gtk_combo_box_entry_new_with_model(GTK_TREE_MODEL(model), 0);
|
|
||||||
gtk_container_add(GTK_CONTAINER(frame), combo_box);
|
|
||||||
|
|
||||||
renderer = gtk_cell_renderer_text_new();
|
|
||||||
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box), renderer, TRUE);
|
|
||||||
|
|
||||||
if (default_index != -1)
|
|
||||||
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box), default_index);
|
|
||||||
else
|
|
||||||
if (default_dive_computer_device)
|
|
||||||
gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(combo_box))),
|
|
||||||
default_dive_computer_device);
|
|
||||||
|
|
||||||
return GTK_COMBO_BOX(combo_box);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void do_import_file(gpointer data, gpointer user_data)
|
static void do_import_file(gpointer data, gpointer user_data)
|
||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
|
@ -2041,161 +1717,6 @@ void import_files(GtkWidget *w, gpointer data)
|
||||||
restore_tree_state();
|
restore_tree_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
static GtkWidget *import_dive_computer(device_data_t *data, GtkDialog *dialog)
|
|
||||||
{
|
|
||||||
GError *error;
|
|
||||||
GtkWidget *vbox, *info, *container, *label, *button;
|
|
||||||
|
|
||||||
/* HACK to simply include the Uemis Zurich in the list */
|
|
||||||
if (! strcmp(data->vendor, "Uemis") && ! strcmp(data->product, "Zurich")) {
|
|
||||||
error = uemis_download(data->devname, &data->progress, data->dialog, data->force_download);
|
|
||||||
} else {
|
|
||||||
error = do_import(data);
|
|
||||||
}
|
|
||||||
if (!error)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
button = gtk_dialog_get_widget_for_response(dialog, GTK_RESPONSE_ACCEPT);
|
|
||||||
gtk_button_set_use_stock(GTK_BUTTON(button), 0);
|
|
||||||
gtk_button_set_label(GTK_BUTTON(button), _("Retry"));
|
|
||||||
|
|
||||||
vbox = gtk_dialog_get_content_area(dialog);
|
|
||||||
|
|
||||||
info = gtk_info_bar_new();
|
|
||||||
container = gtk_info_bar_get_content_area(GTK_INFO_BAR(info));
|
|
||||||
label = gtk_label_new(error->message);
|
|
||||||
gtk_container_add(GTK_CONTAINER(container), label);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), info, FALSE, FALSE, 0);
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* this prevents clicking the [x] button, while the import thread is still running */
|
|
||||||
static void download_dialog_delete(GtkWidget *w, gpointer data)
|
|
||||||
{
|
|
||||||
/* a no-op */
|
|
||||||
}
|
|
||||||
|
|
||||||
void download_dialog(GtkWidget *w, gpointer data)
|
|
||||||
{
|
|
||||||
int result;
|
|
||||||
char *devname, *ns, *ne;
|
|
||||||
GtkWidget *dialog, *button, *hbox, *vbox, *label, *info = NULL;
|
|
||||||
GtkComboBox *computer, *device;
|
|
||||||
GtkTreeIter iter;
|
|
||||||
device_data_t devicedata = {
|
|
||||||
.devname = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
remember_tree_state();
|
|
||||||
dialog = gtk_dialog_new_with_buttons(_("Download From Dive Computer"),
|
|
||||||
GTK_WINDOW(main_window),
|
|
||||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
||||||
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
|
||||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
||||||
NULL);
|
|
||||||
g_signal_connect(dialog, "delete-event", G_CALLBACK(download_dialog_delete), NULL);
|
|
||||||
|
|
||||||
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
|
||||||
label = gtk_label_new(_(" Please select dive computer and device. "));
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3);
|
|
||||||
computer = dive_computer_selector(vbox);
|
|
||||||
device = dc_device_selector(vbox);
|
|
||||||
hbox = gtk_hbox_new(FALSE, 6);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 3);
|
|
||||||
devicedata.progress.bar = gtk_progress_bar_new();
|
|
||||||
gtk_container_add(GTK_CONTAINER(hbox), devicedata.progress.bar);
|
|
||||||
|
|
||||||
force_download = FALSE;
|
|
||||||
button = gtk_check_button_new_with_label(_("Force download of all dives"));
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 6);
|
|
||||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(force_toggle), NULL);
|
|
||||||
|
|
||||||
prefer_downloaded = FALSE;
|
|
||||||
button = gtk_check_button_new_with_label(_("Always prefer downloaded dive"));
|
|
||||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), FALSE);
|
|
||||||
gtk_box_pack_start(GTK_BOX(vbox), button, FALSE, FALSE, 6);
|
|
||||||
g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(prefer_dl_toggle), NULL);
|
|
||||||
|
|
||||||
button = gtk_dialog_get_widget_for_response(GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT);
|
|
||||||
if (!gtk_combo_box_get_active_iter(computer, &iter))
|
|
||||||
gtk_widget_set_sensitive(button, FALSE);
|
|
||||||
|
|
||||||
repeat:
|
|
||||||
gtk_widget_show_all(dialog);
|
|
||||||
result = gtk_dialog_run(GTK_DIALOG(dialog));
|
|
||||||
switch (result) {
|
|
||||||
dc_descriptor_t *descriptor;
|
|
||||||
GtkTreeModel *model;
|
|
||||||
|
|
||||||
case GTK_RESPONSE_ACCEPT:
|
|
||||||
/* once the accept event is triggered the dialog becomes non-modal.
|
|
||||||
* lets re-set that */
|
|
||||||
gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
|
|
||||||
if (info)
|
|
||||||
gtk_widget_destroy(info);
|
|
||||||
const char *vendor, *product;
|
|
||||||
|
|
||||||
if (!gtk_combo_box_get_active_iter(computer, &iter))
|
|
||||||
break;
|
|
||||||
|
|
||||||
model = gtk_combo_box_get_model(computer);
|
|
||||||
gtk_tree_model_get(model, &iter,
|
|
||||||
0, &descriptor,
|
|
||||||
-1);
|
|
||||||
|
|
||||||
vendor = dc_descriptor_get_vendor(descriptor);
|
|
||||||
product = dc_descriptor_get_product(descriptor);
|
|
||||||
|
|
||||||
devicedata.descriptor = descriptor;
|
|
||||||
devicedata.vendor = vendor;
|
|
||||||
devicedata.product = product;
|
|
||||||
set_default_dive_computer(vendor, product);
|
|
||||||
|
|
||||||
/* get the device name from the combo box entry and set as default */
|
|
||||||
devname = strdup(gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(device)))));
|
|
||||||
set_default_dive_computer_device(devname);
|
|
||||||
/* clear leading and trailing white space from the device name and also
|
|
||||||
* everything after (and including) the first '(' char. */
|
|
||||||
ns = devname;
|
|
||||||
while (*ns == ' ' || *ns == '\t')
|
|
||||||
ns++;
|
|
||||||
ne = ns;
|
|
||||||
while (*ne && *ne != '(')
|
|
||||||
ne++;
|
|
||||||
*ne = '\0';
|
|
||||||
if (ne > ns)
|
|
||||||
while (*(--ne) == ' ' || *ne == '\t')
|
|
||||||
*ne = '\0';
|
|
||||||
devicedata.devname = ns;
|
|
||||||
devicedata.dialog = GTK_DIALOG(dialog);
|
|
||||||
devicedata.force_download = force_download;
|
|
||||||
force_download = FALSE; /* when retrying we don't want to restart */
|
|
||||||
info = import_dive_computer(&devicedata, GTK_DIALOG(dialog));
|
|
||||||
free((void *)devname);
|
|
||||||
if (info)
|
|
||||||
goto repeat;
|
|
||||||
report_dives(TRUE, prefer_downloaded);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* it's possible that some dives were downloaded */
|
|
||||||
report_dives(TRUE, prefer_downloaded);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
gtk_widget_destroy(dialog);
|
|
||||||
restore_tree_state();
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_progressbar(progressbar_t *progress, double value)
|
|
||||||
{
|
|
||||||
gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progress->bar), value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void update_progressbar_text(progressbar_t *progress, const char *text)
|
|
||||||
{
|
|
||||||
gtk_progress_bar_set_text(GTK_PROGRESS_BAR(progress->bar), text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_filename(const char *filename, gboolean force)
|
void set_filename(const char *filename, gboolean force)
|
||||||
{
|
{
|
||||||
if (!force && existing_filename)
|
if (!force && existing_filename)
|
||||||
|
|
Loading…
Reference in a new issue