4 * Copyright (C) 1997-2011 Adam Williams <broadcast at earthling dot net>
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-1307 USA
28 #include "indexfile.h"
29 #include "mainindexes.h"
31 #include "mainsession.h"
34 #include "mwindowgui.h"
36 #include "undostack.h"
38 MainUndo::MainUndo(MWindow *mwindow)
40 this->mwindow = mwindow;
41 undo_stack = new UndoStack;
42 last_update = new Timer;
52 void MainUndo::update_undo_entry(const char *description,
59 mwindow->edl->save_xml(&file, "");
60 file.terminate_string();
61 if(changes_made) mwindow->session->changes_made = 1;
63 // Remove all entries after current and create new one
64 UndoStackItem *current = undo_stack->push();
66 current->set_flags(load_flags);
67 current->set_data(file.string());
68 current->set_description((char*)description);
69 current->set_creator(creator);
70 current->set_filename(mwindow->session->filename);
71 //printf("MainUndo::update_undo_entry %d %p %s\n", __LINE__, current, current->get_filename());
73 // Can't undo only 1 record.
74 if(undo_stack->total() > 1)
76 // mwindow->gui->lock_window("MainUndo::update_undo");
77 mwindow->gui->mainmenu->undo->update_caption(description);
78 mwindow->gui->mainmenu->redo->update_caption("");
79 // mwindow->gui->unlock_window();
83 last_update->update();
86 void MainUndo::update_undo_before(const char *description, void *creator)
88 //printf("MainUndo::update_undo_before %d\n", __LINE__);
89 if(undo_stack->current && !(undo_stack->number_of(undo_stack->current) % 2))
91 printf("MainUndo::update_undo_before %d \"%s\": must be on an after entry to do this. size=%d\n",
99 // Move up an entry to get back in sync
103 mwindow->commit_commercial();
105 // Discard if creator matches previous before entry and within a time limit
108 UndoStackItem *current = undo_stack->current;
109 // Currently on an after entry
115 // Now on a before entry
118 if(current->get_creator() == creator &&
119 !strcmp(current->get_description(), description) &&
120 last_update->get_difference() < UNDO_SPAN)
122 // Before entry has same creator within minimum time. Reuse it.
123 // Stack must point to the before entry
124 undo_stack->current = current;
130 // Append new entry after current position
131 update_undo_entry("", 0, creator, 0);
134 void MainUndo::update_undo_after(const char *description,
138 //printf("MainUndo::update_undo_after %d\n", __LINE__);
139 if(undo_stack->number_of(undo_stack->current) % 2)
141 printf("MainUndo::update_undo_after %d \"%s\": must be on a before entry to do this. size=%d\n",
144 undo_stack->total());
148 // Not getting any update_undo_before to get back in sync, so just append 1 here
152 update_undo_entry(description, load_flags, 0, changes_made);
154 // Update the before entry flags
155 UndoStackItem *current = undo_stack->last;
156 if(current) current = PREVIOUS;
159 current->set_flags(load_flags);
160 current->set_description((char*)description);
165 UndoStackItem *MainUndo::next_undo()
167 return undo_stack->get_current_undo();
170 UndoStackItem *MainUndo::next_redo()
172 return undo_stack->get_current_redo();
175 int MainUndo::undo_load_flags()
177 UndoStackItem *item = next_undo();
178 return item ? item->get_flags() : 0;
181 int MainUndo::redo_load_flags()
183 UndoStackItem *item = next_redo();
184 return item ? item->get_flags() : 0;
190 mwindow->gui->close_keyvalue_popup();
191 mwindow->undo_commercial();
193 UndoStackItem *current = undo_stack->current;
195 undo_stack->current = next_undo();
196 if( undo_stack->number_of(current) % 2 )
197 current = PREVIOUS; // Now have an even number
200 // Set the redo text to the current description
201 UndoStackItem *next = NEXT;
202 mwindow->gui->mainmenu->redo->
203 update_caption(next ? next->get_description() : "");
204 char *current_data = current->get_data();
207 file.read_from_string(current_data);
208 delete [] current_data;
209 load_from_undo(&file, current->get_flags());
210 //printf("MainUndo::undo %d %s\n", __LINE__, current->get_filename());
211 mwindow->set_filename(current->get_filename());
213 // Now update the menu with the after entry
214 UndoStackItem *prev = PREVIOUS;
215 mwindow->gui->mainmenu->undo->
216 update_caption(prev ? prev->get_description() : "");
220 mwindow->reset_caches(1);
227 mwindow->gui->close_keyvalue_popup();
228 UndoStackItem *current = next_redo();
230 undo_stack->current = current;
231 char *current_data = current->get_data();
233 mwindow->set_filename(current->get_filename());
235 file.read_from_string(current_data);
236 load_from_undo(&file, current->get_flags());
237 delete [] current_data;
239 mwindow->gui->mainmenu->undo->
240 update_caption(current->get_description());
241 // Get next after entry
242 if( (current=NEXT) ) current = NEXT;
243 mwindow->gui->mainmenu->redo->
244 update_caption(current ? current->get_description() : "");
247 mwindow->reset_caches(1);
254 // Here the master EDL loads
255 int MainUndo::load_from_undo(FileXML *file, uint32_t load_flags)
257 mwindow->hide_plugins();
258 if( load_flags & LOAD_SESSION ) {
259 mwindow->gui->unlock_window();
260 mwindow->close_mixers();
261 mwindow->gui->lock_window("MainUndo::load_from_undo");
263 EDL *prev_edl = mwindow->edl;
264 if( (load_flags & LOAD_ALL) == LOAD_ALL )
266 mwindow->edl->load_xml(file, load_flags);
267 for( Asset *asset=mwindow->edl->assets->first; asset; asset=asset->next ) {
268 mwindow->mainindexes->add_indexable(asset);
270 if( prev_edl != mwindow->edl ) {
271 for( int i=0; i<mwindow->edl->nested_edls.size(); ++i ) {
272 EDL *nested_edl = mwindow->edl->nested_edls[i];
273 if( !nested_edl->path[0] ) continue;
274 int k = prev_edl->nested_edls.size();
275 while( --k >= 0 && // if nested edl was updated, force index rebuild
276 strcmp(nested_edl->path, prev_edl->nested_edls[k]->path) );
277 if( k >= 0 && prev_edl->nested_edls[k]->equivalent_output(nested_edl) >= 0 )
278 IndexFile::delete_index_files(mwindow->preferences, nested_edl);
279 mwindow->mainindexes->add_indexable(nested_edl);
281 prev_edl->remove_user();
283 mwindow->mainindexes->start_build();
284 mwindow->update_plugin_guis(1);
285 if( load_flags & LOAD_SESSION ) {
286 mwindow->gui->unlock_window();
287 mwindow->open_mixers();
288 mwindow->gui->lock_window("MainUndo::load_from_undo");
294 void MainUndo::reset_creators()
296 for( UndoStackItem *current=undo_stack->first; current; current=NEXT ) {
297 current->set_creator(0);
302 void MainUndo::dump(FILE *fp)
304 undo_stack->dump(fp);
307 void MainUndo::save(FILE *fp)
309 undo_stack->save(fp);
312 void MainUndo::load(FILE *fp)
314 undo_stack->load(fp);
315 UndoStackItem *current = undo_stack->current;
316 char *current_data = current ? current->get_data() : 0;
317 if( !current_data ) return;
318 mwindow->gui->lock_window("MainUndo::load");
319 UndoStackItem *next = current->next;
320 mwindow->gui->mainmenu->redo->
321 update_caption(next ? next->get_description() : "");
322 mwindow->set_filename(current->get_filename());
324 file.read_from_string(current_data);
325 load_from_undo(&file, LOAD_ALL);
326 delete [] current_data;
327 UndoStackItem *prev = current->previous;
328 mwindow->gui->mainmenu->undo->
329 update_caption(prev ? prev->get_description() : "");
330 mwindow->update_project(LOADMODE_REPLACE);
331 mwindow->gui->unlock_window();