5 #include "mainindexes.h"
7 #include "mainsession.h"
10 #include "mwindowgui.h"
11 #include "undostackitem.h"
15 // Minimum number of undoable operations on the undo stack
16 #define UNDOMINLEVELS 5
17 // Limits the bytes of memory used by the undo stack
18 #define UNDOMEMORY 50000000
21 class MainUndoStackItem : public UndoStackItem
24 MainUndoStackItem(MainUndo* undo, char* description,
25 uint32_t load_flags, void* creator);
26 virtual ~MainUndoStackItem();
28 void set_data_before(char *data);
30 virtual int get_size();
33 // type of modification
34 unsigned long load_flags;
36 // data before the modification for undos
41 void load_from_undo(FileXML *file, uint32_t load_flags); // loads undo from the stringfile to the project
45 MainUndo::MainUndo(MWindow *mwindow)
47 this->mwindow = mwindow;
50 last_update = new Timer;
52 // get the initial project so we have something that the last undo reverts to
62 void MainUndo::update_undo(char *description, uint32_t load_flags,
63 void *creator, int changes_made)
65 if (ignore_push(description, load_flags, creator))
71 MainUndoStackItem* new_entry = new MainUndoStackItem(this, description, load_flags, creator);
73 // the old data_after is the state before the change
74 new_entry->set_data_before(data_after);
76 push_undo_item(new_entry);
79 void MainUndo::push_undo_item(UndoStackItem *item)
82 while (redo_stack.last)
83 redo_stack.remove(redo_stack.last);
85 // move item onto undo_stack
86 undo_stack.append(item);
91 mwindow->session->changes_made = 1;
92 mwindow->gui->lock_window("MainUndo::update_undo_before");
93 mwindow->gui->mainmenu->undo->update_caption(item->description);
94 mwindow->gui->mainmenu->redo->update_caption("");
95 mwindow->gui->unlock_window();
98 void MainUndo::capture_state()
101 mwindow->edl->save_xml(mwindow->plugindb,
106 file.terminate_string();
107 delete [] data_after;
108 data_after = new char[strlen(file.string)+1];
109 strcpy(data_after, file.string);
112 bool MainUndo::ignore_push(char *description, uint32_t load_flags, void* creator)
114 // ignore this push under certain conditions:
115 // - if nothing was undone
116 bool ignore = redo_stack.last == 0 &&
117 // - if it is not the first push
119 // - if it has the same description as the previous undo
120 strcmp(undo_stack.last->description, description) == 0 &&
121 // - if it originates from the same creator
122 undo_stack.last->creator == creator &&
123 // - if it follows closely after the previous undo
124 last_update->get_difference() < 300 /*millisec*/;
125 last_update->update();
129 void MainUndo::push_state(char *description, uint32_t load_flags, void* creator)
131 if (ignore_push(description, load_flags, creator))
137 MainUndoStackItem* new_entry = new MainUndoStackItem(this, description, load_flags, creator);
138 // the old data_after is the state before the change
139 new_entry->set_data_before(data_after);
140 push_undo_item(new_entry);
142 mwindow->session->changes_made = 1;
152 UndoStackItem* current_entry = undo_stack.last;
156 // move item to redo_stack
157 undo_stack.remove_pointer(current_entry);
158 current_entry->undo();
159 redo_stack.append(current_entry);
164 mwindow->gui->mainmenu->redo->update_caption(current_entry->description);
167 mwindow->gui->mainmenu->undo->update_caption(undo_stack.last->description);
169 mwindow->gui->mainmenu->undo->update_caption("");
179 UndoStackItem* current_entry = redo_stack.last;
183 // move item to undo_stack
184 redo_stack.remove_pointer(current_entry);
185 current_entry->undo();
186 undo_stack.append(current_entry);
191 mwindow->gui->mainmenu->undo->update_caption(current_entry->description);
194 mwindow->gui->mainmenu->redo->update_caption(redo_stack.last->description);
196 mwindow->gui->mainmenu->redo->update_caption("");
203 // enforces that the undo stack does not exceed a size of UNDOMEMORY
204 // except that it always has at least UNDOMINLEVELS entries
205 void MainUndo::prune_undo()
210 UndoStackItem* i = undo_stack.last;
211 while (i != 0 && (levels < UNDOMINLEVELS || size <= UNDOMEMORY))
213 size += i->get_size();
220 // truncate everything before and including i
221 while (undo_stack.first != i)
222 undo_stack.remove(undo_stack.first);
223 undo_stack.remove(undo_stack.first);
231 MainUndoStackItem::MainUndoStackItem(MainUndo* main_undo, char* description,
232 uint32_t load_flags, void* creator)
235 this->load_flags = load_flags;
236 this->main_undo = main_undo;
237 set_description(description);
238 set_creator(creator);
241 MainUndoStackItem::~MainUndoStackItem()
243 delete [] data_before;
246 void MainUndoStackItem::set_data_before(char *data)
248 data_before = new char[strlen(data) + 1];
249 strcpy(data_before, data);
252 void MainUndoStackItem::undo()
254 // move the old data_after here
255 char* before = data_before;
257 set_data_before(main_undo->data_after);
262 file.read_from_string(before);
263 load_from_undo(&file, load_flags);
266 int MainUndoStackItem::get_size()
268 return data_before ? strlen(data_before) : 0;
271 // Here the master EDL loads
272 void MainUndoStackItem::load_from_undo(FileXML *file, uint32_t load_flags)
274 MWindow* mwindow = main_undo->mwindow;
275 mwindow->edl->load_xml(mwindow->plugindb, file, load_flags);
276 for(Asset *asset = mwindow->edl->assets->first;
280 mwindow->mainindexes->add_next_asset(0, asset);
282 mwindow->mainindexes->start_build();
286 void MainUndo::reset_creators()
288 for(UndoStackItem *current = undo_stack.first;
292 current->set_creator(0);