Expose permanent debugging code to the C compiler.
[geda-gaf/berndj.git] / gschem / src / o_undo.c
blobba2e6d9711bedb85320216c2ef49554e4501837d
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2007 Ales Hvezda
4 * Copyright (C) 1998-2007 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <math.h>
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
31 #include "gschem.h"
33 #ifdef HAVE_LIBDMALLOC
34 #include <dmalloc.h>
35 #endif
37 static int undo_file_index=0;
38 static int prog_pid=0;
40 static char* tmp_path = NULL;
42 /* this is additional number of levels (or history) at which point the */
43 /* undo stack will be trimmed, it's used a safety to prevent running out */
44 /* of entries to free */
45 #define UNDO_PADDING 5
47 /*! \todo Finish function documentation!!!
48 * \brief
49 * \par Function Description
52 void o_undo_init(void)
54 prog_pid = getpid();
56 tmp_path = g_strdup (getenv("TMP"));
57 if (tmp_path == NULL) {
58 tmp_path = g_strdup ("/tmp");
60 if (GEDA_DEBUG) {
61 printf("%s\n", tmp_path);
65 /*! \todo Finish function documentation!!!
66 * \brief
67 * \par Function Description
70 * <B>flag</B> can be one of the following values:
71 * <DL>
72 * <DT>*</DT><DD>UNDO_ALL
73 * <DT>*</DT><DD>UNDO_VIEWPORT_ONLY
74 * </DL>
76 void o_undo_savestate(GSCHEM_TOPLEVEL *w_current, int flag)
78 TOPLEVEL *toplevel = w_current->toplevel;
79 PAGE *page = toplevel->page_current;
80 char *filename = NULL;
81 OBJECT *object_head = NULL;
82 int levels;
84 /* save autosave backups if necessary */
85 o_autosave_backups(w_current);
87 if (w_current->undo_control == FALSE) {
88 return;
91 if (w_current->undo_type == UNDO_DISK && flag == UNDO_ALL) {
92 /* Increment the number of operations since last backup if
93 auto-save is enabled */
94 if (toplevel->auto_save_interval != 0) {
95 page->ops_since_last_backup++;
98 filename = g_strdup_printf("%s%cgschem.save%d_%d.sch",
99 tmp_path, G_DIR_SEPARATOR,
100 prog_pid, undo_file_index++);
102 /* Changed from f_save to o_save when adding backup copy creation. */
103 /* f_save manages the creation of backup copies.
104 This way, f_save is called only when saving a file, and not when
105 saving an undo backup copy */
106 o_save(toplevel, page, filename);
107 } else if (w_current->undo_type == UNDO_MEMORY && flag == UNDO_ALL) {
108 /* Increment the number of operations since last backup if
109 auto-save is enabled */
110 if (toplevel->auto_save_interval != 0) {
111 page->ops_since_last_backup++;
114 object_head = s_toplevel_new_object(toplevel, OBJ_HEAD, "undo_head");
116 o_list_copy_all(toplevel, page->object_head->next,
117 object_head, NORMAL_FLAG);
120 s_undo_add(toplevel, page, flag, filename, object_head,
121 page->left, page->top, page->right, page->bottom,
122 page->page_control, page->up_page);
124 if (GEDA_DEBUG) {
125 printf("\n\n---Undo----\n");
126 s_undo_print_all(page);
127 printf("----\n");
130 g_free(filename);
132 /* Now go through and see if we need to free/remove some undo levels */
133 /* so we stay within the limits */
135 /* only check history every 10 undo savestates */
136 if (undo_file_index % 10) {
137 return;
140 if (GEDA_DEBUG) {
141 levels = s_undo_levels(page);
143 printf("levels: %d\n", levels);
146 s_undo_trim(toplevel, page,
147 w_current->undo_levels + UNDO_PADDING);
149 if (GEDA_DEBUG) {
150 printf("\n\n---Undo----\n");
151 s_undo_print_all(page);
152 printf("----\n");
156 /*! \todo Finish function documentation!!!
157 * \brief
158 * \par Function Description
160 * <B>type</B> can be one of the following values:
161 * <DL>
162 * <DT>*</DT><DD>UNDO_ACTION
163 * <DT>*</DT><DD>REDO_ACTION
164 * </DL>
166 void o_undo_callback(GSCHEM_TOPLEVEL *w_current, int type)
168 TOPLEVEL *toplevel = w_current->toplevel;
169 PAGE *page = toplevel->page_current;
170 PAGE *p_new;
171 GList *old_state, *new_state;
172 UNDO *u_new;
173 UNDO *u_old;
174 GList *save_newest;
175 int save_logging;
176 int find_prev_data=FALSE;
177 int prev_status;
179 char *save_filename;
181 if (w_current->undo_control == FALSE) {
182 s_log_message(_("Undo/Redo disabled in rc file\n"));
183 return;
186 if (page->undo_current == NULL) {
187 return;
190 switch (type) {
191 case UNDO_ACTION:
192 new_state = page->undo_current->next;
193 break;
194 case REDO_ACTION:
195 new_state = page->undo_current->prev;
196 break;
197 default:
198 return;
201 old_state = page->undo_current;
203 if (new_state == NULL) {
204 /* There is no state to undo/redo to. */
205 return;
208 u_new = new_state->data;
209 u_old = old_state->data;
211 switch (w_current->undo_type) {
212 case UNDO_DISK:
213 if (u_new->filename == NULL) {
214 s_log_message(_("File-based undo requested with no file\n"));
215 return;
217 break;
218 case UNDO_MEMORY:
219 if (u_new->object_head == NULL) {
220 s_log_message(_("In-memory undo requested with no object list\n"));
221 return;
223 break;
224 default:
225 s_log_message(_("Unknown undo type\n"));
226 return;
229 if (u_old->type == UNDO_ALL && u_new->type == UNDO_VIEWPORT_ONLY) {
230 if (GEDA_DEBUG) {
231 printf("Type: %d\n", u_new->type);
232 printf("Current is an undo all, next is viewport only!\n");
234 find_prev_data = TRUE;
236 o_undo_copy_prev_memento(new_state, w_current->undo_type);
239 /* save filename */
240 save_filename = g_strdup (page->page_filename);
242 /* save structure so it's not nuked */
243 save_newest = page->undo_newest;
244 page->undo_newest = NULL;
245 page->undo_current = NULL;
247 switch (w_current->undo_type) {
248 case UNDO_DISK:
249 p_new = s_page_new(toplevel, u_new->filename);
250 break;
251 case UNDO_MEMORY:
252 p_new = s_page_new (toplevel, save_filename);
253 break;
254 default:
255 /* We handled the default case gracefully earlier. */
256 g_assert(0);
258 p_new->width = w_current->win_width;
259 p_new->height = w_current->win_height;
260 s_toplevel_goto_page(toplevel, p_new);
261 set_window(toplevel, p_new,
262 toplevel->init_left, toplevel->init_right,
263 toplevel->init_top, toplevel->init_bottom);
265 s_hierarchy_replace_page(toplevel, page, p_new);
267 /* Finally delete the page now that the new page is linked. */
268 s_page_delete (toplevel, page);
270 /* temporarily disable logging */
271 save_logging = do_logging;
272 prev_status = toplevel->DONT_REDRAW;
273 toplevel->DONT_REDRAW = 1;
274 do_logging = FALSE;
276 if (w_current->undo_type == UNDO_DISK && u_new->filename) {
277 f_open(toplevel, p_new, u_new->filename, NULL);
279 x_manual_resize(w_current);
280 p_new->page_control = u_new->page_control;
281 p_new->up_page = u_new->up_page;
282 p_new->CHANGED=1;
283 } else if (w_current->undo_type == UNDO_MEMORY && u_new->object_head) {
284 s_delete_list_fromstart(toplevel, p_new->object_head);
286 p_new->object_head = s_toplevel_new_object(toplevel, OBJ_HEAD, "object_head");
288 o_list_copy_all(toplevel, u_new->object_head->next,
289 p_new->object_head,
290 NORMAL_FLAG);
292 p_new->object_tail = return_tail(p_new->object_head);
293 x_manual_resize(w_current);
294 p_new->page_control = u_new->page_control;
295 p_new->up_page = u_new->up_page;
296 p_new->CHANGED=1;
299 /* do misc setups */
300 set_window(toplevel, p_new,
301 u_new->left, u_new->right,
302 u_new->top, u_new->bottom);
303 x_hscrollbar_update(w_current);
304 x_vscrollbar_update(w_current);
306 /* restore logging */
307 do_logging = save_logging;
309 /* set filename right */
310 g_free(p_new->page_filename);
311 p_new->page_filename = save_filename;
313 /* final redraw */
314 x_pagesel_update (w_current);
315 x_multiattrib_update(w_current, p_new->selection_list);
317 /* Let the caller to decide if redraw or not */
318 /* toplevel->DONT_REDRAW = 0; */
319 toplevel->DONT_REDRAW = prev_status;
321 if (!toplevel->DONT_REDRAW) {
322 o_redraw_all(w_current);
324 i_update_menus(w_current);
326 /* restore saved undo structures */
327 p_new->undo_newest = save_newest;
329 p_new->undo_current = new_state;
331 /* don't have to free data here since filename, object_head are */
332 /* just pointers to the real data (lower in the stack) */
333 if (find_prev_data) {
334 u_new->filename = NULL;
335 u_new->object_head = NULL;
338 if (GEDA_DEBUG) {
339 printf("\n\n---Undo----\n");
340 s_undo_print_all(p_new);
341 printf("----\n");
345 /*! \todo Finish function documentation!!!
346 * \brief
347 * \par Function Description
350 void o_undo_cleanup(void)
352 int i;
353 char *filename;
355 for (i = 0 ; i < undo_file_index; i++) {
356 filename = g_strdup_printf("%s%cgschem.save%d_%d.sch", tmp_path,
357 G_DIR_SEPARATOR, prog_pid, i);
358 unlink(filename);
359 g_free(filename);
362 g_free(tmp_path);
363 tmp_path = NULL;
366 /*! \todo Finish function documentation!!!
367 * \brief
368 * \par Function Description
371 void o_undo_remove_last_undo(GSCHEM_TOPLEVEL *w_current)
373 TOPLEVEL *toplevel = w_current->toplevel;
374 if (toplevel->page_current->undo_current == NULL) {
375 return;
378 toplevel->page_current->undo_current =
379 toplevel->page_current->undo_current->next;