20 |
/* |
/* |
21 |
* TODO: |
* TODO: |
22 |
* |
* |
23 |
* - restore node memberships when restoring a way |
* + restore node memberships when restoring a way |
24 |
* - save restore relation membership |
* - save restore relation membership |
25 |
* - handle permamently deleted objects (newly created, then deleted) |
* - handle permamently deleted objects (newly created, then deleted) |
26 |
*/ |
*/ |
30 |
#define UNDO_ENABLE_CHECK if(!appdata->menu_item_map_undo) return; |
#define UNDO_ENABLE_CHECK if(!appdata->menu_item_map_undo) return; |
31 |
|
|
32 |
/* return plain text of type */ |
/* return plain text of type */ |
33 |
char *undo_type_string(type_t type) { |
static char *undo_type_string(type_t type) { |
34 |
const struct { undo_type_t type; char *name; } types[] = { |
const struct { undo_type_t type; char *name; } types[] = { |
35 |
{ UNDO_DELETE, "DELETE" }, |
{ UNDO_DELETE, "deletion" }, |
36 |
{ UNDO_CREATE, "CREATE" }, |
{ UNDO_CREATE, "creation" }, |
37 |
{ UNDO_MODIFY, "MODIFY" }, |
{ UNDO_MODIFY, "modification" }, |
38 |
{ 0, NULL } |
{ 0, NULL } |
39 |
}; |
}; |
40 |
|
|
46 |
return NULL; |
return NULL; |
47 |
} |
} |
48 |
|
|
49 |
static void undo_object_free(object_t *obj) { |
static void undo_object_free(osm_t *osm, object_t *obj) { |
50 |
printf("free obj %p\n", obj); |
printf("free obj %p\n", obj); |
51 |
|
|
52 |
if(obj->ptr) { |
if(obj->ptr) { |
60 |
|
|
61 |
switch(obj->type) { |
switch(obj->type) { |
62 |
case NODE: |
case NODE: |
63 |
osm_node_free(NULL, obj->node); |
osm_node_free(osm, NULL, obj->node); |
64 |
break; |
break; |
65 |
|
|
66 |
case WAY: |
case WAY: |
78 |
g_free(obj); |
g_free(obj); |
79 |
} |
} |
80 |
|
|
81 |
static void undo_op_free(undo_op_t *op) { |
static void undo_op_free(osm_t *osm, undo_op_t *op) { |
82 |
printf(" free op: %s\n", undo_type_string(op->type)); |
printf(" free op: %s\n", undo_type_string(op->type)); |
83 |
if(op->object) undo_object_free(op->object); |
if(op->object) undo_object_free(osm, op->object); |
84 |
g_free(op); |
g_free(op); |
85 |
} |
} |
86 |
|
|
87 |
static void undo_state_free(undo_state_t *state) { |
static void undo_state_free(osm_t *osm, undo_state_t *state) { |
88 |
printf(" free state: %s\n", undo_type_string(state->type)); |
printf(" free state: %s\n", undo_type_string(state->type)); |
89 |
|
|
90 |
if(state->name) |
if(state->name) |
93 |
undo_op_t *op = state->op; |
undo_op_t *op = state->op; |
94 |
while(op) { |
while(op) { |
95 |
undo_op_t *next = op->next; |
undo_op_t *next = op->next; |
96 |
undo_op_free(op); |
undo_op_free(osm, op); |
97 |
op = next; |
op = next; |
98 |
} |
} |
99 |
|
|
102 |
|
|
103 |
/* free all undo states, thus forgetting the entire history */ |
/* free all undo states, thus forgetting the entire history */ |
104 |
/* called at program exit or e.g. at project change */ |
/* called at program exit or e.g. at project change */ |
105 |
void undo_free(undo_state_t *state) { |
void undo_free(osm_t *osm, undo_state_t *state) { |
106 |
printf("Freeing all UNDO states:\n"); |
printf("Freeing all UNDO states:\n"); |
107 |
|
|
108 |
while(state) { |
while(state) { |
109 |
undo_state_t *next = state->next; |
undo_state_t *next = state->next; |
110 |
undo_state_free(state); |
undo_state_free(osm, state); |
111 |
state = next; |
state = next; |
112 |
} |
} |
113 |
} |
} |
130 |
/* delete first entry if the chain is too long */ |
/* delete first entry if the chain is too long */ |
131 |
if(undo_chain_length >= UNDO_QUEUE_LEN) { |
if(undo_chain_length >= UNDO_QUEUE_LEN) { |
132 |
undo_state_t *second = appdata->undo.state->next; |
undo_state_t *second = appdata->undo.state->next; |
133 |
undo_state_free(appdata->undo.state); |
undo_state_free(appdata->osm, appdata->undo.state); |
134 |
appdata->undo.state = second; |
appdata->undo.state = second; |
135 |
} |
} |
136 |
|
|
325 |
g_assert(!wchain); |
g_assert(!wchain); |
326 |
|
|
327 |
/* then restore old node */ |
/* then restore old node */ |
|
// osm_node_dump(obj->node); |
|
328 |
osm_node_restore(appdata->osm, obj->node); |
osm_node_restore(appdata->osm, obj->node); |
329 |
josm_elemstyles_colorize_node(appdata->map->style, obj->node); |
|
|
map_node_draw(appdata->map, obj->node); |
|
330 |
obj->ptr = NULL; |
obj->ptr = NULL; |
331 |
} break; |
} break; |
332 |
|
|
339 |
osm_way_delete(appdata->osm, &appdata->icon, orig, TRUE); |
osm_way_delete(appdata->osm, &appdata->icon, orig, TRUE); |
340 |
|
|
341 |
osm_way_restore(appdata->osm, obj->way); |
osm_way_restore(appdata->osm, obj->way); |
|
josm_elemstyles_colorize_way(appdata->map->style, obj->way); |
|
|
map_way_draw(appdata->map, obj->way); |
|
342 |
|
|
|
printf("ptr of obj %p cleared\n", obj); |
|
343 |
obj->ptr = NULL; |
obj->ptr = NULL; |
344 |
} break; |
} break; |
345 |
|
|
382 |
|
|
383 |
printf("UNDO state: %s\n", undo_type_string(state->type)); |
printf("UNDO state: %s\n", undo_type_string(state->type)); |
384 |
|
|
385 |
|
char *msg = g_strdup_printf(_("Undoing %s of %s"), |
386 |
|
undo_type_string(state->type), |
387 |
|
state->name); |
388 |
|
banner_show_info(appdata, msg); |
389 |
|
g_free(msg); |
390 |
|
|
391 |
/* since the operations list was built by prepending new */ |
/* since the operations list was built by prepending new */ |
392 |
/* entries, just going through the list will run the operations */ |
/* entries, just going through the list will run the operations */ |
393 |
/* in reverse order. That's exactly what we want! */ |
/* in reverse order. That's exactly what we want! */ |
401 |
undo_state_t **stateP = &appdata->undo.state; |
undo_state_t **stateP = &appdata->undo.state; |
402 |
while(*stateP && (*stateP)->next) stateP = &(*stateP)->next; |
while(*stateP && (*stateP)->next) stateP = &(*stateP)->next; |
403 |
|
|
404 |
undo_state_free(*stateP); |
undo_state_free(appdata->osm, *stateP); |
405 |
*stateP = NULL; |
*stateP = NULL; |
406 |
|
|
407 |
|
/* redraw entire map */ |
408 |
|
map_clear(appdata, MAP_LAYER_ALL); |
409 |
|
map_paint(appdata); |
410 |
} |
} |