mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +00:00
Merge branch 'trip3' of git://git.hohndel.org/subsurface
Pull trip manipulation branch from Dirk Hohndel: "I have added yet more of the requested features. I am not aware of any outstanding bugs or crashes (except for the Gtk problem that causes the import to crash for some people on Ubuntu and MacOS - but as I mentioned earlier, that bug has been around as long as the import file selector box)." * 'trip3' of git://git.hohndel.org/subsurface: Avoid duplicate dive_trip entries More trip manipulations: remove selected dives from trip Add ability to merge trip with trip below Use the infrastructure for moving dives in more places Correct the trip related test dives Fix crash when removing the first dive of a trip Correctly initialize the toggle state of the autogroup menu entry Fix copy_tree_node to no longer overwrite dive duration Add autogen menu command Fix a crash when changing sort column Use truth values with gboolean Allow modification and edits of trips Clean up macros and auxiliary functions Store time_t as long value
This commit is contained in:
commit
252c28f8f2
10 changed files with 707 additions and 97 deletions
46
dive.h
46
dive.h
|
@ -241,6 +241,7 @@ extern const char *tripflag_names[NUM_TRIPFLAGS];
|
||||||
struct dive {
|
struct dive {
|
||||||
int number;
|
int number;
|
||||||
tripflag_t tripflag;
|
tripflag_t tripflag;
|
||||||
|
struct dive *divetrip;
|
||||||
int selected;
|
int selected;
|
||||||
time_t when;
|
time_t when;
|
||||||
char *location;
|
char *location;
|
||||||
|
@ -270,49 +271,63 @@ extern gboolean autogroup;
|
||||||
|
|
||||||
#define UNGROUPED_DIVE(_dive) ((_dive)->tripflag == NO_TRIP)
|
#define UNGROUPED_DIVE(_dive) ((_dive)->tripflag == NO_TRIP)
|
||||||
#define DIVE_IN_TRIP(_dive) ((_dive)->tripflag == IN_TRIP)
|
#define DIVE_IN_TRIP(_dive) ((_dive)->tripflag == IN_TRIP)
|
||||||
#define NEXT_TRIP(_entry, _list) ((_entry) ? g_list_next(_entry) : (_list))
|
#define NEXT_TRIP(_entry) ((_entry) ? g_list_next(_entry) : (dive_trip_list))
|
||||||
#define PREV_TRIP(_entry, _list) ((_entry) ? g_list_previous(_entry) : g_list_last(_list))
|
#define PREV_TRIP(_entry) ((_entry) ? g_list_previous(_entry) : g_list_last(dive_trip_list))
|
||||||
#define DIVE_TRIP(_trip) ((struct dive *)(_trip)->data)
|
#define DIVE_TRIP(_trip) ((struct dive *)(_trip)->data)
|
||||||
#define DIVE_FITS_TRIP(_dive, _dive_trip) ((_dive_trip)->when - TRIP_THRESHOLD <= (_dive)->when)
|
#define DIVE_FITS_TRIP(_dive, _dive_trip) ((_dive_trip)->when - TRIP_THRESHOLD <= (_dive)->when)
|
||||||
|
|
||||||
|
/* compare two dives by when they happened */
|
||||||
static inline int dive_date_cmp(gconstpointer _a, gconstpointer _b) {
|
static inline int dive_date_cmp(gconstpointer _a, gconstpointer _b) {
|
||||||
return ((struct dive *)(_a))->when - ((struct dive *)(_b))->when;
|
return ((struct dive *)_a)->when - ((struct dive *)_b)->when;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FIND_TRIP(_trip, _list) g_list_find_custom((_list), (_trip), dive_date_cmp)
|
/* returns 0 if the dive happened exactly at time */
|
||||||
|
static inline int dive_when_find(gconstpointer _dive, gconstpointer _time) {
|
||||||
|
return ((struct dive *)_dive)->when != (time_t) _time;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FIND_TRIP(_when) g_list_find_custom(dive_trip_list, (gconstpointer)(_when), dive_when_find)
|
||||||
|
|
||||||
#ifdef DEBUG_TRIP
|
#ifdef DEBUG_TRIP
|
||||||
static void dump_trip_list(void)
|
static void dump_trip_list(void)
|
||||||
{
|
{
|
||||||
GList *p = NULL;
|
GList *p = NULL;
|
||||||
int i=0;
|
int i=0;
|
||||||
while ((p = NEXT_TRIP(p, dive_trip_list))) {
|
while ((p = NEXT_TRIP(p))) {
|
||||||
struct tm *tm = gmtime(&DIVE_TRIP(p)->when);
|
struct tm *tm = gmtime(&DIVE_TRIP(p)->when);
|
||||||
printf("trip %d to \"%s\" on %04u-%02u-%02u\n", ++i, DIVE_TRIP(p)->location,
|
printf("trip %d to \"%s\" on %04u-%02u-%02u %02u:%02u:%02u\n", ++i, DIVE_TRIP(p)->location,
|
||||||
tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday);
|
tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
}
|
}
|
||||||
printf("-----\n");
|
printf("-----\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* insert the trip into the list - but ensure you don't have two trips
|
/* insert the trip into the dive_trip_list - but ensure you don't have
|
||||||
* for the same date; but if you have, make sure you don't keep the
|
* two trips for the same date; but if you have, make sure you don't
|
||||||
* one with less information */
|
* keep the one with less information */
|
||||||
static inline GList *insert_trip(struct dive *_trip, GList *_list)
|
static void inline insert_trip(struct dive **trip)
|
||||||
{
|
{
|
||||||
GList *result = FIND_TRIP(_trip, _list);
|
struct dive *dive_trip = *trip;
|
||||||
|
GList *result = FIND_TRIP(dive_trip->when);
|
||||||
if (result) {
|
if (result) {
|
||||||
if (! DIVE_TRIP(result)->location)
|
if (! DIVE_TRIP(result)->location)
|
||||||
DIVE_TRIP(result)->location = _trip->location;
|
DIVE_TRIP(result)->location = dive_trip->location;
|
||||||
|
*trip = DIVE_TRIP(result);
|
||||||
} else {
|
} else {
|
||||||
result = g_list_insert_sorted((_list), (_trip), dive_date_cmp);
|
dive_trip_list = g_list_insert_sorted(dive_trip_list, dive_trip, dive_date_cmp);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_TRIP
|
#ifdef DEBUG_TRIP
|
||||||
dump_trip_list();
|
dump_trip_list();
|
||||||
#endif
|
#endif
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void delete_trip(GList *trip)
|
||||||
|
{
|
||||||
|
dive_trip_list = g_list_delete_link(dive_trip_list, trip);
|
||||||
|
#ifdef DEBUG_TRIP
|
||||||
|
dump_trip_list();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* We keep our internal data in well-specified units, but
|
* We keep our internal data in well-specified units, but
|
||||||
* the input and output may come in some random format. This
|
* the input and output may come in some random format. This
|
||||||
|
@ -421,6 +436,7 @@ extern void remember_event(const char *eventname);
|
||||||
extern void evn_foreach(void (*callback)(const char *, int *, void *), void *data);
|
extern void evn_foreach(void (*callback)(const char *, int *, void *), void *data);
|
||||||
|
|
||||||
extern int add_new_dive(struct dive *dive);
|
extern int add_new_dive(struct dive *dive);
|
||||||
|
extern gboolean edit_trip(struct dive *trip);
|
||||||
extern int edit_dive_info(struct dive *dive);
|
extern int edit_dive_info(struct dive *dive);
|
||||||
extern int edit_multi_dive_info(struct dive *single_dive);
|
extern int edit_multi_dive_info(struct dive *single_dive);
|
||||||
extern void dive_list_update_dives(void);
|
extern void dive_list_update_dives(void);
|
||||||
|
|
647
divelist.c
647
divelist.c
|
@ -31,6 +31,13 @@ struct DiveList {
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct DiveList dive_list;
|
static struct DiveList dive_list;
|
||||||
|
#define MODEL(_dl) GTK_TREE_MODEL((_dl).model)
|
||||||
|
#define TREEMODEL(_dl) GTK_TREE_MODEL((_dl).treemodel)
|
||||||
|
#define LISTMODEL(_dl) GTK_TREE_MODEL((_dl).listmodel)
|
||||||
|
#define STORE(_dl) GTK_TREE_STORE((_dl).model)
|
||||||
|
#define TREESTORE(_dl) GTK_TREE_STORE((_dl).treemodel)
|
||||||
|
#define LISTSTORE(_dl) GTK_TREE_STORE((_dl).listmodel)
|
||||||
|
|
||||||
GList *dive_trip_list;
|
GList *dive_trip_list;
|
||||||
gboolean autogroup = FALSE;
|
gboolean autogroup = FALSE;
|
||||||
|
|
||||||
|
@ -65,9 +72,17 @@ static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
|
||||||
char *location;
|
char *location;
|
||||||
int idx, nr, duration;
|
int idx, nr, duration;
|
||||||
struct dive *dive;
|
struct dive *dive;
|
||||||
|
time_t when;
|
||||||
|
struct tm *tm;
|
||||||
|
|
||||||
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1);
|
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, DIVE_DATE, &when,
|
||||||
printf("entry #%d : nr %d duration %d location %s ", idx, nr, duration, location);
|
DIVE_DURATION, &duration, DIVE_LOCATION, &location, -1);
|
||||||
|
tm = gmtime(&when);
|
||||||
|
printf("iter %x:%x entry #%d : nr %d @ %04d-%02d-%02d %02d:%02d:%02d duration %d location %s ",
|
||||||
|
iter->stamp, iter->user_data, idx, nr,
|
||||||
|
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
|
||||||
|
tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||||
|
duration, location);
|
||||||
dive = get_dive(idx);
|
dive = get_dive(idx);
|
||||||
if (dive)
|
if (dive)
|
||||||
printf("tripflag %d\n", dive->tripflag);
|
printf("tripflag %d\n", dive->tripflag);
|
||||||
|
@ -82,6 +97,7 @@ static gboolean dump_model_entry(GtkTreeModel *model, GtkTreePath *path,
|
||||||
static void dump_model(GtkListStore *store)
|
static void dump_model(GtkListStore *store)
|
||||||
{
|
{
|
||||||
gtk_tree_model_foreach(GTK_TREE_MODEL(store), dump_model_entry, NULL);
|
gtk_tree_model_foreach(GTK_TREE_MODEL(store), dump_model_entry, NULL);
|
||||||
|
printf("\n---\n\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -116,7 +132,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx)
|
||||||
return;
|
return;
|
||||||
if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath))
|
if(!gtk_tree_view_row_expanded(GTK_TREE_VIEW(dive_list.tree_view), tpath))
|
||||||
gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE);
|
gtk_tree_view_expand_row(GTK_TREE_VIEW(dive_list.tree_view), tpath, FALSE);
|
||||||
gtk_tree_model_get(GTK_TREE_MODEL(model), iter, DIVE_INDEX, diveidx, -1);
|
gtk_tree_model_get(model, iter, DIVE_INDEX, diveidx, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +141,7 @@ static void first_leaf(GtkTreeModel *model, GtkTreeIter *iter, int *diveidx)
|
||||||
void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
|
void row_expanded_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
|
||||||
{
|
{
|
||||||
GtkTreeIter child;
|
GtkTreeIter child;
|
||||||
GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
|
GtkTreeModel *model = MODEL(dive_list);
|
||||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
|
|
||||||
if (!gtk_tree_model_iter_children(model, &child, iter))
|
if (!gtk_tree_model_iter_children(model, &child, iter))
|
||||||
|
@ -169,7 +185,7 @@ static int selected_children(GtkTreeModel *model, GtkTreeIter *iter)
|
||||||
shows up as selected too */
|
shows up as selected too */
|
||||||
void row_collapsed_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
|
void row_collapsed_cb(GtkTreeView *tree_view, GtkTreeIter *iter, GtkTreePath *path, gpointer data)
|
||||||
{
|
{
|
||||||
GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
|
GtkTreeModel *model = MODEL(dive_list);
|
||||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
|
|
||||||
if (selected_children(model, iter))
|
if (selected_children(model, iter))
|
||||||
|
@ -253,7 +269,7 @@ static void select_dive_group(GtkTreeModel *model, GtkTreeSelection *selection,
|
||||||
*/
|
*/
|
||||||
static void check_selection_cb(GtkTreeIter *iter, GtkTreeSelection *selection)
|
static void check_selection_cb(GtkTreeIter *iter, GtkTreeSelection *selection)
|
||||||
{
|
{
|
||||||
GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
|
GtkTreeModel *model = MODEL(dive_list);
|
||||||
struct dive *dive;
|
struct dive *dive;
|
||||||
int idx, gtk_selected;
|
int idx, gtk_selected;
|
||||||
|
|
||||||
|
@ -449,13 +465,20 @@ static void nr_data_func(GtkTreeViewColumn *col,
|
||||||
{
|
{
|
||||||
int idx, nr;
|
int idx, nr;
|
||||||
char buffer[40];
|
char buffer[40];
|
||||||
|
struct dive *dive;
|
||||||
|
|
||||||
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, -1);
|
gtk_tree_model_get(model, iter, DIVE_INDEX, &idx, DIVE_NR, &nr, -1);
|
||||||
if (idx < 0)
|
if (idx < 0) {
|
||||||
*buffer = '\0';
|
*buffer = '\0';
|
||||||
else
|
} else {
|
||||||
snprintf(buffer, sizeof(buffer), "%d", nr);
|
/* make dives that are not in trips stand out */
|
||||||
g_object_set(renderer, "text", buffer, NULL);
|
dive = get_dive(idx);
|
||||||
|
if (!DIVE_IN_TRIP(dive))
|
||||||
|
snprintf(buffer, sizeof(buffer), "<b>%d</b>", nr);
|
||||||
|
else
|
||||||
|
snprintf(buffer, sizeof(buffer), "%d", nr);
|
||||||
|
}
|
||||||
|
g_object_set(renderer, "markup", buffer, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -787,7 +810,7 @@ static void fill_one_dive(struct dive *dive,
|
||||||
GtkTreeIter *iter)
|
GtkTreeIter *iter)
|
||||||
{
|
{
|
||||||
char *location, *cylinder, *suit;
|
char *location, *cylinder, *suit;
|
||||||
GtkTreeStore *othermodel;
|
GtkTreeModel *othermodel;
|
||||||
|
|
||||||
get_cylinder(dive, &cylinder);
|
get_cylinder(dive, &cylinder);
|
||||||
get_location(dive, &location);
|
get_location(dive, &location);
|
||||||
|
@ -808,13 +831,13 @@ static void fill_one_dive(struct dive *dive,
|
||||||
free(cylinder);
|
free(cylinder);
|
||||||
free(suit);
|
free(suit);
|
||||||
|
|
||||||
if (model == GTK_TREE_MODEL(dive_list.treemodel))
|
if (model == TREEMODEL(dive_list))
|
||||||
othermodel = dive_list.listmodel;
|
othermodel = LISTMODEL(dive_list);
|
||||||
else
|
else
|
||||||
othermodel = dive_list.treemodel;
|
othermodel = TREEMODEL(dive_list);
|
||||||
if (othermodel != dive_list.model)
|
if (othermodel != MODEL(dive_list))
|
||||||
/* recursive call */
|
/* recursive call */
|
||||||
gtk_tree_model_foreach(GTK_TREE_MODEL(othermodel), set_one_dive, dive);
|
gtk_tree_model_foreach(othermodel, set_one_dive, dive);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean set_one_dive(GtkTreeModel *model,
|
static gboolean set_one_dive(GtkTreeModel *model,
|
||||||
|
@ -841,7 +864,7 @@ static gboolean set_one_dive(GtkTreeModel *model,
|
||||||
|
|
||||||
void flush_divelist(struct dive *dive)
|
void flush_divelist(struct dive *dive)
|
||||||
{
|
{
|
||||||
GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
|
GtkTreeModel *model = MODEL(dive_list);
|
||||||
|
|
||||||
gtk_tree_model_foreach(model, set_one_dive, dive);
|
gtk_tree_model_foreach(model, set_one_dive, dive);
|
||||||
}
|
}
|
||||||
|
@ -856,7 +879,7 @@ void set_divelist_font(const char *font)
|
||||||
void update_dive_list_units(void)
|
void update_dive_list_units(void)
|
||||||
{
|
{
|
||||||
const char *unit;
|
const char *unit;
|
||||||
GtkTreeModel *model = GTK_TREE_MODEL(dive_list.model);
|
GtkTreeModel *model = MODEL(dive_list);
|
||||||
|
|
||||||
(void) get_depth_units(0, NULL, &unit);
|
(void) get_depth_units(0, NULL, &unit);
|
||||||
gtk_tree_view_column_set_title(dive_list.depth, unit);
|
gtk_tree_view_column_set_title(dive_list.depth, unit);
|
||||||
|
@ -882,6 +905,28 @@ void update_dive_list_col_visibility(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GList *find_matching_trip(time_t when)
|
||||||
|
{
|
||||||
|
GList *trip = dive_trip_list;
|
||||||
|
if (!trip || DIVE_TRIP(trip)->when > when)
|
||||||
|
return NULL;
|
||||||
|
while (trip->next && DIVE_TRIP(trip->next)->when <= when)
|
||||||
|
trip = trip->next;
|
||||||
|
return trip;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct dive *create_and_hookup_trip_from_dive(struct dive *dive)
|
||||||
|
{
|
||||||
|
struct dive *dive_trip = alloc_dive();
|
||||||
|
dive_trip->when = dive->when;
|
||||||
|
if (dive->location)
|
||||||
|
dive_trip->location = strdup(dive->location);
|
||||||
|
insert_trip(&dive_trip);
|
||||||
|
dive->divetrip = dive_trip;
|
||||||
|
dive->tripflag = IN_TRIP;
|
||||||
|
return dive_trip;
|
||||||
|
}
|
||||||
|
|
||||||
static void fill_dive_list(void)
|
static void fill_dive_list(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -894,8 +939,8 @@ static void fill_dive_list(void)
|
||||||
/* if we have pre-existing trips, start on the last one */
|
/* if we have pre-existing trips, start on the last one */
|
||||||
trip = g_list_last(dive_trip_list);
|
trip = g_list_last(dive_trip_list);
|
||||||
|
|
||||||
treestore = GTK_TREE_STORE(dive_list.treemodel);
|
treestore = TREESTORE(dive_list);
|
||||||
liststore = GTK_TREE_STORE(dive_list.listmodel);
|
liststore = LISTSTORE(dive_list);
|
||||||
|
|
||||||
i = dive_table.nr;
|
i = dive_table.nr;
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
|
@ -924,35 +969,25 @@ static void fill_dive_list(void)
|
||||||
if ( ! dive_trip || ! DIVE_FITS_TRIP(dive, dive_trip)) {
|
if ( ! dive_trip || ! DIVE_FITS_TRIP(dive, dive_trip)) {
|
||||||
/* allocate new trip - all fields default to 0
|
/* allocate new trip - all fields default to 0
|
||||||
and get filled in further down */
|
and get filled in further down */
|
||||||
dive_trip = alloc_dive();
|
dive_trip = create_and_hookup_trip_from_dive(dive);
|
||||||
dive_trip_list = insert_trip(dive_trip, dive_trip_list);
|
dive_trip->tripflag = IN_TRIP; /* this marks an autogen trip */
|
||||||
trip = FIND_TRIP(dive_trip, dive_trip_list);
|
trip = FIND_TRIP(dive_trip->when);
|
||||||
}
|
|
||||||
} else { /* either the dive has a trip or we aren't creating trips */
|
|
||||||
if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) {
|
|
||||||
GList *last_trip = trip;
|
|
||||||
trip = PREV_TRIP(trip, dive_trip_list);
|
|
||||||
if (! (trip && DIVE_FITS_TRIP(dive, DIVE_TRIP(trip)))) {
|
|
||||||
/* we could get here if there are no trips in the XML file
|
|
||||||
* and we aren't creating trips, either.
|
|
||||||
* Otherwise we need to create a new trip */
|
|
||||||
if (autogroup) {
|
|
||||||
dive_trip = alloc_dive();
|
|
||||||
dive_trip_list = insert_trip(dive_trip, dive_trip_list);
|
|
||||||
trip = FIND_TRIP(dive_trip, dive_trip_list);
|
|
||||||
} else {
|
|
||||||
/* let's go back to the last valid trip */
|
|
||||||
trip = last_trip;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dive_trip = trip->data;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else if (DIVE_IN_TRIP(dive)) {
|
||||||
|
trip = find_matching_trip(dive->when);
|
||||||
|
dive_trip = DIVE_TRIP(trip);
|
||||||
|
} else {
|
||||||
|
/* dive is not in a trip and we aren't autogrouping */
|
||||||
|
dive_trip = NULL;
|
||||||
|
parent_ptr = NULL;
|
||||||
}
|
}
|
||||||
/* update dive_trip time and (if necessary) location */
|
/* update dive as part of dive_trip and
|
||||||
|
* (if necessary) update dive_trip time and location */
|
||||||
if (dive_trip) {
|
if (dive_trip) {
|
||||||
dive->tripflag = IN_TRIP;
|
dive->tripflag = IN_TRIP;
|
||||||
dive_trip->when = dive->when;
|
dive->divetrip = dive_trip;
|
||||||
|
if (dive_trip->when > dive->when)
|
||||||
|
dive_trip->when = dive->when;
|
||||||
if (!dive_trip->location && dive->location)
|
if (!dive_trip->location && dive->location)
|
||||||
dive_trip->location = dive->location;
|
dive_trip->location = dive->location;
|
||||||
if (dive_trip != last_trip) {
|
if (dive_trip != last_trip) {
|
||||||
|
@ -1007,12 +1042,12 @@ static void fill_dive_list(void)
|
||||||
DIVE_LOCATION, dive_trip->location,
|
DIVE_LOCATION, dive_trip->location,
|
||||||
-1);
|
-1);
|
||||||
update_dive_list_units();
|
update_dive_list_units();
|
||||||
if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(dive_list.model), &iter)) {
|
if (gtk_tree_model_get_iter_first(MODEL(dive_list), &iter)) {
|
||||||
GtkTreeSelection *selection;
|
GtkTreeSelection *selection;
|
||||||
|
|
||||||
/* select the last dive (and make sure it's an actual dive that is selected) */
|
/* select the last dive (and make sure it's an actual dive that is selected) */
|
||||||
gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &selected_dive, -1);
|
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &selected_dive, -1);
|
||||||
first_leaf(GTK_TREE_MODEL(dive_list.model), &iter, &selected_dive);
|
first_leaf(MODEL(dive_list), &iter, &selected_dive);
|
||||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
gtk_tree_selection_select_iter(selection, &iter);
|
gtk_tree_selection_select_iter(selection, &iter);
|
||||||
}
|
}
|
||||||
|
@ -1020,8 +1055,8 @@ static void fill_dive_list(void)
|
||||||
|
|
||||||
void dive_list_update_dives(void)
|
void dive_list_update_dives(void)
|
||||||
{
|
{
|
||||||
gtk_tree_store_clear(GTK_TREE_STORE(dive_list.treemodel));
|
gtk_tree_store_clear(TREESTORE(dive_list));
|
||||||
gtk_tree_store_clear(GTK_TREE_STORE(dive_list.listmodel));
|
gtk_tree_store_clear(LISTSTORE(dive_list));
|
||||||
fill_dive_list();
|
fill_dive_list();
|
||||||
repaint_dive();
|
repaint_dive();
|
||||||
}
|
}
|
||||||
|
@ -1106,10 +1141,10 @@ static void row_activated_cb(GtkTreeView *tree_view,
|
||||||
int index;
|
int index;
|
||||||
GtkTreeIter iter;
|
GtkTreeIter iter;
|
||||||
|
|
||||||
if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(dive_list.model), &iter, path))
|
if (!gtk_tree_model_get_iter(MODEL(dive_list), &iter, path))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gtk_tree_model_get(GTK_TREE_MODEL(dive_list.model), &iter, DIVE_INDEX, &index, -1);
|
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &index, -1);
|
||||||
/* a negative index is special for the "group by date" entries */
|
/* a negative index is special for the "group by date" entries */
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
collapse_expand(tree_view, path);
|
collapse_expand(tree_view, path);
|
||||||
|
@ -1131,11 +1166,39 @@ void add_dive_cb(GtkWidget *menuitem, gpointer data)
|
||||||
free(dive);
|
free(dive);
|
||||||
}
|
}
|
||||||
|
|
||||||
void edit_dive_cb(GtkWidget *menuitem, gpointer data)
|
void edit_trip_cb(GtkWidget *menuitem, GtkTreePath *path)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
time_t when;
|
||||||
|
struct dive *dive_trip;
|
||||||
|
GList *trip;
|
||||||
|
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_DATE, &when, -1);
|
||||||
|
trip = FIND_TRIP(when);
|
||||||
|
dive_trip = DIVE_TRIP(trip);
|
||||||
|
if (edit_trip(dive_trip))
|
||||||
|
gtk_tree_store_set(STORE(dive_list), &iter, DIVE_LOCATION, dive_trip->location, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void edit_selected_dives_cb(GtkWidget *menuitem, gpointer data)
|
||||||
{
|
{
|
||||||
edit_multi_dive_info(NULL);
|
edit_multi_dive_info(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void edit_dive_from_path_cb(GtkWidget *menuitem, GtkTreePath *path)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
int idx;
|
||||||
|
struct dive *dive;
|
||||||
|
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
|
||||||
|
dive = get_dive(idx);
|
||||||
|
|
||||||
|
edit_multi_dive_info(dive);
|
||||||
|
}
|
||||||
|
|
||||||
static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view)
|
static void expand_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view)
|
||||||
{
|
{
|
||||||
gtk_tree_view_expand_all(tree_view);
|
gtk_tree_view_expand_all(tree_view);
|
||||||
|
@ -1146,10 +1209,382 @@ static void collapse_all_cb(GtkWidget *menuitem, GtkTreeView *tree_view)
|
||||||
gtk_tree_view_collapse_all(tree_view);
|
gtk_tree_view_collapse_all(tree_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button)
|
/* copy the node and return the index */
|
||||||
|
static int copy_tree_node(GtkTreeIter *a, GtkTreeIter *b)
|
||||||
|
{
|
||||||
|
struct dive store_dive;
|
||||||
|
int totalweight, idx;
|
||||||
|
char *cylinder_text;
|
||||||
|
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), a,
|
||||||
|
DIVE_INDEX, &idx,
|
||||||
|
DIVE_NR, &store_dive.number,
|
||||||
|
DIVE_DATE, &store_dive.when,
|
||||||
|
DIVE_RATING, &store_dive.rating,
|
||||||
|
DIVE_DEPTH, &store_dive.maxdepth,
|
||||||
|
DIVE_DURATION, &store_dive.duration,
|
||||||
|
DIVE_TEMPERATURE, &store_dive.watertemp.mkelvin,
|
||||||
|
DIVE_TOTALWEIGHT, &totalweight,
|
||||||
|
DIVE_SUIT, &store_dive.suit,
|
||||||
|
DIVE_CYLINDER, &cylinder_text,
|
||||||
|
DIVE_SAC, &store_dive.sac,
|
||||||
|
DIVE_OTU, &store_dive.otu,
|
||||||
|
DIVE_LOCATION, &store_dive.location,
|
||||||
|
-1);
|
||||||
|
gtk_tree_store_set(STORE(dive_list), b,
|
||||||
|
DIVE_INDEX, idx,
|
||||||
|
DIVE_NR, store_dive.number,
|
||||||
|
DIVE_DATE, store_dive.when,
|
||||||
|
DIVE_RATING, store_dive.rating,
|
||||||
|
DIVE_DEPTH, store_dive.maxdepth,
|
||||||
|
DIVE_DURATION, store_dive.duration,
|
||||||
|
DIVE_TEMPERATURE, store_dive.watertemp.mkelvin,
|
||||||
|
DIVE_TOTALWEIGHT, totalweight,
|
||||||
|
DIVE_SUIT, store_dive.suit,
|
||||||
|
DIVE_CYLINDER, cylinder_text,
|
||||||
|
DIVE_SAC, store_dive.sac,
|
||||||
|
DIVE_OTU, store_dive.otu,
|
||||||
|
DIVE_LOCATION, store_dive.location,
|
||||||
|
-1);
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* to avoid complicated special cases based on ordering or number of children,
|
||||||
|
we always take the first and last child and pick the smaller time_t (which
|
||||||
|
works regardless of ordering and also with just one child) */
|
||||||
|
static void update_trip_timestamp(GtkTreeIter *parent, struct dive *divetrip)
|
||||||
|
{
|
||||||
|
GtkTreeIter first_child, last_child;
|
||||||
|
int nr;
|
||||||
|
time_t t1, t2, tnew;
|
||||||
|
|
||||||
|
if (gtk_tree_store_iter_depth(STORE(dive_list), parent) != 0 ||
|
||||||
|
gtk_tree_model_iter_n_children(MODEL(dive_list), parent) == 0)
|
||||||
|
return;
|
||||||
|
nr = gtk_tree_model_iter_n_children(MODEL(dive_list), parent);
|
||||||
|
gtk_tree_model_iter_nth_child(MODEL(dive_list), &first_child, parent, 0);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &first_child, DIVE_DATE, &t1, -1);
|
||||||
|
gtk_tree_model_iter_nth_child(MODEL(dive_list), &last_child, parent, nr - 1);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &last_child, DIVE_DATE, &t2, -1);
|
||||||
|
tnew = MIN(t1, t2);
|
||||||
|
gtk_tree_store_set(STORE(dive_list), parent, DIVE_DATE, tnew, -1);
|
||||||
|
if (divetrip)
|
||||||
|
divetrip->when = tnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move dive_iter, which is a child of old_trip (could be NULL) to new_trip (could be NULL);
|
||||||
|
* either of the trips being NULL means that this was (or will be) a dive without a trip;
|
||||||
|
* update the dive trips (especially the starting times) accordingly
|
||||||
|
* maintain the selected status of the dive
|
||||||
|
* IMPORTANT - the move needs to keep the tree consistant - so no out of order moving... */
|
||||||
|
static GtkTreeIter *move_dive_between_trips(GtkTreeIter *dive_iter, GtkTreeIter *old_trip, GtkTreeIter *new_trip,
|
||||||
|
GtkTreeIter *sibling, gboolean before)
|
||||||
|
{
|
||||||
|
int idx;
|
||||||
|
time_t old_when, new_when;
|
||||||
|
struct dive *dive, *old_divetrip, *new_divetrip;
|
||||||
|
GtkTreeIter *new_iter = malloc(sizeof(GtkTreeIter));
|
||||||
|
|
||||||
|
if (before)
|
||||||
|
gtk_tree_store_insert_before(STORE(dive_list), new_iter, new_trip, sibling);
|
||||||
|
else
|
||||||
|
gtk_tree_store_insert_after(STORE(dive_list), new_iter, new_trip, sibling);
|
||||||
|
idx = copy_tree_node(dive_iter, new_iter);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), new_iter, DIVE_INDEX, &idx, -1);
|
||||||
|
dive = get_dive(idx);
|
||||||
|
gtk_tree_store_remove(STORE(dive_list), dive_iter);
|
||||||
|
if (old_trip) {
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), old_trip, DIVE_DATE, &old_when, -1);
|
||||||
|
old_divetrip = DIVE_TRIP(find_matching_trip(old_when));
|
||||||
|
update_trip_timestamp(old_trip, old_divetrip);
|
||||||
|
}
|
||||||
|
if (new_trip) {
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), new_trip, DIVE_DATE, &new_when, -1);
|
||||||
|
new_divetrip = dive->divetrip;
|
||||||
|
update_trip_timestamp(new_trip, new_divetrip);
|
||||||
|
}
|
||||||
|
if (dive->selected) {
|
||||||
|
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
|
gtk_tree_selection_select_iter(selection, new_iter);
|
||||||
|
}
|
||||||
|
return new_iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void turn_dive_into_trip(GtkTreePath *path)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter, *newiter, newparent;
|
||||||
|
GtkTreePath *treepath;
|
||||||
|
time_t when;
|
||||||
|
char *location;
|
||||||
|
int idx;
|
||||||
|
struct dive *dive;
|
||||||
|
|
||||||
|
/* this is a dive on the top level, insert trip AFTER it, populate its date / location, and
|
||||||
|
* then move the dive below that trip */
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||||
|
gtk_tree_store_insert_after(STORE(dive_list), &newparent, NULL, &iter);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &iter,
|
||||||
|
DIVE_INDEX, &idx, DIVE_DATE, &when, DIVE_LOCATION, &location, -1);
|
||||||
|
gtk_tree_store_set(STORE(dive_list), &newparent,
|
||||||
|
DIVE_INDEX, -1, DIVE_DATE, when, DIVE_LOCATION, location, -1);
|
||||||
|
free(location);
|
||||||
|
newiter = move_dive_between_trips(&iter, NULL, &newparent, NULL, FALSE);
|
||||||
|
treepath = gtk_tree_model_get_path(MODEL(dive_list), newiter);
|
||||||
|
gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath);
|
||||||
|
dive = get_dive(idx);
|
||||||
|
/* we don't need the return value - everything is hooked up in the function */
|
||||||
|
(void)create_and_hookup_trip_from_dive(dive);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we know that path is pointing at a dive in a trip and are asked to split this trip into two */
|
||||||
|
static void insert_trip_before(GtkTreePath *path)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter, prev_iter, parent, newparent, nextsibling;
|
||||||
|
GtkTreePath *treepath, *prev_path;
|
||||||
|
struct dive *dive, *prev_dive, *new_divetrip;
|
||||||
|
int idx, nr, i;
|
||||||
|
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||||
|
prev_path = gtk_tree_path_copy(path);
|
||||||
|
if (!gtk_tree_path_prev(prev_path) ||
|
||||||
|
!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter))
|
||||||
|
return;
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &prev_iter, prev_path);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &prev_iter, DIVE_INDEX, &idx, -1);
|
||||||
|
prev_dive = get_dive(idx);
|
||||||
|
gtk_tree_store_insert_after(STORE(dive_list), &newparent, NULL, &parent);
|
||||||
|
copy_tree_node(&parent, &newparent);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
|
||||||
|
dive = get_dive(idx);
|
||||||
|
/* make sure that the time_t of the previous divetrip is correct before
|
||||||
|
* inserting a new one */
|
||||||
|
if (dive->when < prev_dive->when)
|
||||||
|
if (prev_dive->divetrip && prev_dive->divetrip->when < prev_dive->when)
|
||||||
|
prev_dive->divetrip->when = prev_dive->when;
|
||||||
|
new_divetrip = create_and_hookup_trip_from_dive(dive);
|
||||||
|
|
||||||
|
/* in order for the data structures to stay consistent we need to walk from
|
||||||
|
* the last child backwards to this one. The easiest way seems to be to do
|
||||||
|
* this with the nth iterator API */
|
||||||
|
nr = gtk_tree_model_iter_n_children(MODEL(dive_list), &parent);
|
||||||
|
for (i = nr - 1; i >= 0; i--) {
|
||||||
|
gtk_tree_model_iter_nth_child(MODEL(dive_list), &nextsibling, &parent, i);
|
||||||
|
treepath = gtk_tree_model_get_path(MODEL(dive_list), &nextsibling);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &nextsibling, DIVE_INDEX, &idx, -1);
|
||||||
|
dive = get_dive(idx);
|
||||||
|
dive->divetrip = new_divetrip;
|
||||||
|
if (dive->when < dive->divetrip->when)
|
||||||
|
dive->divetrip->when = dive->when;
|
||||||
|
(void) move_dive_between_trips(&nextsibling, &parent, &newparent, NULL, FALSE);
|
||||||
|
if (gtk_tree_path_compare(path, treepath) == 0)
|
||||||
|
/* we copied the dive we were called with; we are done */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
treepath = gtk_tree_model_get_path(MODEL(dive_list), &newparent);
|
||||||
|
gtk_tree_view_expand_to_path(GTK_TREE_VIEW(dive_list.tree_view), treepath);
|
||||||
|
#ifdef DEBUG_TRIP
|
||||||
|
dump_trip_list();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void insert_trip_before_cb(GtkWidget *menuitem, GtkTreePath *path)
|
||||||
|
{
|
||||||
|
/* is this splitting a trip or turning a dive into a trip? */
|
||||||
|
if (gtk_tree_path_get_depth(path) == 2)
|
||||||
|
insert_trip_before(path);
|
||||||
|
else
|
||||||
|
turn_dive_into_trip(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_from_trip(GtkTreePath *path)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter, nextiter, *newiter, parent;
|
||||||
|
GtkTreePath *nextpath;
|
||||||
|
struct dive *dive;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||||
|
if (!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter))
|
||||||
|
return;
|
||||||
|
/* if this isn't the last dive in a trip we simply split the trip
|
||||||
|
in two right after this dive */
|
||||||
|
nextpath = gtk_tree_path_copy(path);
|
||||||
|
gtk_tree_path_next(nextpath);
|
||||||
|
if (gtk_tree_model_get_iter(MODEL(dive_list), &nextiter, nextpath))
|
||||||
|
insert_trip_before(nextpath);
|
||||||
|
/* now move the dive to the top level, as sibling after its former parent */
|
||||||
|
newiter = move_dive_between_trips(&iter, &parent, NULL, &parent, FALSE);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), newiter, DIVE_INDEX, &idx, -1);
|
||||||
|
dive = get_dive(idx);
|
||||||
|
if (dive->selected) {
|
||||||
|
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
|
gtk_tree_selection_select_iter(selection, newiter);
|
||||||
|
}
|
||||||
|
/* if this was the last dive on the trip, remove the trip */
|
||||||
|
if (! gtk_tree_model_iter_has_child(MODEL(dive_list), &parent)) {
|
||||||
|
gtk_tree_store_remove(STORE(dive_list), &parent);
|
||||||
|
delete_trip(FIND_TRIP(dive->divetrip->when));
|
||||||
|
free(dive->divetrip);
|
||||||
|
}
|
||||||
|
/* mark the dive as intentionally at the top level */
|
||||||
|
dive->tripflag = NO_TRIP;
|
||||||
|
dive->divetrip = NULL;
|
||||||
|
#ifdef DEBUG_TRIP
|
||||||
|
dump_trip_list();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_rowref_from_trip(gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
GtkTreeRowReference *rowref = data;
|
||||||
|
GtkTreePath *path = gtk_tree_row_reference_get_path(rowref);
|
||||||
|
if (path)
|
||||||
|
remove_from_trip(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean add_rowref_if_selected(GtkTreeModel *model, GtkTreePath *path,
|
||||||
|
GtkTreeIter *iter, gpointer data)
|
||||||
|
{
|
||||||
|
GList **rowref_list = data;
|
||||||
|
int idx;
|
||||||
|
struct dive *dive;
|
||||||
|
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), iter, DIVE_INDEX, &idx, -1);
|
||||||
|
if (idx >=0 ) {
|
||||||
|
dive = get_dive(idx);
|
||||||
|
if (dive->selected) {
|
||||||
|
/* we need to store the Row References as those
|
||||||
|
stay valid across modifications of the model */
|
||||||
|
GtkTreeRowReference *rowref;
|
||||||
|
rowref = gtk_tree_row_reference_new(TREEMODEL(dive_list), path);
|
||||||
|
*rowref_list = g_list_append(*rowref_list, rowref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE; /* continue foreach loop */
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_from_trip_cb(GtkWidget *menuitem, GtkTreePath *path)
|
||||||
|
{
|
||||||
|
GtkTreeIter iter, parent;
|
||||||
|
struct dive *dive;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||||
|
if (!gtk_tree_model_iter_parent(MODEL(dive_list), &parent, &iter))
|
||||||
|
return;
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
|
||||||
|
if (idx < 0 )
|
||||||
|
return;
|
||||||
|
dive = get_dive(idx);
|
||||||
|
if (dive->selected) {
|
||||||
|
/* remove all the selected dives
|
||||||
|
since removing the dives from trips changes the model we need to
|
||||||
|
take the extra step of acquiring rowrefs before actually moving dives */
|
||||||
|
GList *rowref_list = NULL;
|
||||||
|
gtk_tree_model_foreach(MODEL(dive_list), add_rowref_if_selected, &rowref_list);
|
||||||
|
/* We need to walk that list backwards as otherwise
|
||||||
|
the newly insered trips below dives that were
|
||||||
|
removed also mess with the validity */
|
||||||
|
rowref_list = g_list_reverse(rowref_list);
|
||||||
|
g_list_foreach(rowref_list, remove_rowref_from_trip, NULL);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/* just remove the dive the mouse pointer is on */
|
||||||
|
remove_from_trip(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_trip(GtkTreePath *trippath, gboolean force_no_trip)
|
||||||
|
{
|
||||||
|
GtkTreeIter newiter, parent, child, *lastiter = &parent;
|
||||||
|
struct dive *dive, *dive_trip = NULL;
|
||||||
|
int idx;
|
||||||
|
GtkTreePath *childpath;
|
||||||
|
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
|
|
||||||
|
/* what a pain - we can't just move the nodes, we have to
|
||||||
|
* create new ones and delete the existing ones instead */
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &parent, trippath);
|
||||||
|
childpath = gtk_tree_path_copy(trippath);
|
||||||
|
gtk_tree_path_down(childpath);
|
||||||
|
for (;;) {
|
||||||
|
if( ! gtk_tree_model_get_iter(MODEL(dive_list), &child, childpath))
|
||||||
|
break;
|
||||||
|
gtk_tree_store_insert_after(STORE(dive_list), &newiter, NULL, lastiter);
|
||||||
|
copy_tree_node(&child, &newiter);
|
||||||
|
/* we need to track what was selected */
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &child, DIVE_INDEX, &idx, -1);
|
||||||
|
dive = get_dive(idx);
|
||||||
|
if (dive->selected)
|
||||||
|
gtk_tree_selection_select_iter(selection, &newiter);
|
||||||
|
if (force_no_trip)
|
||||||
|
dive->tripflag = NO_TRIP;
|
||||||
|
else
|
||||||
|
dive->tripflag = TF_NONE;
|
||||||
|
if (!dive_trip)
|
||||||
|
dive_trip = dive->divetrip;
|
||||||
|
dive->divetrip = NULL;
|
||||||
|
/* this removes the child - now childpath points to the next child */
|
||||||
|
gtk_tree_store_remove(STORE(dive_list), &child);
|
||||||
|
lastiter = &newiter;
|
||||||
|
}
|
||||||
|
/* finally, remove the trip */
|
||||||
|
gtk_tree_store_remove(STORE(dive_list), &parent);
|
||||||
|
delete_trip(FIND_TRIP(dive_trip->when));
|
||||||
|
free(dive_trip);
|
||||||
|
#ifdef DEBUG_TRIP
|
||||||
|
dump_trip_list();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void remove_trip_cb(GtkWidget *menuitem, GtkTreePath *trippath)
|
||||||
|
{
|
||||||
|
remove_trip(trippath, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge_trips_cb(GtkWidget *menuitem, GtkTreePath *trippath)
|
||||||
|
{
|
||||||
|
GtkTreePath *prevpath;
|
||||||
|
GtkTreeIter thistripiter, prevtripiter, newiter, iter;
|
||||||
|
GtkTreeModel *tm = MODEL(dive_list);
|
||||||
|
GList *trip, *prevtrip;
|
||||||
|
time_t when;
|
||||||
|
|
||||||
|
/* this only gets called when we are on a trip and there is another trip right before */
|
||||||
|
prevpath = gtk_tree_path_copy(trippath);
|
||||||
|
gtk_tree_path_prev(prevpath);
|
||||||
|
gtk_tree_model_get_iter(tm, &thistripiter, trippath);
|
||||||
|
gtk_tree_model_get(tm, &thistripiter, DIVE_DATE, &when, -1);
|
||||||
|
trip = find_matching_trip(when);
|
||||||
|
gtk_tree_model_get_iter(tm, &prevtripiter, prevpath);
|
||||||
|
gtk_tree_model_get(tm, &prevtripiter, DIVE_DATE, &when, -1);
|
||||||
|
prevtrip = find_matching_trip(when);
|
||||||
|
while (gtk_tree_model_iter_children(tm, &iter, &thistripiter)) {
|
||||||
|
int idx;
|
||||||
|
gtk_tree_store_insert_before(STORE(dive_list), &newiter, &prevtripiter, NULL);
|
||||||
|
idx = copy_tree_node(&iter, &newiter);
|
||||||
|
gtk_tree_store_remove(STORE(dive_list), &iter);
|
||||||
|
get_dive(idx)->divetrip = DIVE_TRIP(prevtrip);
|
||||||
|
}
|
||||||
|
update_trip_timestamp(&prevtripiter, DIVE_TRIP(prevtrip));
|
||||||
|
free(DIVE_TRIP(trip));
|
||||||
|
delete_trip(trip);
|
||||||
|
gtk_tree_store_remove(STORE(dive_list), &thistripiter);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int button, GdkEventButton *event)
|
||||||
{
|
{
|
||||||
GtkWidget *menu, *menuitem, *image;
|
GtkWidget *menu, *menuitem, *image;
|
||||||
char editlabel[] = "Edit dives";
|
char editlabel[] = "Edit dives";
|
||||||
|
GtkTreePath *path, *prevpath, *nextpath;
|
||||||
|
GtkTreeIter iter, previter, nextiter;
|
||||||
|
int idx, previdx, nextidx;
|
||||||
|
struct dive *dive;
|
||||||
|
|
||||||
|
if (!gtk_tree_view_get_path_at_pos(tree_view, event->x, event->y, &path, NULL, NULL, NULL))
|
||||||
|
return;
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &iter, path);
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &iter, DIVE_INDEX, &idx, -1);
|
||||||
|
|
||||||
menu = gtk_menu_new();
|
menu = gtk_menu_new();
|
||||||
menuitem = gtk_image_menu_item_new_with_label("Add dive");
|
menuitem = gtk_image_menu_item_new_with_label("Add dive");
|
||||||
|
@ -1157,12 +1592,69 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
|
||||||
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
|
gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(menuitem), image);
|
||||||
g_signal_connect(menuitem, "activate", G_CALLBACK(add_dive_cb), NULL);
|
g_signal_connect(menuitem, "activate", G_CALLBACK(add_dive_cb), NULL);
|
||||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
if (amount_selected) {
|
|
||||||
if (amount_selected == 1)
|
if (idx < 0) {
|
||||||
editlabel[strlen(editlabel) - 1] = '\0';
|
/* mouse pointer is on a trip summary entry */
|
||||||
menuitem = gtk_menu_item_new_with_label(editlabel);
|
menuitem = gtk_menu_item_new_with_label("Edit Trip Summary");
|
||||||
g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_cb), model);
|
g_signal_connect(menuitem, "activate", G_CALLBACK(edit_trip_cb), path);
|
||||||
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
prevpath = gtk_tree_path_copy(path);
|
||||||
|
if (gtk_tree_path_prev(prevpath) &&
|
||||||
|
gtk_tree_model_get_iter(MODEL(dive_list), &previter, prevpath)) {
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &previter, DIVE_INDEX, &previdx, -1);
|
||||||
|
if (previdx < 0) {
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Merge trip with trip above");
|
||||||
|
g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), path);
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextpath = gtk_tree_path_copy(path);
|
||||||
|
gtk_tree_path_next(nextpath);
|
||||||
|
if (gtk_tree_model_get_iter(MODEL(dive_list), &nextiter, nextpath)) {
|
||||||
|
gtk_tree_model_get(MODEL(dive_list), &nextiter, DIVE_INDEX, &nextidx, -1);
|
||||||
|
if (nextidx < 0) {
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Merge trip with trip below");
|
||||||
|
g_signal_connect(menuitem, "activate", G_CALLBACK(merge_trips_cb), nextpath);
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Remove Trip");
|
||||||
|
g_signal_connect(menuitem, "activate", G_CALLBACK(remove_trip_cb), path);
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
} else {
|
||||||
|
dive = get_dive(idx);
|
||||||
|
/* if we right click on selected dive(s), edit those */
|
||||||
|
if (dive->selected) {
|
||||||
|
if (amount_selected == 1)
|
||||||
|
editlabel[strlen(editlabel) - 1] = '\0';
|
||||||
|
menuitem = gtk_menu_item_new_with_label(editlabel);
|
||||||
|
g_signal_connect(menuitem, "activate", G_CALLBACK(edit_selected_dives_cb), NULL);
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
} else {
|
||||||
|
editlabel[strlen(editlabel) - 1] = '\0';
|
||||||
|
menuitem = gtk_menu_item_new_with_label(editlabel);
|
||||||
|
g_signal_connect(menuitem, "activate", G_CALLBACK(edit_dive_from_path_cb), path);
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
}
|
||||||
|
/* only offer trip editing options when we are displaying the tree model */
|
||||||
|
if (dive_list.model == dive_list.treemodel) {
|
||||||
|
int depth;
|
||||||
|
int *indices = gtk_tree_path_get_indices_with_depth(path, &depth);
|
||||||
|
|
||||||
|
if (depth == 1 || indices[1] > 0) {
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Add new trip above");
|
||||||
|
g_signal_connect(menuitem, "activate", G_CALLBACK(insert_trip_before_cb), path);
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
}
|
||||||
|
if (DIVE_IN_TRIP(dive)) {
|
||||||
|
if (dive->selected && amount_selected > 1)
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Remove selected dives from trip");
|
||||||
|
else
|
||||||
|
menuitem = gtk_menu_item_new_with_label("Remove dive from trip");
|
||||||
|
g_signal_connect(menuitem, "activate", G_CALLBACK(remove_from_trip_cb), path);
|
||||||
|
gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
menuitem = gtk_menu_item_new_with_label("Expand all");
|
menuitem = gtk_menu_item_new_with_label("Expand all");
|
||||||
g_signal_connect(menuitem, "activate", G_CALLBACK(expand_all_cb), tree_view);
|
g_signal_connect(menuitem, "activate", G_CALLBACK(expand_all_cb), tree_view);
|
||||||
|
@ -1178,14 +1670,14 @@ static void popup_divelist_menu(GtkTreeView *tree_view, GtkTreeModel *model, int
|
||||||
|
|
||||||
static void popup_menu_cb(GtkTreeView *tree_view, gpointer userdata)
|
static void popup_menu_cb(GtkTreeView *tree_view, gpointer userdata)
|
||||||
{
|
{
|
||||||
popup_divelist_menu(tree_view, GTK_TREE_MODEL(dive_list.model), 0);
|
popup_divelist_menu(tree_view, MODEL(dive_list), 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean button_press_cb(GtkWidget *treeview, GdkEventButton *event, gpointer userdata)
|
static gboolean button_press_cb(GtkWidget *treeview, GdkEventButton *event, gpointer userdata)
|
||||||
{
|
{
|
||||||
/* Right-click? Bring up the menu */
|
/* Right-click? Bring up the menu */
|
||||||
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
|
if (event->type == GDK_BUTTON_PRESS && event->button == 3) {
|
||||||
popup_divelist_menu(GTK_TREE_VIEW(treeview), GTK_TREE_MODEL(dive_list.model), 3);
|
popup_divelist_menu(GTK_TREE_VIEW(treeview), MODEL(dive_list), 3, event);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -1276,9 +1768,9 @@ static void sort_column_change_cb(GtkTreeSortable *treeview, gpointer data)
|
||||||
if (dive_list.model != currentmodel) {
|
if (dive_list.model != currentmodel) {
|
||||||
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
|
|
||||||
gtk_tree_view_set_model(GTK_TREE_VIEW(dive_list.tree_view), GTK_TREE_MODEL(dive_list.model));
|
gtk_tree_view_set_model(GTK_TREE_VIEW(dive_list.tree_view), MODEL(dive_list));
|
||||||
update_column_and_order(colid);
|
update_column_and_order(colid);
|
||||||
gtk_tree_model_foreach(GTK_TREE_MODEL(dive_list.model), set_selected, selection);
|
gtk_tree_model_foreach(MODEL(dive_list), set_selected, selection);
|
||||||
} else {
|
} else {
|
||||||
if (order != sortorder[colid]) {
|
if (order != sortorder[colid]) {
|
||||||
update_column_and_order(colid);
|
update_column_and_order(colid);
|
||||||
|
@ -1293,7 +1785,7 @@ GtkWidget *dive_list_create(void)
|
||||||
dive_list.listmodel = gtk_tree_store_new(DIVELIST_COLUMNS,
|
dive_list.listmodel = gtk_tree_store_new(DIVELIST_COLUMNS,
|
||||||
G_TYPE_INT, /* index */
|
G_TYPE_INT, /* index */
|
||||||
G_TYPE_INT, /* nr */
|
G_TYPE_INT, /* nr */
|
||||||
G_TYPE_INT, /* Date */
|
G_TYPE_LONG, /* Date */
|
||||||
G_TYPE_INT, /* Star rating */
|
G_TYPE_INT, /* Star rating */
|
||||||
G_TYPE_INT, /* Depth */
|
G_TYPE_INT, /* Depth */
|
||||||
G_TYPE_INT, /* Duration */
|
G_TYPE_INT, /* Duration */
|
||||||
|
@ -1309,7 +1801,7 @@ GtkWidget *dive_list_create(void)
|
||||||
dive_list.treemodel = gtk_tree_store_new(DIVELIST_COLUMNS,
|
dive_list.treemodel = gtk_tree_store_new(DIVELIST_COLUMNS,
|
||||||
G_TYPE_INT, /* index */
|
G_TYPE_INT, /* index */
|
||||||
G_TYPE_INT, /* nr */
|
G_TYPE_INT, /* nr */
|
||||||
G_TYPE_INT, /* Date */
|
G_TYPE_LONG, /* Date */
|
||||||
G_TYPE_INT, /* Star rating */
|
G_TYPE_INT, /* Star rating */
|
||||||
G_TYPE_INT, /* Depth */
|
G_TYPE_INT, /* Depth */
|
||||||
G_TYPE_INT, /* Duration */
|
G_TYPE_INT, /* Duration */
|
||||||
|
@ -1323,7 +1815,7 @@ GtkWidget *dive_list_create(void)
|
||||||
G_TYPE_STRING /* Location */
|
G_TYPE_STRING /* Location */
|
||||||
);
|
);
|
||||||
dive_list.model = dive_list.treemodel;
|
dive_list.model = dive_list.treemodel;
|
||||||
dive_list.tree_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(dive_list.model));
|
dive_list.tree_view = gtk_tree_view_new_with_model(TREEMODEL(dive_list));
|
||||||
set_divelist_font(divelist_font);
|
set_divelist_font(divelist_font);
|
||||||
|
|
||||||
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(dive_list.tree_view));
|
||||||
|
@ -1383,3 +1875,26 @@ int unsaved_changes()
|
||||||
{
|
{
|
||||||
return dive_list.changed;
|
return dive_list.changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void remove_autogen_trips()
|
||||||
|
{
|
||||||
|
GtkTreeIter iter;
|
||||||
|
GtkTreePath *path;
|
||||||
|
time_t when;
|
||||||
|
int idx;
|
||||||
|
GList *trip;
|
||||||
|
|
||||||
|
/* start with the first top level entry and walk all of them */
|
||||||
|
path = gtk_tree_path_new_from_string("0");
|
||||||
|
while(gtk_tree_model_get_iter(TREEMODEL(dive_list), &iter, path)) {
|
||||||
|
gtk_tree_model_get(TREEMODEL(dive_list), &iter, DIVE_INDEX, &idx, DIVE_DATE, &when, -1);
|
||||||
|
if (idx < 0) {
|
||||||
|
trip = FIND_TRIP(when);
|
||||||
|
if (DIVE_TRIP(trip)->tripflag == IN_TRIP) { /* this was autogen */
|
||||||
|
remove_trip(path, FALSE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gtk_tree_path_next(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,4 +10,5 @@ extern void flush_divelist(struct dive *);
|
||||||
extern void update_cylinder_related_info(struct dive *);
|
extern void update_cylinder_related_info(struct dive *);
|
||||||
extern void mark_divelist_changed(int);
|
extern void mark_divelist_changed(int);
|
||||||
extern int unsaved_changes(void);
|
extern int unsaved_changes(void);
|
||||||
|
extern void remove_autogen_trips(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<dives>
|
<dives>
|
||||||
<program name='subsurface' version='1'></program>
|
<program name='subsurface' version='1'></program>
|
||||||
<trip date='2011-12-02' />
|
<trip date='2011-12-02' time='14:00:00' />
|
||||||
<dive number='20' tripflag='INTRIP' date='2011-12-02' time='14:00:00' duration='30:00 min'>
|
<dive number='20' tripflag='INTRIP' date='2011-12-02' time='14:00:00' duration='30:00 min'>
|
||||||
<depth max='20.0 m' mean='15.0 m' />
|
<depth max='20.0 m' mean='15.0 m' />
|
||||||
<location>20th test dive - this should be in a trip with same location</location>
|
<location>20th test dive - this should be in a trip with same location</location>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<dives>
|
<dives>
|
||||||
<program name='subsurface' version='1'></program>
|
<program name='subsurface' version='1'></program>
|
||||||
<trip date='2011-12-02' location='trip location' />
|
<trip date='2011-12-02' location='trip location' time='15:00:00' />
|
||||||
<dive number='21' tripflag='INTRIP' date='2011-12-02' time='15:00:00' duration='30:00 min'>
|
<dive number='21' tripflag='INTRIP' date='2011-12-02' time='15:00:00' duration='30:00 min'>
|
||||||
<depth max='20.0 m' mean='15.0 m' />
|
<depth max='20.0 m' mean='15.0 m' />
|
||||||
<location>21st test dive - this should be in a trip with a trip location</location>
|
<location>21st test dive - this should be in a trip with a trip location</location>
|
||||||
|
|
|
@ -1,7 +1,12 @@
|
||||||
<dives>
|
<dives>
|
||||||
<program name='subsurface' version='1'></program>
|
<program name='subsurface' version='1'></program>
|
||||||
<trip date='2011-12-02' location='trip location' />
|
<trip date='2011-12-02' time='6:00:00' location='trip location' />
|
||||||
<dive number='22' tripflag='NOTRIP' date='2011-12-09' time='6:00:00' duration='30:00 min'>
|
<dive number='23' tripflag='INTRIP' date='2011-12-02' time='6:00:00' duration='30:00 min'>
|
||||||
|
<depth max='20.0 m' mean='15.0 m' />
|
||||||
|
<location>23rd test dive - this should be in a trip</location>
|
||||||
|
<notes>We are testing that the NOTRIP flag works</notes>
|
||||||
|
</dive>
|
||||||
|
<dive number='22' tripflag='NOTRIP' date='2011-12-03' time='7:00:00' duration='30:00 min'>
|
||||||
<depth max='20.0 m' mean='15.0 m' />
|
<depth max='20.0 m' mean='15.0 m' />
|
||||||
<location>22nd test dive - this should not be in a trip</location>
|
<location>22nd test dive - this should not be in a trip</location>
|
||||||
<notes>We are testing that the NOTRIP flag works</notes>
|
<notes>We are testing that the NOTRIP flag works</notes>
|
||||||
|
|
18
gtk-gui.c
18
gtk-gui.c
|
@ -634,6 +634,14 @@ static void selectevents_dialog(GtkWidget *w, gpointer data)
|
||||||
gtk_widget_destroy(dialog);
|
gtk_widget_destroy(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void autogroup_cb(GtkWidget *w, gpointer data)
|
||||||
|
{
|
||||||
|
autogroup = !autogroup;
|
||||||
|
if (! autogroup)
|
||||||
|
remove_autogen_trips();
|
||||||
|
dive_list_update_dives();
|
||||||
|
}
|
||||||
|
|
||||||
static void renumber_dialog(GtkWidget *w, gpointer data)
|
static void renumber_dialog(GtkWidget *w, gpointer data)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
@ -757,10 +765,15 @@ static GtkActionEntry menu_items[] = {
|
||||||
{ "ViewProfile", NULL, "Profile", CTRLCHAR "2", NULL, G_CALLBACK(view_profile) },
|
{ "ViewProfile", NULL, "Profile", CTRLCHAR "2", NULL, G_CALLBACK(view_profile) },
|
||||||
{ "ViewInfo", NULL, "Info", CTRLCHAR "3", NULL, G_CALLBACK(view_info) },
|
{ "ViewInfo", NULL, "Info", CTRLCHAR "3", NULL, G_CALLBACK(view_info) },
|
||||||
{ "ViewThree", NULL, "Three", CTRLCHAR "4", NULL, G_CALLBACK(view_three) },
|
{ "ViewThree", NULL, "Three", CTRLCHAR "4", NULL, G_CALLBACK(view_three) },
|
||||||
{ "ToggleZoom", NULL, "Toggle Zoom", CTRLCHAR "0", NULL, G_CALLBACK(toggle_zoom) },
|
|
||||||
};
|
};
|
||||||
static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
|
static gint nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);
|
||||||
|
|
||||||
|
static GtkToggleActionEntry toggle_items[] = {
|
||||||
|
{ "Autogroup", NULL, "Autogroup", NULL, NULL, G_CALLBACK(autogroup_cb), FALSE },
|
||||||
|
{ "ToggleZoom", NULL, "Toggle Zoom", CTRLCHAR "0", NULL, G_CALLBACK(toggle_zoom), FALSE },
|
||||||
|
};
|
||||||
|
static gint ntoggle_items = sizeof (toggle_items) / sizeof (toggle_items[0]);
|
||||||
|
|
||||||
static const gchar* ui_string = " \
|
static const gchar* ui_string = " \
|
||||||
<ui> \
|
<ui> \
|
||||||
<menubar name=\"MainMenu\"> \
|
<menubar name=\"MainMenu\"> \
|
||||||
|
@ -779,6 +792,7 @@ static const gchar* ui_string = " \
|
||||||
<menuitem name=\"Add Dive\" action=\"AddDive\" /> \
|
<menuitem name=\"Add Dive\" action=\"AddDive\" /> \
|
||||||
<separator name=\"Separator\"/> \
|
<separator name=\"Separator\"/> \
|
||||||
<menuitem name=\"Renumber\" action=\"Renumber\" /> \
|
<menuitem name=\"Renumber\" action=\"Renumber\" /> \
|
||||||
|
<menuitem name=\"Autogroup\" action=\"Autogroup\" /> \
|
||||||
<menuitem name=\"Toggle Zoom\" action=\"ToggleZoom\" /> \
|
<menuitem name=\"Toggle Zoom\" action=\"ToggleZoom\" /> \
|
||||||
<menu name=\"View\" action=\"ViewMenuAction\"> \
|
<menu name=\"View\" action=\"ViewMenuAction\"> \
|
||||||
<menuitem name=\"List\" action=\"ViewList\" /> \
|
<menuitem name=\"List\" action=\"ViewList\" /> \
|
||||||
|
@ -801,6 +815,8 @@ static GtkWidget *get_menubar_menu(GtkWidget *window, GtkUIManager *ui_manager)
|
||||||
{
|
{
|
||||||
GtkActionGroup *action_group = gtk_action_group_new("Menu");
|
GtkActionGroup *action_group = gtk_action_group_new("Menu");
|
||||||
gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0);
|
gtk_action_group_add_actions(action_group, menu_items, nmenu_items, 0);
|
||||||
|
toggle_items[0].is_active = autogroup;
|
||||||
|
gtk_action_group_add_toggle_actions(action_group, toggle_items, ntoggle_items, 0);
|
||||||
|
|
||||||
gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
|
gtk_ui_manager_insert_action_group(ui_manager, action_group, 0);
|
||||||
GError* error = 0;
|
GError* error = 0;
|
||||||
|
|
62
info.c
62
info.c
|
@ -415,6 +415,24 @@ static void save_dive_info_changes(struct dive *dive, struct dive *master, struc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dive_trip_widget(GtkWidget *box, struct dive *trip, struct dive_info *info)
|
||||||
|
{
|
||||||
|
GtkWidget *hbox, *label;
|
||||||
|
char buffer[80] = "Edit trip summary";
|
||||||
|
|
||||||
|
label = gtk_label_new(buffer);
|
||||||
|
gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0);
|
||||||
|
|
||||||
|
info->location = text_entry(box, "Location", location_list, trip->location);
|
||||||
|
|
||||||
|
hbox = gtk_hbox_new(FALSE, 3);
|
||||||
|
gtk_box_pack_start(GTK_BOX(box), hbox, FALSE, TRUE, 0);
|
||||||
|
|
||||||
|
info->notes = text_view(box, "Notes", READ_WRITE);
|
||||||
|
if (trip->notes && *trip->notes)
|
||||||
|
gtk_text_buffer_set_text(gtk_text_view_get_buffer(info->notes), trip->notes, -1);
|
||||||
|
}
|
||||||
|
|
||||||
static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info *info, gboolean multi)
|
static void dive_info_widget(GtkWidget *box, struct dive *dive, struct dive_info *info, gboolean multi)
|
||||||
{
|
{
|
||||||
GtkWidget *hbox, *label, *frame, *equipment;
|
GtkWidget *hbox, *label, *frame, *equipment;
|
||||||
|
@ -489,7 +507,49 @@ void update_equipment_data(struct dive *dive, struct dive *master)
|
||||||
memcpy(dive->weightsystem, master->weightsystem, WS_BYTES);
|
memcpy(dive->weightsystem, master->weightsystem, WS_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A negative index means "all selected" */
|
gboolean edit_trip(struct dive *trip)
|
||||||
|
{
|
||||||
|
GtkWidget *dialog, *vbox;
|
||||||
|
int success;
|
||||||
|
gboolean changed = FALSE;
|
||||||
|
char *old_text, *new_text;
|
||||||
|
struct dive_info info;
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(struct dive_info));
|
||||||
|
dialog = gtk_dialog_new_with_buttons("Edit Trip Info",
|
||||||
|
GTK_WINDOW(main_window),
|
||||||
|
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||||
|
GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
|
||||||
|
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
|
||||||
|
NULL);
|
||||||
|
vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
|
||||||
|
dive_trip_widget(vbox, trip, &info);
|
||||||
|
gtk_widget_show_all(dialog);
|
||||||
|
success = gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT;
|
||||||
|
if (success) {
|
||||||
|
/* we need to store the edited location and notes */
|
||||||
|
new_text = get_combo_box_entry_text(info.location, &trip->location, trip->location);
|
||||||
|
if (new_text) {
|
||||||
|
add_location(new_text);
|
||||||
|
changed = TRUE;
|
||||||
|
}
|
||||||
|
if (info.notes) {
|
||||||
|
old_text = trip->notes;
|
||||||
|
trip->notes = get_text(info.notes);
|
||||||
|
if (text_changed(old_text, trip->notes))
|
||||||
|
changed = TRUE;
|
||||||
|
if (old_text)
|
||||||
|
g_free(old_text);
|
||||||
|
}
|
||||||
|
if (changed) {
|
||||||
|
mark_divelist_changed(TRUE);
|
||||||
|
flush_divelist(trip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gtk_widget_destroy(dialog);
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
int edit_multi_dive_info(struct dive *single_dive)
|
int edit_multi_dive_info(struct dive *single_dive)
|
||||||
{
|
{
|
||||||
int success;
|
int success;
|
||||||
|
|
13
parse-xml.c
13
parse-xml.c
|
@ -39,11 +39,6 @@ void record_dive(struct dive *dive)
|
||||||
dive_table.nr = nr+1;
|
dive_table.nr = nr+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void record_trip(struct dive *trip)
|
|
||||||
{
|
|
||||||
dive_trip_list = insert_trip(trip, dive_trip_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete_dive_renumber(struct dive **dives, int i, int nr)
|
static void delete_dive_renumber(struct dive **dives, int i, int nr)
|
||||||
{
|
{
|
||||||
struct dive *dive = dives[i];
|
struct dive *dive = dives[i];
|
||||||
|
@ -1165,10 +1160,10 @@ static void try_to_fill_trip(struct dive **divep, const char *name, char *buf)
|
||||||
|
|
||||||
struct dive *dive = *divep;
|
struct dive *dive = *divep;
|
||||||
|
|
||||||
if (MATCH(".date", divedate, &dive->when)) {
|
if (MATCH(".date", divedate, &dive->when))
|
||||||
dive->when = utc_mktime(&cur_tm);
|
return;
|
||||||
|
if (MATCH(".time", divetime, &dive->when))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
if (MATCH(".location", utf8_string, &dive->location))
|
if (MATCH(".location", utf8_string, &dive->location))
|
||||||
return;
|
return;
|
||||||
if (MATCH(".notes", utf8_string, &dive->notes))
|
if (MATCH(".notes", utf8_string, &dive->notes))
|
||||||
|
@ -1213,7 +1208,7 @@ static void trip_end(void)
|
||||||
{
|
{
|
||||||
if (!cur_trip)
|
if (!cur_trip)
|
||||||
return;
|
return;
|
||||||
record_trip(cur_trip);
|
insert_trip(&cur_trip);
|
||||||
cur_trip = NULL;
|
cur_trip = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -291,6 +291,8 @@ static void save_trip(FILE *f, struct dive *trip)
|
||||||
fprintf(f, "<trip");
|
fprintf(f, "<trip");
|
||||||
fprintf(f, " date='%04u-%02u-%02u'",
|
fprintf(f, " date='%04u-%02u-%02u'",
|
||||||
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
|
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday);
|
||||||
|
fprintf(f, " time='%02u:%02u:%02u'",
|
||||||
|
tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||||
if (trip->location)
|
if (trip->location)
|
||||||
show_utf8(f, trip->location, " location=\'","\'", 1);
|
show_utf8(f, trip->location, " location=\'","\'", 1);
|
||||||
fprintf(f, " />\n");
|
fprintf(f, " />\n");
|
||||||
|
@ -341,7 +343,7 @@ void save_dives(const char *filename)
|
||||||
fprintf(f, "<dives>\n<program name='subsurface' version='%d'></program>\n", VERSION);
|
fprintf(f, "<dives>\n<program name='subsurface' version='%d'></program>\n", VERSION);
|
||||||
|
|
||||||
/* save the trips */
|
/* save the trips */
|
||||||
while ((trip = NEXT_TRIP(trip, dive_trip_list)) != 0)
|
while ((trip = NEXT_TRIP(trip)) != NULL)
|
||||||
save_trip(f, trip->data);
|
save_trip(f, trip->data);
|
||||||
|
|
||||||
/* save the dives */
|
/* save the dives */
|
||||||
|
|
Loading…
Add table
Reference in a new issue