/*! \todo Finish function documentation!!! * \brief * \par Function Description * * * <B>flag</B> can be one of the following values: * <DL> * <DT>*</DT><DD>UNDO_ALL * <DT>*</DT><DD>UNDO_VIEWPORT_ONLY * </DL> */ void o_undo_savestate (GschemToplevel *w_current, PAGE *page, int flag) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); char *filename = NULL; GList *object_list = NULL; int levels; UNDO *u_current; UNDO *u_current_next; GschemPageView *view = gschem_toplevel_get_current_page_view (w_current); g_return_if_fail (view != NULL); g_return_if_fail (page != NULL); GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view); /* save autosave backups if necessary */ o_autosave_backups(w_current); if (w_current->undo_control == FALSE) { return; } if (flag == UNDO_ALL) { /* Increment the number of operations since last backup if auto-save is enabled */ if (toplevel->auto_save_interval != 0) { page->ops_since_last_backup++; } /* HACK */ /* Before we save the undo state, consolidate nets as necessary */ /* This is where the net consolidation call would have been * triggered before it was removed from o_save_buffer(). */ if (toplevel->net_consolidate == TRUE) geda_net_object_consolidate (toplevel, page); } if (w_current->undo_type == UNDO_DISK && flag == UNDO_ALL) { filename = g_strdup_printf("%s%cgschem.save%d_%d.sch", tmp_path, G_DIR_SEPARATOR, prog_pid, undo_file_index++); /* Changed from f_save to o_save when adding backup copy creation. */ /* f_save manages the creaton of backup copies. This way, f_save is called only when saving a file, and not when saving an undo backup copy */ o_save (toplevel, s_page_objects (page), filename, NULL); } else if (w_current->undo_type == UNDO_MEMORY && flag == UNDO_ALL) { object_list = o_glist_copy_all (toplevel, s_page_objects (page), object_list); } /* Clear Anything above current */ if (page->undo_current) { s_undo_remove_rest(toplevel, page->undo_current->next); page->undo_current->next = NULL; } else { /* undo current is NULL */ s_undo_remove_rest(toplevel, page->undo_bottom); page->undo_bottom = NULL; } page->undo_tos = page->undo_current; if (geometry != NULL) { page->undo_tos = s_undo_add(page->undo_tos, flag, filename, object_list, (geometry->viewport_left + geometry->viewport_right) / 2, (geometry->viewport_top + geometry->viewport_bottom) / 2, /* scale */ max (((double) abs (geometry->viewport_right - geometry->viewport_left) / geometry->screen_width), ((double) abs (geometry->viewport_top - geometry->viewport_bottom) / geometry->screen_height)), page->page_control, page->up); } else { page->undo_tos = s_undo_add(page->undo_tos, flag, filename, object_list, 0, /* center x */ 0, /* center y */ 0, /* scale */ page->page_control, page->up); } page->undo_current = page->undo_tos; if (page->undo_bottom == NULL) { page->undo_bottom = page->undo_tos; } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(page->undo_bottom); printf("BOTTOM: %s\n", page->undo_bottom->filename); printf("TOS: %s\n", page->undo_tos->filename); printf("CURRENT: %s\n", page->undo_current->filename); printf("----\n"); #endif g_free(filename); /* Now go through and see if we need to free/remove some undo levels */ /* so we stay within the limits */ /* only check history every 10 undo savestates */ if (undo_file_index % 10) { return; } levels = s_undo_levels(page->undo_bottom); #if DEBUG printf("levels: %d\n", levels); #endif if (levels >= w_current->undo_levels + UNDO_PADDING) { levels = levels - w_current->undo_levels; #if DEBUG printf("Trimming: %d levels\n", levels); #endif u_current = page->undo_bottom; while (levels > 0) { /* Because we use a pad you are always guaranteed to never */ /* exhaust the list */ g_assert (u_current != NULL); u_current_next = u_current->next; if (u_current->filename) { #if DEBUG printf("Freeing: %s\n", u_current->filename); #endif unlink(u_current->filename); g_free(u_current->filename); } if (u_current->object_list) { geda_object_list_delete (toplevel, u_current->object_list); u_current->object_list = NULL; } u_current->next = NULL; u_current->prev = NULL; g_free(u_current); u_current = u_current_next; levels--; } g_assert (u_current != NULL); u_current->prev = NULL; page->undo_bottom = u_current; #if DEBUG printf("New current is: %s\n", u_current->filename); #endif } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(page->undo_bottom); printf("BOTTOM: %s\n", page->undo_bottom->filename); printf("TOS: %s\n", page->undo_tos->filename); printf("CURRENT: %s\n", page->undo_current->filename); printf("----\n"); #endif }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * * * <B>flag</B> can be one of the following values: * <DL> * <DT>*</DT><DD>UNDO_ALL * <DT>*</DT><DD>UNDO_VIEWPORT_ONLY * </DL> */ void o_undo_savestate(GSCHEM_TOPLEVEL *w_current, int flag) { TOPLEVEL *toplevel = w_current->toplevel; char *filename = NULL; GList *object_list = NULL; int levels; UNDO *u_current; UNDO *u_current_next; /* save autosave backups if necessary */ o_autosave_backups(w_current); if (w_current->undo_control == FALSE) { return; } if (flag == UNDO_ALL) { /* Increment the number of operations since last backup if auto-save is enabled */ if (toplevel->auto_save_interval != 0) { toplevel->page_current->ops_since_last_backup++; } /* HACK */ /* Before we save the undo state, consolidate nets as necessary */ /* This is where the net consolidation call would have been * triggered before it was removed from o_save_buffer(). */ if (toplevel->net_consolidate == TRUE) o_net_consolidate (toplevel, toplevel->page_current); } if (w_current->undo_type == UNDO_DISK && flag == UNDO_ALL) { filename = g_strdup_printf("%s%cgschem.save%d_%d.sch", tmp_path, G_DIR_SEPARATOR, prog_pid, undo_file_index++); /* Changed from f_save to o_save when adding backup copy creation. */ /* f_save manages the creaton of backup copies. This way, f_save is called only when saving a file, and not when saving an undo backup copy */ o_save (toplevel, s_page_objects (toplevel->page_current), filename, NULL); } else if (w_current->undo_type == UNDO_MEMORY && flag == UNDO_ALL) { object_list = o_glist_copy_all (toplevel, s_page_objects (toplevel->page_current), object_list); } /* Clear Anything above current */ if (toplevel->page_current->undo_current) { s_undo_remove_rest(toplevel, toplevel->page_current->undo_current->next); toplevel->page_current->undo_current->next = NULL; } else { /* undo current is NULL */ s_undo_remove_rest(toplevel, toplevel->page_current->undo_bottom); toplevel->page_current->undo_bottom = NULL; } toplevel->page_current->undo_tos = toplevel->page_current->undo_current; toplevel->page_current->undo_tos = s_undo_add(toplevel->page_current->undo_tos, flag, filename, object_list, toplevel->page_current->left, toplevel->page_current->top, toplevel->page_current->right, toplevel->page_current->bottom, toplevel->page_current->page_control, toplevel->page_current->up); toplevel->page_current->undo_current = toplevel->page_current->undo_tos; if (toplevel->page_current->undo_bottom == NULL) { toplevel->page_current->undo_bottom = toplevel->page_current->undo_tos; } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(toplevel->page_current->undo_bottom); printf("BOTTOM: %s\n", toplevel->page_current->undo_bottom->filename); printf("TOS: %s\n", toplevel->page_current->undo_tos->filename); printf("CURRENT: %s\n", toplevel->page_current->undo_current->filename); printf("----\n"); #endif g_free(filename); /* Now go through and see if we need to free/remove some undo levels */ /* so we stay within the limits */ /* only check history every 10 undo savestates */ if (undo_file_index % 10) { return; } levels = s_undo_levels(toplevel->page_current->undo_bottom); #if DEBUG printf("levels: %d\n", levels); #endif if (levels >= w_current->undo_levels + UNDO_PADDING) { levels = levels - w_current->undo_levels; #if DEBUG printf("Trimming: %d levels\n", levels); #endif u_current = toplevel->page_current->undo_bottom; while(u_current && levels > 0) { u_current_next = u_current->next; if (u_current->filename) { #if DEBUG printf("Freeing: %s\n", u_current->filename); #endif unlink(u_current->filename); g_free(u_current->filename); } if (u_current->object_list) { s_delete_object_glist (toplevel, u_current->object_list); u_current->object_list = NULL; } u_current->next = NULL; u_current->prev = NULL; g_free(u_current); u_current = u_current_next; levels--; } /* Because we use a pad you are always garanteed to never */ /* exhaust the list */ u_current->prev = NULL; toplevel->page_current->undo_bottom = u_current; #if DEBUG printf("New current is: %s\n", u_current->filename); #endif } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(toplevel->page_current->undo_bottom); printf("BOTTOM: %s\n", toplevel->page_current->undo_bottom->filename); printf("TOS: %s\n", toplevel->page_current->undo_tos->filename); printf("CURRENT: %s\n", toplevel->page_current->undo_current->filename); printf("----\n"); #endif }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * * <B>type</B> can be one of the following values: * <DL> * <DT>*</DT><DD>UNDO_ACTION * <DT>*</DT><DD>REDO_ACTION * </DL> */ void o_undo_callback (GschemToplevel *w_current, PAGE *page, int type) { TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current); UNDO *u_current; UNDO *u_next; UNDO *save_bottom; UNDO *save_tos; UNDO *save_current; int save_logging; int find_prev_data=FALSE; char *save_filename; g_return_if_fail (w_current != NULL); g_return_if_fail (page != NULL); if (w_current->undo_control == FALSE) { s_log_message(_("Undo/Redo disabled in rc file\n")); return; } if (page->undo_current == NULL) { return; } if (type == UNDO_ACTION) { u_current = page->undo_current->prev; } else { u_current = page->undo_current->next; } u_next = page->undo_current; if (u_current == NULL) { return; } if (u_next->type == UNDO_ALL && u_current->type == UNDO_VIEWPORT_ONLY) { #if DEBUG printf("Type: %d\n", u_current->type); printf("Current is an undo all, next is viewport only!\n"); #endif find_prev_data = TRUE; if (w_current->undo_type == UNDO_DISK) { u_current->filename = o_undo_find_prev_filename(u_current); } else { u_current->object_list = o_undo_find_prev_object_head (u_current); } } /* save filename */ save_filename = g_strdup (page->page_filename); /* save structure so it's not nuked */ save_bottom = page->undo_bottom; save_tos = page->undo_tos; save_current = page->undo_current; page->undo_bottom = NULL; page->undo_tos = NULL; page->undo_current = NULL; o_select_unselect_all (w_current); if (w_current->undo_type == UNDO_DISK && u_current->filename) { /* delete objects of page */ s_page_delete_objects (toplevel, page); /* Free the objects in the place list. */ geda_object_list_delete (toplevel, page->place_list); page->place_list = NULL; gschem_toplevel_page_content_changed (w_current, page); } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) { /* delete objects of page */ s_page_delete_objects (toplevel, page); /* Free the objects in the place list. */ geda_object_list_delete (toplevel, page->place_list); page->place_list = NULL; gschem_toplevel_page_content_changed (w_current, page); } /* temporarily disable logging */ save_logging = do_logging; do_logging = FALSE; if (w_current->undo_type == UNDO_DISK && u_current->filename) { f_open(toplevel, page, u_current->filename, NULL); } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) { s_page_append_list (toplevel, page, o_glist_copy_all (toplevel, u_current->object_list, NULL)); } page->page_control = u_current->page_control; page->up = u_current->up; gschem_toplevel_page_content_changed (w_current, page); GschemPageView *view = gschem_toplevel_get_current_page_view (w_current); g_return_if_fail (view != NULL); GschemPageGeometry *geometry = gschem_page_view_get_page_geometry (view); if (u_current->scale != 0) { gschem_page_geometry_set_viewport (geometry, u_current->x, u_current->y, u_current->scale); gschem_page_view_invalidate_all (view); } else { gschem_page_view_zoom_extents (view, u_current->object_list); } /* restore logging */ do_logging = save_logging; /* set filename right */ g_free(page->page_filename); page->page_filename = save_filename; /* final redraw */ x_pagesel_update (w_current); x_multiattrib_update (w_current); i_update_menus(w_current); /* restore saved undo structures */ page->undo_bottom = save_bottom; page->undo_tos = save_tos; page->undo_current = save_current; if (type == UNDO_ACTION) { if (page->undo_current) { page->undo_current = page->undo_current->prev; if (page->undo_current == NULL) { page->undo_current = page->undo_bottom; } } } else { /* type is REDO_ACTION */ if (page->undo_current) { page->undo_current = page->undo_current->next; if (page->undo_current == NULL) { page->undo_current = page->undo_tos; } } } /* don't have to free data here since filename, object_list are */ /* just pointers to the real data (lower in the stack) */ if (find_prev_data) { u_current->filename = NULL; u_current->object_list = NULL; } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(page->undo_bottom); printf("TOS: %s\n", page->undo_tos->filename); printf("CURRENT: %s\n", page->undo_current->filename); printf("----\n"); #endif }
/*! \todo Finish function documentation!!! * \brief * \par Function Description * * <B>type</B> can be one of the following values: * <DL> * <DT>*</DT><DD>UNDO_ACTION * <DT>*</DT><DD>REDO_ACTION * </DL> */ void o_undo_callback(GSCHEM_TOPLEVEL *w_current, int type) { TOPLEVEL *toplevel = w_current->toplevel; UNDO *u_current; UNDO *u_next; UNDO *save_bottom; UNDO *save_tos; UNDO *save_current; int save_logging; int find_prev_data=FALSE; char *save_filename; if (w_current->undo_control == FALSE) { s_log_message(_("Undo/Redo disabled in rc file\n")); return; } if (toplevel->page_current->undo_current == NULL) { return; } if (type == UNDO_ACTION) { u_current = toplevel->page_current->undo_current->prev; } else { u_current = toplevel->page_current->undo_current->next; } u_next = toplevel->page_current->undo_current; if (u_current == NULL) { return; } if (u_next->type == UNDO_ALL && u_current->type == UNDO_VIEWPORT_ONLY) { #if DEBUG printf("Type: %d\n", u_current->type); printf("Current is an undo all, next is viewport only!\n"); #endif find_prev_data = TRUE; if (w_current->undo_type == UNDO_DISK) { u_current->filename = o_undo_find_prev_filename(u_current); } else { u_current->object_list = o_undo_find_prev_object_head (u_current); } } /* save filename */ save_filename = g_strdup (toplevel->page_current->page_filename); /* save structure so it's not nuked */ save_bottom = toplevel->page_current->undo_bottom; save_tos = toplevel->page_current->undo_tos; save_current = toplevel->page_current->undo_current; toplevel->page_current->undo_bottom = NULL; toplevel->page_current->undo_tos = NULL; toplevel->page_current->undo_current = NULL; if (w_current->undo_type == UNDO_DISK && u_current->filename) { PAGE *p_new; s_page_delete (toplevel, toplevel->page_current); p_new = s_page_new(toplevel, u_current->filename); s_page_goto (toplevel, p_new); } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) { PAGE *p_new; s_page_delete (toplevel, toplevel->page_current); p_new = s_page_new (toplevel, save_filename); s_page_goto (toplevel, p_new); } /* temporarily disable logging */ save_logging = do_logging; do_logging = FALSE; if (w_current->undo_type == UNDO_DISK && u_current->filename) { f_open(toplevel, toplevel->page_current, u_current->filename, NULL); x_manual_resize(w_current); toplevel->page_current->page_control = u_current->page_control; toplevel->page_current->up = u_current->up; toplevel->page_current->CHANGED=1; } else if (w_current->undo_type == UNDO_MEMORY && u_current->object_list) { s_page_delete_objects (toplevel, toplevel->page_current); s_page_append_list (toplevel, toplevel->page_current, o_glist_copy_all (toplevel, u_current->object_list, NULL)); x_manual_resize(w_current); toplevel->page_current->page_control = u_current->page_control; toplevel->page_current->up = u_current->up; toplevel->page_current->CHANGED=1; } /* do misc setups */ set_window(toplevel, toplevel->page_current, u_current->left, u_current->right, u_current->top, u_current->bottom); x_hscrollbar_update(w_current); x_vscrollbar_update(w_current); /* restore logging */ do_logging = save_logging; /* set filename right */ g_free(toplevel->page_current->page_filename); toplevel->page_current->page_filename = save_filename; /* final redraw */ x_pagesel_update (w_current); x_multiattrib_update (w_current); /* Let the caller to decide if redraw or not */ o_invalidate_all (w_current); i_update_menus(w_current); /* restore saved undo structures */ toplevel->page_current->undo_bottom = save_bottom; toplevel->page_current->undo_tos = save_tos; toplevel->page_current->undo_current = save_current; if (type == UNDO_ACTION) { if (toplevel->page_current->undo_current) { toplevel->page_current->undo_current = toplevel->page_current->undo_current->prev; if (toplevel->page_current->undo_current == NULL) { toplevel->page_current->undo_current = toplevel->page_current->undo_bottom; } } } else { /* type is REDO_ACTION */ if (toplevel->page_current->undo_current) { toplevel->page_current->undo_current = toplevel->page_current->undo_current->next; if (toplevel->page_current->undo_current == NULL) { toplevel->page_current->undo_current = toplevel->page_current->undo_tos; } } } /* don't have to free data here since filename, object_list are */ /* just pointers to the real data (lower in the stack) */ if (find_prev_data) { u_current->filename = NULL; u_current->object_list = NULL; } #if DEBUG printf("\n\n---Undo----\n"); s_undo_print_all(toplevel->page_current->undo_bottom); printf("TOS: %s\n", toplevel->page_current->undo_tos->filename); printf("CURRENT: %s\n", toplevel->page_current->undo_current->filename); printf("----\n"); #endif }