diff options
-rw-r--r-- | display-gtk.h | 3 | ||||
-rw-r--r-- | dive.h | 8 | ||||
-rw-r--r-- | dives/test24.xml | 4 | ||||
-rw-r--r-- | equipment.c | 6 | ||||
-rw-r--r-- | file.c | 4 | ||||
-rw-r--r-- | gtk-gui.c | 384 | ||||
-rw-r--r-- | info.c | 25 | ||||
-rw-r--r-- | linux.c | 21 | ||||
-rw-r--r-- | macos.c | 30 | ||||
-rw-r--r-- | main.c | 21 | ||||
-rw-r--r-- | parse-xml.c | 21 | ||||
-rw-r--r-- | statistics.c | 29 | ||||
-rw-r--r-- | windows.c | 24 |
13 files changed, 444 insertions, 136 deletions
diff --git a/display-gtk.h b/display-gtk.h index dd7e2c4a0..9d0ea4ed3 100644 --- a/display-gtk.h +++ b/display-gtk.h @@ -49,8 +49,7 @@ extern const char *subsurface_USB_name(void); extern const char *subsurface_icon_name(void); extern void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, GtkWidget *vbox, GtkUIManager *ui_manager); - -extern const char *divelist_font; +extern void quit(GtkWidget *w, gpointer data); extern visible_cols_t visible_cols; @@ -5,6 +5,7 @@ #include <time.h> #include <glib.h> +#include <glib/gstdio.h> #include <libxml/tree.h> /* @@ -384,7 +385,7 @@ static inline struct dive *get_dive(unsigned int nr) extern void parse_xml_init(void); extern void parse_xml_buffer(const char *url, const char *buf, int size, GError **error); -extern void set_filename(const char *filename); +extern void set_filename(const char *filename, gboolean force); extern void parse_file(const char *filename, GError **error); @@ -395,8 +396,10 @@ extern xmlDoc *test_xslt_transforms(xmlDoc *doc); extern void show_dive_info(struct dive *); extern void show_dive_equipment(struct dive *, int w_idx); +extern void clear_equipment_widgets(void); extern void show_dive_stats(struct dive *); +extern void clear_stats_widgets(void); extern void show_yearly_stats(void); @@ -466,6 +469,9 @@ const char *monthname(int mon); #define FIVE_STARS UTF8_BLACKSTAR UTF8_BLACKSTAR UTF8_BLACKSTAR UTF8_BLACKSTAR UTF8_BLACKSTAR extern const char *star_strings[]; +extern const char *default_filename; +extern const char *existing_filename; +extern const char *subsurface_default_filename(void); #define AIR_PERMILLE 209 #define FRACTION(n,x) ((unsigned)(n)/(x)),((unsigned)(n)%(x)) diff --git a/dives/test24.xml b/dives/test24.xml new file mode 100644 index 000000000..8ddc9be42 --- /dev/null +++ b/dives/test24.xml @@ -0,0 +1,4 @@ +<dives> +<program name='subsurface' version='1'></program> +</dives> +<!-- intentionally empty dive file - should register as no dives --> diff --git a/equipment.c b/equipment.c index 2230f5fca..adfb02989 100644 --- a/equipment.c +++ b/equipment.c @@ -1646,3 +1646,9 @@ GtkWidget *equipment_widget(int w_idx) return vbox; } + +void clear_equipment_widgets() +{ + gtk_list_store_clear(cylinder_list[W_IDX_PRIMARY].model); + gtk_list_store_clear(weightsystem_list[W_IDX_PRIMARY].model); +} @@ -253,6 +253,10 @@ void parse_file(const char *filename, GError **error) struct memblock mem; if (readfile(filename, &mem) < 0) { + /* we don't want to display an error if this was the default file */ + if (default_filename && ! strcmp(filename, default_filename)) + return; + fprintf(stderr, "Failed to read '%s'.\n", filename); if (error) { *error = g_error_new(g_quark_from_string("subsurface"), @@ -8,6 +8,7 @@ #include <stdlib.h> #include <time.h> #include <unistd.h> +#include <sys/stat.h> #include "dive.h" #include "divelist.h" @@ -24,8 +25,9 @@ GtkWidget *vpane, *hpane; GtkWidget *notebook; int error_count; - +const char *existing_filename; const char *divelist_font; +const char *default_filename; struct units output_units; @@ -79,7 +81,6 @@ void repaint_dive(void) gtk_widget_queue_draw(dive_profile); } -static char *existing_filename; static gboolean need_icon = TRUE; static void on_info_bar_response(GtkWidget *widget, gint response, @@ -125,81 +126,17 @@ void report_error(GError* error) } } -static void file_open(GtkWidget *w, gpointer data) +static GtkFileFilter *setup_filter(void) { - GtkWidget *dialog; - GtkFileFilter *filter; - - 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); - - filter = gtk_file_filter_new(); + GtkFileFilter *filter = gtk_file_filter_new(); gtk_file_filter_add_pattern(filter, "*.xml"); gtk_file_filter_add_pattern(filter, "*.XML"); gtk_file_filter_add_pattern(filter, "*.sda"); gtk_file_filter_add_pattern(filter, "*.SDA"); gtk_file_filter_add_mime_type(filter, "text/xml"); gtk_file_filter_set_name(filter, "XML file"); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); - - if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { - GSList *filenames, *fn_glist; - char *filename; - filenames = fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); - - GError *error = NULL; - while(filenames != NULL) { - filename = filenames->data; - parse_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(fn_glist); - report_dives(FALSE); - } - gtk_widget_destroy(dialog); -} - -/* return the path and the file component contained in the full path */ -static char *path_and_file(char *pathin, char **fileout) { - char *slash = pathin, *next; - char *result; - size_t len, n; - if (! pathin) { - *fileout = strdup(""); - return strdup(""); - } - while ((next = strpbrk(slash + 1, "\\/"))) - slash = next; - if (pathin != slash) - slash++; - *fileout = strdup(slash); - - /* strndup(pathin, slash - pathin) */ - n = slash - pathin; - len = strlen(pathin); - if (n < len) - len = n; - - result = (char *)malloc(len + 1); - if (!result) - return 0; - - result[len] = '\0'; - return (char *)memcpy(result, pathin, len); + return filter; } static void file_save_as(GtkWidget *w, gpointer data) @@ -217,7 +154,14 @@ static void file_save_as(GtkWidget *w, gpointer data) NULL); gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog), TRUE); - current_dir = path_and_file(existing_filename, ¤t_file); + if (existing_filename) { + current_dir = g_path_get_dirname(existing_filename); + current_file = g_path_get_basename(existing_filename); + } else { + const char *current_default = subsurface_default_filename(); + current_dir = g_path_get_dirname(current_default); + current_file = g_path_get_basename(current_default); + } gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), current_dir); gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), current_file); @@ -231,7 +175,7 @@ static void file_save_as(GtkWidget *w, gpointer data) if (filename){ save_dives(filename); - set_filename(filename); + set_filename(filename, TRUE); g_free(filename); mark_divelist_changed(FALSE); } @@ -239,9 +183,24 @@ static void file_save_as(GtkWidget *w, gpointer data) static void file_save(GtkWidget *w, gpointer data) { + const char *current_default; + if (!existing_filename) return file_save_as(w, data); + current_default = subsurface_default_filename(); + if (strcmp(existing_filename, current_default) == 0) { + /* if we are using the default filename the directory + * that we are creating the file in may not exist */ + char *current_def_dir; + struct stat sb; + + current_def_dir = g_path_get_dirname(existing_filename); + if (stat(current_def_dir, &sb) != 0) { + g_mkdir(current_def_dir, S_IRWXU); + } + free(current_def_dir); + } save_dives(existing_filename); mark_divelist_changed(FALSE); } @@ -260,11 +219,11 @@ static gboolean ask_save_changes() if (!existing_filename){ label = gtk_label_new ( - "You have unsaved changes\nWould you like to save those before exiting the program?"); + "You have unsaved changes\nWould you like to save those before closing the datafile?"); } else { char *label_text = (char*) malloc(sizeof(char) * (93 + strlen(existing_filename))); sprintf(label_text, - "You have unsaved changes to file: %s \nWould you like to save those before exiting the program?", + "You have unsaved changes to file: %s \nWould you like to save those before closing the datafile?", existing_filename); label = gtk_label_new (label_text); g_free(label_text); @@ -282,6 +241,93 @@ static gboolean ask_save_changes() return quit; } +static void file_close(GtkWidget *w, gpointer data) +{ + int i; + + if (unsaved_changes()) + if (ask_save_changes() == FALSE) + return; + + if (existing_filename) + free((void *)existing_filename); + existing_filename = NULL; + + /* free the dives and trips */ + for (i = 0; i < dive_table.nr; i++) + free(get_dive(i)); + dive_table.nr = 0; + dive_table.preexisting = 0; + mark_divelist_changed(FALSE); + + /* inlined version of g_list_free_full(dive_trip_list, free); */ + g_list_foreach(dive_trip_list, (GFunc)free, NULL); + g_list_free(dive_trip_list); + + dive_trip_list = NULL; + + /* clear the selection and the statistics */ + amount_selected = 0; + selected_dive = 0; + process_selected_dives(); + clear_stats_widgets(); + + /* clear the equipment page */ + clear_equipment_widgets(); + + /* redraw the screen */ + dive_list_update_dives(); + show_dive_info(NULL); +} + +static void file_open(GtkWidget *w, gpointer data) +{ + GtkWidget *dialog; + GtkFileFilter *filter; + const char *current_default; + + 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); + current_default = subsurface_default_filename(); + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), current_default); + /* when opening the data file we should allow only one file to be chosen */ + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), FALSE); + + filter = setup_filter(); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); + + if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { + GSList *fn_glist; + char *filename; + + /* first, close the existing file, if any, and forget its name */ + file_close(w, data); + free((void *)existing_filename); + existing_filename = NULL; + + /* we know there is only one filename */ + fn_glist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog)); + + GError *error = NULL; + filename = fn_glist->data; + parse_file(filename, &error); + if (error != NULL) + { + report_error(error); + g_error_free(error); + error = NULL; + } + g_free(filename); + g_slist_free(fn_glist); + report_dives(FALSE); + } + gtk_widget_destroy(dialog); +} + static gboolean on_delete(GtkWidget* w, gpointer data) { /* Make sure to flush any modified dive data */ @@ -303,7 +349,7 @@ static void on_destroy(GtkWidget* w, gpointer data) gtk_main_quit(); } -static void quit(GtkWidget *w, gpointer data) +void quit(GtkWidget *w, gpointer data) { /* Make sure to flush any modified dive data */ update_dive(NULL); @@ -437,10 +483,58 @@ static void event_toggle(GtkWidget *w, gpointer _data) *plot_ev = GTK_TOGGLE_BUTTON(w)->active; } +static void pick_default_file(GtkWidget *w, GtkButton *button) +{ + GtkWidget *fs_dialog, *preferences; + const char *current_default; + char *current_def_file, *current_def_dir; + GtkFileFilter *filter; + struct stat sb; + + fs_dialog = gtk_file_chooser_dialog_new("Choose Default XML File", + GTK_WINDOW(main_window), + GTK_FILE_CHOOSER_ACTION_SAVE, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, + NULL); + preferences = gtk_widget_get_ancestor(w, GTK_TYPE_DIALOG); + gtk_window_set_accept_focus(GTK_WINDOW(preferences), FALSE); + + current_default = subsurface_default_filename(); + current_def_dir = g_path_get_dirname(current_default); + current_def_file = g_path_get_basename(current_default); + + /* it's possible that the directory doesn't exist (especially for the default) + * For gtk's file select box to make sense we create it */ + if (stat(current_def_dir, &sb) != 0) + g_mkdir(current_def_dir, S_IRWXU); + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fs_dialog), current_def_dir); + gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(fs_dialog), current_def_file); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(fs_dialog), FALSE); + filter = setup_filter(); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs_dialog), filter); + gtk_widget_show_all(fs_dialog); + if (gtk_dialog_run(GTK_DIALOG(fs_dialog)) == GTK_RESPONSE_ACCEPT) { + GSList *list; + + list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(fs_dialog)); + if (g_slist_length(list) == 1) + gtk_button_set_label(button, list->data); + g_slist_free(list); + } + + free(current_def_dir); + free(current_def_file); + gtk_widget_destroy(fs_dialog); + gtk_window_set_accept_focus(GTK_WINDOW(preferences), TRUE); +} + static void preferences_dialog(GtkWidget *w, gpointer data) { int result; GtkWidget *dialog, *font, *frame, *box, *vbox, *button; + const char *current_default, *new_default; menu_units = output_units; @@ -541,6 +635,15 @@ static void preferences_dialog(GtkWidget *w, gpointer data) gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); g_signal_connect(G_OBJECT(button), "toggled", G_CALLBACK(autogroup_toggle), NULL); + frame = gtk_frame_new("Default XML Data File"); + gtk_box_pack_start(GTK_BOX(box), frame, FALSE, FALSE, 5); + box = gtk_hbox_new(FALSE, 6); + gtk_container_add(GTK_CONTAINER(frame), box); + current_default = subsurface_default_filename(); + button = gtk_button_new_with_label(current_default); + g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(pick_default_file), button); + gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 6); + gtk_widget_show_all(dialog); result = gtk_dialog_run(GTK_DIALOG(dialog)); if (result == GTK_RESPONSE_ACCEPT) { @@ -569,6 +672,22 @@ static void preferences_dialog(GtkWidget *w, gpointer data) subsurface_set_conf("OTU", PREF_BOOL, BOOL_TO_PTR(visible_cols.otu)); subsurface_set_conf("divelist_font", PREF_STRING, divelist_font); subsurface_set_conf("autogroup", PREF_BOOL, BOOL_TO_PTR(autogroup)); + new_default = strdup(gtk_button_get_label(GTK_BUTTON(button))); + + /* if we opened the default file and are changing its name, + * update existing_filename */ + if (existing_filename) { + if (strcmp(current_default, existing_filename) == 0) { + free((void *)existing_filename); + existing_filename = strdup(new_default); + } + } + + if (strcmp(current_default, new_default)) { + subsurface_set_conf("default_filename", PREF_STRING, new_default); + free((void *)default_filename); + default_filename = new_default; + } /* Flush the changes out to the system */ subsurface_flush_conf(); @@ -753,8 +872,9 @@ static GtkActionEntry menu_items[] = { { "OpenFile", GTK_STOCK_OPEN, NULL, CTRLCHAR "O", NULL, G_CALLBACK(file_open) }, { "SaveFile", GTK_STOCK_SAVE, NULL, CTRLCHAR "S", NULL, G_CALLBACK(file_save) }, { "SaveAsFile", GTK_STOCK_SAVE_AS, NULL, SHIFTCHAR CTRLCHAR "S", NULL, G_CALLBACK(file_save_as) }, + { "CloseFile", GTK_STOCK_CLOSE, NULL, NULL, NULL, G_CALLBACK(file_close) }, { "Print", GTK_STOCK_PRINT, NULL, CTRLCHAR "P", NULL, G_CALLBACK(do_print) }, - { "Import", NULL, "Import", NULL, NULL, G_CALLBACK(import_dialog) }, + { "Import", NULL, "Import", SHIFTCHAR CTRLCHAR "O", NULL, G_CALLBACK(import_dialog) }, { "AddDive", GTK_STOCK_ADD, "Add Dive", NULL, NULL, G_CALLBACK(add_dive_cb) }, { "Preferences", GTK_STOCK_PREFERENCES, "Preferences", PREFERENCE_ACCEL, NULL, G_CALLBACK(preferences_dialog) }, { "Renumber", NULL, "Renumber", NULL, NULL, G_CALLBACK(renumber_dialog) }, @@ -780,8 +900,10 @@ static const gchar* ui_string = " \ <menubar name=\"MainMenu\"> \ <menu name=\"FileMenu\" action=\"FileMenuAction\"> \ <menuitem name=\"Open\" action=\"OpenFile\" /> \ + <menuitem name=\"Import\" action=\"Import\" /> \ <menuitem name=\"Save\" action=\"SaveFile\" /> \ <menuitem name=\"Save As\" action=\"SaveAsFile\" /> \ + <menuitem name=\"Close\" action=\"CloseFile\" /> \ <menuitem name=\"Print\" action=\"Print\" /> \ <separator name=\"Separator1\"/> \ <menuitem name=\"Preferences\" action=\"Preferences\" /> \ @@ -789,7 +911,6 @@ static const gchar* ui_string = " \ <menuitem name=\"Quit\" action=\"Quit\" /> \ </menu> \ <menu name=\"LogMenu\" action=\"LogMenuAction\"> \ - <menuitem name=\"Import\" action=\"Import\" /> \ <menuitem name=\"Add Dive\" action=\"AddDive\" /> \ <separator name=\"Separator\"/> \ <menuitem name=\"Renumber\" action=\"Renumber\" /> \ @@ -875,8 +996,8 @@ void init_ui(int *argcp, char ***argvp) visible_cols.sac = PTR_TO_BOOL(subsurface_get_conf("SAC", PREF_BOOL)); divelist_font = subsurface_get_conf("divelist_font", PREF_STRING); - autogroup = PTR_TO_BOOL(subsurface_get_conf("autogroup", PREF_BOOL)); + default_filename = subsurface_get_conf("default_filename", PREF_STRING); default_dive_computer_vendor = subsurface_get_conf("dive_computer_vendor", PREF_STRING); default_dive_computer_product = subsurface_get_conf("dive_computer_product", PREF_STRING); @@ -968,6 +1089,10 @@ void run_ui(void) void exit_ui(void) { subsurface_close_conf(); + if (default_filename) + free((char *)default_filename); + if (existing_filename) + free((void *)existing_filename); } typedef struct { @@ -1164,52 +1289,68 @@ static GtkEntry *dive_computer_device(GtkWidget *vbox) return GTK_ENTRY(entry); } -/* once a file is selected in the FileChooserButton we want to exit the import dialog */ -static void on_file_set(GtkFileChooserButton *widget, gpointer _data) +static void pick_import_files(GtkWidget *w, GSList **filelist) { - GtkDialog *main_dialog = _data; + GtkWidget *fs_dialog, *import; + const char *current_default; + char *current_def_dir; + GtkFileFilter *filter; + struct stat sb; - gtk_dialog_response(main_dialog, GTK_RESPONSE_ACCEPT); + *filelist = NULL; + fs_dialog = gtk_file_chooser_dialog_new("Choose Files to import", + GTK_WINDOW(main_window), + GTK_FILE_CHOOSER_ACTION_OPEN, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, + NULL); + import = gtk_widget_get_ancestor(w, GTK_TYPE_DIALOG); + gtk_window_set_accept_focus(GTK_WINDOW(import), FALSE); + + /* I'm not sure what the best default path should be... */ + if (existing_filename) { + current_def_dir = g_path_get_dirname(existing_filename); + } else { + current_default = subsurface_default_filename(); + current_def_dir = g_path_get_dirname(current_default); + free((void *)current_default); + } + + /* it's possible that the directory doesn't exist (especially for the default) + * For gtk's file select box to make sense we create it */ + if (stat(current_def_dir, &sb) != 0) + g_mkdir(current_def_dir, S_IRWXU); + + gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fs_dialog), current_def_dir); + gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(fs_dialog), TRUE); + filter = setup_filter(); + gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fs_dialog), filter); + gtk_widget_show_all(fs_dialog); + if (gtk_dialog_run(GTK_DIALOG(fs_dialog)) == GTK_RESPONSE_ACCEPT) + *filelist = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(fs_dialog)); + free(current_def_dir); + gtk_widget_destroy(fs_dialog); + gtk_window_set_accept_focus(GTK_WINDOW(import), TRUE); + /* if we selected one or more files, pretent that we clicked OK in the import dialog */ + if (*filelist != NULL) + gtk_dialog_response(GTK_DIALOG(import), GTK_RESPONSE_ACCEPT); } -static GtkWidget *xml_file_selector(GtkWidget *vbox, GtkWidget *main_dialog) +static void xml_file_selector(GtkWidget *vbox, GtkWidget *main_dialog, GSList **list) { - GtkWidget *hbox, *frame, *chooser, *dialog; - GtkFileFilter *filter; - char *current_file, *current_dir; + GtkWidget *hbox, *frame, *chooser, *box; hbox = gtk_hbox_new(FALSE, 6); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 3); frame = gtk_frame_new("XML file name"); gtk_box_pack_start(GTK_BOX(hbox), frame, FALSE, TRUE, 3); - dialog = gtk_file_chooser_dialog_new("Open XML 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), FALSE); - current_dir = path_and_file(existing_filename, ¤t_file); - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), current_dir); - free(current_dir); - free(current_file); - filter = gtk_file_filter_new(); - gtk_file_filter_add_pattern(filter, "*.xml"); - gtk_file_filter_add_pattern(filter, "*.XML"); - gtk_file_filter_add_pattern(filter, "*.sda"); - gtk_file_filter_add_pattern(filter, "*.SDA"); - gtk_file_filter_add_mime_type(filter, "text/xml"); - gtk_file_filter_set_name(filter, "XML file"); - gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter); - - chooser = gtk_file_chooser_button_new_with_dialog(dialog); - g_signal_connect(G_OBJECT(chooser), "file-set", G_CALLBACK(on_file_set), main_dialog); - gtk_file_chooser_button_set_width_chars(GTK_FILE_CHOOSER_BUTTON(chooser), 30); - gtk_container_add(GTK_CONTAINER(frame), chooser); - - return chooser; + box = gtk_hbox_new(FALSE, 6); + gtk_container_add(GTK_CONTAINER(frame), box); + chooser = gtk_button_new_with_label("Pick XML file to import"); + g_signal_connect(G_OBJECT(chooser), "clicked", G_CALLBACK(pick_import_files), list); + gtk_box_pack_start(GTK_BOX(box), chooser, FALSE, FALSE, 6); } static void do_import_file(gpointer data, gpointer user_data) @@ -1252,9 +1393,9 @@ void import_dialog(GtkWidget *w, gpointer data) { int result; GtkWidget *dialog, *hbox, *vbox, *label, *info = NULL; + GSList *filenames; GtkComboBox *computer; GtkEntry *device; - GtkWidget *XMLchooser; device_data_t devicedata = { .devname = NULL, }; @@ -1269,7 +1410,7 @@ void import_dialog(GtkWidget *w, gpointer data) vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); label = gtk_label_new("Import: \nLoad XML file or import directly from dive computer"); gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, TRUE, 3); - XMLchooser = xml_file_selector(vbox, dialog); + xml_file_selector(vbox, dialog, &filenames); computer = dive_computer_selector(vbox); device = dive_computer_device(vbox); hbox = gtk_hbox_new(FALSE, 6); @@ -1284,14 +1425,13 @@ repeat: dc_descriptor_t *descriptor; GtkTreeIter iter; GtkTreeModel *model; - GSList *list; + case GTK_RESPONSE_ACCEPT: /* what happened - did the user pick a file? In that case * we ignore whether a dive computer model was picked */ if (info) gtk_widget_destroy(info); - list = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(XMLchooser)); - if (g_slist_length(list) == 0) { + if (g_slist_length(filenames) == 0) { const char *vendor, *product; if (!gtk_combo_box_get_active_iter(computer, &iter)) @@ -1314,8 +1454,8 @@ repeat: if (info) goto repeat; } else { - g_slist_foreach(list,do_import_file,NULL); - g_slist_free(list); + g_slist_foreach(filenames,do_import_file,NULL); + g_slist_free(filenames); } break; default: @@ -1336,11 +1476,11 @@ 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) +void set_filename(const char *filename, gboolean force) { - if (existing_filename) - free(existing_filename); - existing_filename = NULL; + if (!force && existing_filename) + return; + free((void *)existing_filename); if (filename) existing_filename = strdup(filename); } @@ -112,6 +112,23 @@ void show_dive_info(struct dive *dive) { const char *text; char buffer[80]; + char title[80]; + + if (!dive) { + if (existing_filename) { + snprintf(title, 80, "Subsurface: %s", g_path_get_basename(existing_filename)); + gtk_window_set_title(GTK_WINDOW(main_window), title); + } else { + gtk_window_set_title(GTK_WINDOW(main_window), "Subsurface"); + } + SET_TEXT_VALUE(divemaster); + SET_TEXT_VALUE(buddy); + SET_TEXT_VALUE(location); + SET_TEXT_VALUE(suit); + gtk_entry_set_text(rating, star_strings[0]); + gtk_text_buffer_set_text(gtk_text_view_get_buffer(notes), "", -1); + return; + } /* dive number and location (or lacking that, the date) go in the window title */ text = dive->location; @@ -125,8 +142,14 @@ void show_dive_info(struct dive *dive) text = buffer; if (!dive->number) text += 10; /* Skip the "Dive #0 - " part */ - gtk_window_set_title(GTK_WINDOW(main_window), text); + /* put it all together */ + if (existing_filename) { + snprintf(title, 80, "%s: %s", g_path_get_basename(existing_filename), text); + gtk_window_set_title(GTK_WINDOW(main_window), title); + } else { + gtk_window_set_title(GTK_WINDOW(main_window), text); + } SET_TEXT_VALUE(divemaster); SET_TEXT_VALUE(buddy); SET_TEXT_VALUE(location); @@ -1,7 +1,10 @@ /* linux.c */ /* implements Linux specific functions */ +#include "dive.h" #include "display-gtk.h" #include <gconf/gconf-client.h> +#include <string.h> + #define DIVELIST_DEFAULT_FONT "Sans 8" GConfClient *gconf; @@ -63,6 +66,24 @@ const char *subsurface_icon_name() return "subsurface.svg"; } +const char *subsurface_default_filename() +{ + if (default_filename) { + return strdup(default_filename); + } else { + const char *home, *user; + char *buffer; + int len; + + home = g_get_home_dir(); + user = g_get_user_name(); + len = strlen(home) + strlen(user) + 17; + buffer = malloc(len); + snprintf(buffer, len, "%s/subsurface/%s.xml", home, user); + return buffer; + } +} + void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, GtkWidget *vbox, GtkUIManager *ui_manager) { @@ -1,5 +1,6 @@ /* macos.c */ /* implements Mac OS X specific functions */ +#include "dive.h" #include "display-gtk.h" #include <CoreFoundation/CoreFoundation.h> #include <mach-o/dyld.h> @@ -53,7 +54,7 @@ const void *subsurface_get_conf(char *name, pref_type_t type) strpref = CFPreferencesCopyAppValue(CFSTR_VAR(name), SUBSURFACE_PREFERENCES); if (!strpref) return NULL; - return CFStringGetCStringPtr(strpref, kCFStringEncodingMacRoman); + return strdup(CFStringGetCStringPtr(strpref, kCFStringEncodingMacRoman)); } /* we shouldn't get here, but having this line makes the compiler happy */ return NULL; @@ -85,6 +86,30 @@ const char *subsurface_icon_name() return path; } +const char *subsurface_default_filename() +{ + if (default_filename) { + return strdup(default_filename); + } else { + const char *home, *user; + char *buffer; + int len; + + home = g_get_home_dir(); + user = g_get_user_name(); + len = strlen(home) + strlen(user) + 45; + buffer = malloc(len); + snprintf(buffer, len, "%s/Library/Application Support/Subsurface/%s.xml", home, user); + return buffer; + } +} + +static void show_main_window(GtkWidget *w, gpointer data) +{ + gtk_widget_show(main_window); + gtk_window_present(GTK_WINDOW(main_window)); +} + void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, GtkWidget *vbox, GtkUIManager *ui_manager) { @@ -122,5 +147,8 @@ void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, gtk_osxapplication_insert_app_menu_item (osx_app, sep, 3); gtk_osxapplication_set_use_quartz_accelerators(osx_app, TRUE); + g_signal_connect(osx_app,"NSApplicationDidBecomeActive",G_CALLBACK(show_main_window),NULL); + g_signal_connect(osx_app,"NSApplicationWillTerminate",G_CALLBACK(quit),NULL); + gtk_osxapplication_ready(osx_app); } @@ -125,6 +125,9 @@ void report_dives(gboolean is_imported) if (!merged) continue; + /* careful - we might free the dive that last points to. Oops... */ + if (last == prev || last == dive) + last = merged; free(prev); free(dive); *pp = merged; @@ -140,8 +143,8 @@ void report_dives(gboolean is_imported) 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) + /* did we add dives to the dive table? */ + if (preexisting != dive_table.nr) mark_divelist_changed(TRUE); } dive_table.preexisting = dive_table.nr; @@ -211,6 +214,7 @@ void renumber_dives(int nr) int main(int argc, char **argv) { int i; + gboolean no_filenames = TRUE; output_units = SI_units; @@ -225,6 +229,7 @@ int main(int argc, char **argv) parse_argument(a); continue; } + no_filenames = FALSE; GError *error = NULL; parse_file(a, &error); @@ -235,9 +240,17 @@ int main(int argc, char **argv) error = NULL; } } - + if (no_filenames) { + GError *error = NULL; + const char *filename = subsurface_default_filename(); + parse_file(filename, &error); + /* don't report errors - this file may not exist, but make + sure we remember this as the filename in use */ + set_filename(filename, FALSE); + } report_dives(imported); - + if (dive_table.nr == 0) + show_dive_info(NULL); run_ui(); exit_ui(); return 0; diff --git a/parse-xml.c b/parse-xml.c index 1c4db7d9d..f47ac5a26 100644 --- a/parse-xml.c +++ b/parse-xml.c @@ -1173,11 +1173,23 @@ static void try_to_fill_trip(struct dive **divep, const char *name, char *buf) } /* - * File boundaries are dive boundaries. But sometimes there are + * While in some formats file boundaries are dive boundaries, in many + * others (as for example in our native format) there are * multiple dives per file, so there can be other events too that * trigger a "new dive" marker and you may get some nesting due * to that. Just ignore nesting levels. + * On the flipside it is possible that we start an XML file that ends + * up having no dives in it at all - don't create a bogus empty dive + * for those. It's not entirely clear what is the minimum set of data + * to make a dive valid, but if it has no location, no date and no + * samples I'm pretty sure it's useless. */ +static gboolean is_dive(void) +{ + return (cur_dive && + (cur_dive->location || cur_dive->when || cur_dive->samples)); +} + static void dive_start(void) { if (cur_dive) @@ -1188,7 +1200,7 @@ static void dive_start(void) static void dive_end(void) { - if (!cur_dive) + if (!is_dive()) return; record_dive(cur_dive); cur_dive = NULL; @@ -1475,9 +1487,8 @@ void parse_xml_buffer(const char *url, const char *buffer, int size, GError **er } return; } - /* we assume that the last (or only) filename passed as argument is a - * great filename to use as default when saving the dives */ - set_filename(url); + /* remember, if necessary, that this is the filename to store to */ + set_filename(url, FALSE); reset_all(); dive_start(); #ifdef XSLT diff --git a/statistics.c b/statistics.c index f4a9de6f3..5e1c8804a 100644 --- a/statistics.c +++ b/statistics.c @@ -715,3 +715,32 @@ GtkWidget *single_stats_widget(void) return vbox; } + +void clear_stats_widgets(void) +{ + set_label(single_w.date, ""); + set_label(single_w.dive_time, ""); + set_label(single_w.surf_intv, ""); + set_label(single_w.max_depth, ""); + set_label(single_w.avg_depth, ""); + set_label(single_w.water_temp, ""); + set_label(single_w.sac, ""); + set_label(single_w.sac, ""); + set_label(single_w.otu, ""); + set_label(single_w.o2he, ""); + set_label(single_w.gas_used, ""); + set_label(stats_w.total_time,""); + set_label(stats_w.avg_time,""); + set_label(stats_w.shortest_time,""); + set_label(stats_w.longest_time,""); + set_label(stats_w.max_overall_depth,""); + set_label(stats_w.min_overall_depth,""); + set_label(stats_w.avg_overall_depth,""); + set_label(stats_w.min_sac,""); + set_label(stats_w.avg_sac,""); + set_label(stats_w.max_sac,""); + set_label(stats_w.selection_size,""); + set_label(stats_w.max_temp,""); + set_label(stats_w.avg_temp,""); + set_label(stats_w.min_temp,""); +} @@ -1,7 +1,9 @@ /* windows.c */ /* implements Windows specific functions */ +#include "dive.h" #include "display-gtk.h" #include <windows.h> +#include <shlobj.h> #define DIVELIST_DEFAULT_FONT "Sans 8" static HKEY hkey; @@ -93,6 +95,28 @@ const char *subsurface_icon_name() return "subsurface.ico"; } +const char *subsurface_default_filename() +{ + if (default_filename) { + return strdup(default_filename); + } else { + char datapath[MAX_PATH]; + const char *user; + char *buffer; + int len; + + user = g_get_user_name(); + if (! SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, datapath))) { + datapath[0] = '.'; + datapath[1] = '\0'; + } + len = strlen(datapath) + strlen(user) + 17; + buffer = malloc(len); + snprintf(buffer, len, "%s\\Subsurface\\%s.xml", datapath, user); + return buffer; + } +} + void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, GtkWidget *vbox, GtkUIManager *ui_manager) { |