mirror of
https://github.com/subsurface/subsurface.git
synced 2025-01-19 22:35:27 +00:00
Merge branch 'defaultfile'
By now the default file code seems quite matured, so in preparation for 2.0 we'll bring it back into master. I made a few small clean-ups during the merge, but the merge itself is very much straight forward. Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This commit is contained in:
commit
3835faa8fb
13 changed files with 444 additions and 136 deletions
|
@ -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;
|
||||
|
||||
|
|
8
dive.h
8
dive.h
|
@ -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))
|
||||
|
|
4
dives/test24.xml
Normal file
4
dives/test24.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<dives>
|
||||
<program name='subsurface' version='1'></program>
|
||||
</dives>
|
||||
<!-- intentionally empty dive file - should register as no dives -->
|
|
@ -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);
|
||||
}
|
||||
|
|
4
file.c
4
file.c
|
@ -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"),
|
||||
|
|
384
gtk-gui.c
384
gtk-gui.c
|
@ -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);
|
||||
}
|
||||
|
|
25
info.c
25
info.c
|
@ -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);
|
||||
|
|
21
linux.c
21
linux.c
|
@ -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)
|
||||
{
|
||||
|
|
30
macos.c
30
macos.c
|
@ -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);
|
||||
}
|
||||
|
|
21
main.c
21
main.c
|
@ -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;
|
||||
|
|
21
parse-xml.c
21
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
|
||||
|
|
29
statistics.c
29
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,"");
|
||||
}
|
||||
|
|
24
windows.c
24
windows.c
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue