X-Git-Url: http://git.tdb.fi/?p=ext%2Fsubsurface.git;a=blobdiff_plain;f=main.c;h=2489473b9c2f9fe43f65c4ce0405fba3b79e7cc6;hp=d125169e2898150bdddc46dd16a21a039ee0ee13;hb=HEAD;hpb=15e3b5f4414d320dbace1bd3913b07d35bd9e9ee diff --git a/main.c b/main.c index d125169..2489473 100644 --- a/main.c +++ b/main.c @@ -1,25 +1,15 @@ +/* main.c */ #include #include #include #include -#include - #include "dive.h" #include "divelist.h" -#include "display.h" - -GtkWidget *main_window; -GtkWidget *main_vbox; -GtkWidget *error_info_bar; -GtkWidget *error_label; -int error_count; -GConfClient *gconf; struct units output_units; -#define GCONF_NAME(x) "/apps/subsurface/" #x - +/* random helper functions, used here or elsewhere */ static int sortfn(const void *_a, const void *_b) { const struct dive *a = *(void **)_a; @@ -32,13 +22,93 @@ static int sortfn(const void *_a, const void *_b) return 0; } +const char *weekday(int wday) +{ + static const char wday_array[7][4] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + return wday_array[wday]; +} + +const char *monthname(int mon) +{ + static const char month_array[12][4] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + }; + return month_array[mon]; +} + +/* + * When adding dives to the dive table, we try to renumber + * the new dives based on any old dives in the dive table. + * + * But we only do it if: + * + * - the last dive in the old dive table was numbered + * + * - all the new dives are strictly at the end (so the + * "last dive" is at the same location in the dive table + * after re-sorting the dives. + * + * - none of the new dives have any numbers + * + * This catches the common case of importing new dives from + * a dive computer, and gives them proper numbers based on + * your old dive list. But it tries to be very conservative + * and not give numbers if there is *any* question about + * what the numbers should be - in which case you need to do + * a manual re-numbering. + */ +static void try_to_renumber(struct dive *last, int preexisting) +{ + int i, nr; + + /* + * If the new dives aren't all strictly at the end, + * we're going to expect the user to do a manual + * renumbering. + */ + if (get_dive(preexisting-1) != last) + return; + + /* + * If any of the new dives already had a number, + * we'll have to do a manual renumbering. + */ + for (i = preexisting; i < dive_table.nr; i++) { + struct dive *dive = get_dive(i); + if (dive->number) + return; + } + + /* + * Ok, renumber.. + */ + nr = last->number; + for (i = preexisting; i < dive_table.nr; i++) { + struct dive *dive = get_dive(i); + dive->number = ++nr; + } +} + +/* + * track whether we switched to importing dives + */ +static gboolean imported = FALSE; + /* * This doesn't really report anything at all. We just sort the * dives, the GUI does the reporting */ -void report_dives(void) +void report_dives(gboolean is_imported) { int i; + int preexisting = dive_table.preexisting; + struct dive *last; + + /* This does the right thing for -1: NULL */ + last = get_dive(preexisting-1); qsort(dive_table.dives, dive_table.nr, sizeof(struct dive *), sortfn); @@ -64,6 +134,18 @@ void report_dives(void) /* Redo the new 'i'th dive */ i--; } + + if (is_imported) { + /* Was the previous dive table state numbered? */ + if (last && last->number) + try_to_renumber(last, preexisting); + + /* did we have dives in the table and added more? */ + if (last && preexisting != dive_table.nr) + mark_divelist_changed(TRUE); + } + dive_table.preexisting = dive_table.nr; + dive_list_update_dives(); } static void parse_argument(const char *arg) @@ -75,6 +157,22 @@ static void parse_argument(const char *arg) case 'v': verbose++; continue; + case '-': + /* long options with -- */ + if (strcmp(arg,"--import") == 0) { + /* mark the dives so far as the base, + * everything after is imported */ + report_dives(FALSE); + imported = TRUE; + return; + } + /* fallthrough */ + case 'p': + /* ignore process serial number argument when run as native macosx app */ + if (strncmp(arg, "-psn_", 5) == 0) { + return; + } + /* fallthrough */ default: fprintf(stderr, "Bad argument '%s'\n", arg); exit(1); @@ -82,415 +180,44 @@ static void parse_argument(const char *arg) } while (*++p); } -static void on_destroy(GtkWidget* w, gpointer data) -{ - gtk_main_quit(); -} - -static GtkWidget *dive_profile; - void update_dive(struct dive *new_dive) { static struct dive *buffered_dive; struct dive *old_dive = buffered_dive; if (old_dive) { - flush_dive_info_changes(old_dive); - flush_dive_equipment_changes(old_dive); flush_divelist(old_dive); } if (new_dive) { show_dive_info(new_dive); - show_dive_equipment(new_dive); + show_dive_equipment(new_dive, W_IDX_PRIMARY); + show_dive_stats(new_dive); } buffered_dive = new_dive; } -void repaint_dive(void) -{ - update_dive(current_dive); - gtk_widget_queue_draw(dive_profile); -} - -static char *existing_filename; - -static void on_info_bar_response(GtkWidget *widget, gint response, - gpointer data) -{ - if (response == GTK_RESPONSE_OK) - { - gtk_widget_destroy(widget); - error_info_bar = NULL; - } -} - -void report_error(GError* error) -{ - if (error == NULL) - { - return; - } - - if (error_info_bar == NULL) - { - error_count = 1; - error_info_bar = gtk_info_bar_new_with_buttons(GTK_STOCK_OK, - GTK_RESPONSE_OK, - NULL); - g_signal_connect(error_info_bar, "response", G_CALLBACK(on_info_bar_response), NULL); - gtk_info_bar_set_message_type(GTK_INFO_BAR(error_info_bar), - GTK_MESSAGE_ERROR); - - error_label = gtk_label_new(error->message); - GtkWidget *container = gtk_info_bar_get_content_area(GTK_INFO_BAR(error_info_bar)); - gtk_container_add(GTK_CONTAINER(container), error_label); - - gtk_box_pack_start(GTK_BOX(main_vbox), error_info_bar, FALSE, FALSE, 0); - gtk_widget_show_all(main_vbox); - } - else - { - error_count++; - char buffer[256]; - snprintf(buffer, sizeof(buffer), "Failed to open %i files.", error_count); - gtk_label_set(GTK_LABEL(error_label), buffer); - } -} - -static void file_open(GtkWidget *w, gpointer data) -{ - GtkWidget *dialog; - dialog = gtk_file_chooser_dialog_new("Open File", - GTK_WINDOW(main_window), - GTK_FILE_CHOOSER_ACTION_OPEN, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), TRUE); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - GSList *filenames; - char *filename; - filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); - - GError *error = NULL; - while(filenames != NULL) { - filename = (char *)filenames->data; - parse_xml_file(filename, &error); - if (error != NULL) - { - report_error(error); - g_error_free(error); - error = NULL; - } - - g_free(filename); - filenames = g_slist_next(filenames); - } - g_slist_free(filenames); - report_dives(); - dive_list_update_dives(); - } - gtk_widget_destroy(dialog); -} - -static void file_save(GtkWidget *w, gpointer data) -{ - GtkWidget *dialog; - dialog = gtk_file_chooser_dialog_new("Save File", - GTK_WINDOW(main_window), - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); - gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); - if (!existing_filename) { - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), "Untitled document"); - } else - gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), existing_filename); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - char *filename; - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); - save_dives(filename); - g_free(filename); - } - gtk_widget_destroy(dialog); -} - -static void quit(GtkWidget *w, gpointer data) -{ - gtk_main_quit(); -} - -static void create_radio(GtkWidget *dialog, const char *name, ...) -{ - va_list args; - GtkRadioButton *group = NULL; - GtkWidget *box, *label; - - box = gtk_hbox_new(TRUE, 10); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), box); - - label = gtk_label_new(name); - gtk_box_pack_start(GTK_BOX(box), label, TRUE, TRUE, 0); - - va_start(args, name); - for (;;) { - int enabled; - const char *name; - GtkWidget *button; - void *callback_fn; - - name = va_arg(args, char *); - if (!name) - break; - callback_fn = va_arg(args, void *); - enabled = va_arg(args, int); - - button = gtk_radio_button_new_with_label_from_widget(group, name); - group = GTK_RADIO_BUTTON(button); - gtk_box_pack_start(GTK_BOX(box), button, TRUE, TRUE, 0); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), enabled); - g_signal_connect(button, "toggled", G_CALLBACK(callback_fn), NULL); - } - va_end(args); -} - -#define UNITCALLBACK(name, type, value) \ -static void name(GtkWidget *w, gpointer data) \ -{ \ - if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) \ - menu_units.type = value; \ -} - -static struct units menu_units; - -UNITCALLBACK(set_meter, length, METERS) -UNITCALLBACK(set_feet, length, FEET) -UNITCALLBACK(set_bar, pressure, BAR) -UNITCALLBACK(set_psi, pressure, PSI) -UNITCALLBACK(set_liter, volume, LITER) -UNITCALLBACK(set_cuft, volume, CUFT) -UNITCALLBACK(set_celsius, temperature, CELSIUS) -UNITCALLBACK(set_fahrenheit, temperature, FAHRENHEIT) - -static void unit_dialog(GtkWidget *w, gpointer data) -{ - int result; - GtkWidget *dialog; - - menu_units = output_units; - - dialog = gtk_dialog_new_with_buttons("Units", - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - - create_radio(dialog, "Depth:", - "Meter", set_meter, (output_units.length == METERS), - "Feet", set_feet, (output_units.length == FEET), - NULL); - - create_radio(dialog, "Pressure:", - "Bar", set_bar, (output_units.pressure == BAR), - "PSI", set_psi, (output_units.pressure == PSI), - NULL); - - create_radio(dialog, "Volume:", - "Liter", set_liter, (output_units.volume == LITER), - "CuFt", set_cuft, (output_units.volume == CUFT), - NULL); - - create_radio(dialog, "Temperature:", - "Celsius", set_celsius, (output_units.temperature == CELSIUS), - "Fahrenheit", set_fahrenheit, (output_units.temperature == FAHRENHEIT), - NULL); - - gtk_widget_show_all(dialog); - result = gtk_dialog_run(GTK_DIALOG(dialog)); - if (result == GTK_RESPONSE_ACCEPT) { - /* Make sure to flush any modified old dive data with old units */ - update_dive(NULL); - output_units = menu_units; - update_dive_list_units(); - repaint_dive(); - gconf_client_set_bool(gconf, GCONF_NAME(feet), output_units.length == FEET, NULL); - gconf_client_set_bool(gconf, GCONF_NAME(psi), output_units.pressure == PSI, NULL); - gconf_client_set_bool(gconf, GCONF_NAME(cuft), output_units.volume == CUFT, NULL); - gconf_client_set_bool(gconf, GCONF_NAME(fahrenheit), output_units.temperature == FAHRENHEIT, NULL); - } - gtk_widget_destroy(dialog); -} - -static void renumber_dives(int nr) +void renumber_dives(int nr) { int i; for (i = 0; i < dive_table.nr; i++) { struct dive *dive = dive_table.dives[i]; dive->number = nr + i; + flush_divelist(dive); } -} - -static void renumber_dialog(GtkWidget *w, gpointer data) -{ - int result; - GtkWidget *dialog, *frame, *button; - - dialog = gtk_dialog_new_with_buttons("Renumber", - GTK_WINDOW(main_window), - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, - GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, - NULL); - - frame = gtk_frame_new("New starting number"); - gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), frame); - - button = gtk_spin_button_new_with_range(1, 50000, 1); - gtk_container_add(GTK_CONTAINER(frame), button); - - gtk_widget_show_all(dialog); - result = gtk_dialog_run(GTK_DIALOG(dialog)); - if (result == GTK_RESPONSE_ACCEPT) { - int nr = gtk_spin_button_get_value(GTK_SPIN_BUTTON(button)); - renumber_dives(nr); - repaint_dive(); - } - gtk_widget_destroy(dialog); -} - -static GtkActionEntry menu_items[] = { - { "FileMenuAction", GTK_STOCK_FILE, "File", NULL, NULL, NULL}, - { "LogMenuAction", GTK_STOCK_FILE, "Log", NULL, NULL, NULL}, - { "OpenFile", GTK_STOCK_OPEN, NULL, "O", NULL, G_CALLBACK(file_open) }, - { "SaveFile", GTK_STOCK_SAVE, NULL, "S", NULL, G_CALLBACK(file_save) }, - { "Print", GTK_STOCK_PRINT, NULL, "P", NULL, G_CALLBACK(do_print) }, - { "Import", NULL, "Import", NULL, NULL, G_CALLBACK(import_dialog) }, - { "Units", NULL, "Units", NULL, NULL, G_CALLBACK(unit_dialog) }, - { "Renumber", NULL, "Renumber", NULL, NULL, G_CALLBACK(renumber_dialog) }, - { "Quit", GTK_STOCK_QUIT, NULL, "Q", NULL, G_CALLBACK(quit) }, -}; -static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]); - -static const gchar* ui_string = " \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ -"; - -static GtkWidget *get_menubar_menu(GtkWidget *window) -{ - GtkActionGroup *action_group = gtk_action_group_new("Menu"); - gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0); - - GtkUIManager *ui_manager = gtk_ui_manager_new(); - gtk_ui_manager_insert_action_group(ui_manager, action_group, 0); - GError* error = 0; - gtk_ui_manager_add_ui_from_string(GTK_UI_MANAGER(ui_manager), ui_string, -1, &error); - - gtk_window_add_accel_group(GTK_WINDOW(window), gtk_ui_manager_get_accel_group(ui_manager)); - GtkWidget* menu = gtk_ui_manager_get_widget(ui_manager, "/MainMenu"); - - return menu; -} - -static void switch_page(GtkNotebook *notebook, gint arg1, gpointer user_data) -{ - repaint_dive(); + mark_divelist_changed(TRUE); } int main(int argc, char **argv) { int i; - GtkWidget *win; - GtkWidget *paned; - GtkWidget *info_box; - GtkWidget *notebook; - GtkWidget *dive_info; - GtkWidget *dive_list; - GtkWidget *equipment; - GtkWidget *menubar; - GtkWidget *vbox; output_units = SI_units; - parse_xml_init(); - - gtk_init(&argc, &argv); - - g_type_init(); - gconf = gconf_client_get_default(); - if (gconf_client_get_bool(gconf, GCONF_NAME(feet), NULL)) - output_units.length = FEET; - if (gconf_client_get_bool(gconf, GCONF_NAME(psi), NULL)) - output_units.pressure = PSI; - if (gconf_client_get_bool(gconf, GCONF_NAME(cuft), NULL)) - output_units.volume = CUFT; - if (gconf_client_get_bool(gconf, GCONF_NAME(fahrenheit), NULL)) - output_units.temperature = FAHRENHEIT; - - error_info_bar = NULL; - win = gtk_window_new(GTK_WINDOW_TOPLEVEL); - g_signal_connect(G_OBJECT(win), "destroy", G_CALLBACK(on_destroy), NULL); - main_window = win; - - vbox = gtk_vbox_new(FALSE, 0); - gtk_container_add(GTK_CONTAINER(win), vbox); - main_vbox = vbox; - - menubar = get_menubar_menu(win); - gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0); - - /* HPane for left the dive list, and right the dive info */ - paned = gtk_vpaned_new(); - gtk_box_pack_end(GTK_BOX(vbox), paned, TRUE, TRUE, 0); - - /* Create the actual divelist */ - dive_list = dive_list_create(); - gtk_paned_add2(GTK_PANED(paned), dive_list); - - /* VBox for dive info, and tabs */ - info_box = gtk_vbox_new(FALSE, 6); - gtk_paned_add1(GTK_PANED(paned), info_box); - - /* Notebook for dive info vs profile vs .. */ - notebook = gtk_notebook_new(); - g_signal_connect(notebook, "switch-page", G_CALLBACK(switch_page), NULL); - gtk_box_pack_start(GTK_BOX(info_box), notebook, TRUE, TRUE, 6); - - /* Frame for dive profile */ - dive_profile = dive_profile_widget(); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dive_profile, gtk_label_new("Dive Profile")); - - /* Frame for extended dive info */ - dive_info = extended_dive_info_widget(); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), dive_info, gtk_label_new("Dive Notes")); + parse_xml_init(); - /* Frame for dive equipment */ - equipment = equipment_widget(); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), equipment, gtk_label_new("Equipment")); + init_ui(&argc, &argv); - gtk_widget_set_app_paintable(win, TRUE); - gtk_widget_show_all(win); - for (i = 1; i < argc; i++) { const char *a = argv[i]; @@ -499,8 +226,8 @@ int main(int argc, char **argv) continue; } GError *error = NULL; - parse_xml_file(a, &error); - + parse_file(a, &error); + if (error != NULL) { report_error(error); @@ -509,9 +236,9 @@ int main(int argc, char **argv) } } - report_dives(); - dive_list_update_dives(); + report_dives(imported); - gtk_main(); + run_ui(); + exit_ui(); return 0; }