r616: The UndoStackItem::redo() is dropped and replaced by UndoStackItem::undo().
[cinelerra_cv.git] / cinelerra / mainundo.C
blobdc504dd3cde6ae3b6512dd02ee2467d5d93ef337
1 #include "asset.h"
2 #include "assets.h"
3 #include "edl.h"
4 #include "filexml.h"
5 #include "mainindexes.h"
6 #include "mainmenu.h"
7 #include "mainsession.h"
8 #include "mainundo.h"
9 #include "mwindow.h"
10 #include "mwindowgui.h"
11 #include "undostackitem.h"
12 #include <string.h>
14 // Minimum number of undoable operations on the undo stack
15 #define UNDOMINLEVELS 5
16 // Limits the bytes of memory used by the undo stack
17 #define UNDOMEMORY 50000000
20 class MainUndoStackItem : public UndoStackItem
22 public:
23         MainUndoStackItem(MainUndo* undo, char* description,
24                         uint32_t load_flags);
25         virtual ~MainUndoStackItem();
27         void set_data_before(char *data);
28         virtual void undo();
29         virtual int get_size();
31 private:
32 // type of modification
33         unsigned long load_flags;
34         
35 // data before the modification for undos
36         char *data_before;          
38         MainUndo *main_undo;
40         void load_from_undo(FileXML *file, uint32_t load_flags);        // loads undo from the stringfile to the project
44 MainUndo::MainUndo(MWindow *mwindow)
45
46         this->mwindow = mwindow;
47         new_entry = 0;
48         data_after = 0;
50 // get the initial project so we have something that the last undo reverts to
51         capture_state();
54 MainUndo::~MainUndo()
56         delete [] data_after;
59 void MainUndo::push_undo_item(UndoStackItem *item)
61 // clear redo_stack
62         while (redo_stack.last)
63                 redo_stack.remove(redo_stack.last);
65 // move item onto undo_stack
66         undo_stack.append(item);
67         prune_undo();
69         capture_state();
71         mwindow->session->changes_made = 1;
72    mwindow->gui->lock_window("MainUndo::update_undo_before");
73    mwindow->gui->mainmenu->undo->update_caption(item->description);
74    mwindow->gui->mainmenu->redo->update_caption("");
75    mwindow->gui->unlock_window();
78 void MainUndo::capture_state()
80         FileXML file;
81         mwindow->edl->save_xml(mwindow->plugindb, 
82                 &file, 
83                 "",
84                 0,
85                 0);
86         file.terminate_string();
87         delete [] data_after;
88         data_after = new char[strlen(file.string)+1];
89         strcpy(data_after, file.string);
92 void MainUndo::update_undo_before(char *description, uint32_t load_flags)
94         if(!new_entry)
95         {
96                 new_entry = new MainUndoStackItem(this, description, load_flags);
97         }
100 void MainUndo::update_undo_after()
102         if(new_entry)
103         {
104 // the old data_after is the state before the change
105                 new_entry->set_data_before(data_after);
106                 data_after = 0;
108                 push_undo_item(new_entry);
109                 new_entry = 0;
110         }
118 int MainUndo::undo()
120         UndoStackItem* current_entry = undo_stack.last;
122         if(current_entry)
123         {
124 // move item to redo_stack
125                 undo_stack.remove_pointer(current_entry);
126                 current_entry->undo();
127                 redo_stack.append(current_entry);
128                 capture_state();
130                 if(mwindow->gui)
131                 {
132                         mwindow->gui->mainmenu->redo->update_caption(current_entry->description);
134                         if(undo_stack.last)
135                                 mwindow->gui->mainmenu->undo->update_caption(undo_stack.last->description);
136                         else
137                                 mwindow->gui->mainmenu->undo->update_caption("");
138                 }
139         }
140         return 0;
143 int MainUndo::redo()
145         UndoStackItem* current_entry = redo_stack.last;
146         
147         if(current_entry)
148         {
149 // move item to undo_stack
150                 redo_stack.remove_pointer(current_entry);
151                 current_entry->undo();
152                 undo_stack.append(current_entry);
153                 capture_state();
155                 if(mwindow->gui)
156                 {
157                         mwindow->gui->mainmenu->undo->update_caption(current_entry->description);
158                         
159                         if(redo_stack.last)
160                                 mwindow->gui->mainmenu->redo->update_caption(redo_stack.last->description);
161                         else
162                                 mwindow->gui->mainmenu->redo->update_caption("");
163                 }
164         }
165         return 0;
168 // enforces that the undo stack does not exceed a size of UNDOMEMORY
169 // except that it always has at least UNDOMINLEVELS entries
170 void MainUndo::prune_undo()
172         int size = 0;
173         int levels = 0;
175         UndoStackItem* i = undo_stack.last;
176         while (i != 0 && (levels < UNDOMINLEVELS || size <= UNDOMEMORY))
177         {
178                 size += i->get_size();
179                 ++levels;
180                 i = i->previous;
181         }
183         if (i != 0)
184         {
185 // truncate everything before and including i
186                 while (undo_stack.first != i)
187                         undo_stack.remove(undo_stack.first);
188                 undo_stack.remove(undo_stack.first);
189         }
196 MainUndoStackItem::MainUndoStackItem(MainUndo* main_undo, char* description,
197                         uint32_t load_flags)
199         data_before = 0;
200         this->load_flags = load_flags;
201         this->main_undo = main_undo;
202         set_description(description);
205 MainUndoStackItem::~MainUndoStackItem()
207         delete [] data_before;
210 void MainUndoStackItem::set_data_before(char *data)
212         data_before = new char[strlen(data) + 1];
213         strcpy(data_before, data);
216 void MainUndoStackItem::undo()
218 // move the old data_after here
219         char* before = data_before;
220         data_before = 0;
221         set_data_before(main_undo->data_after);
223 // undo the state
224         FileXML file;
226         file.read_from_string(before);
227         load_from_undo(&file, load_flags);
230 int MainUndoStackItem::get_size()
232         return data_before ? strlen(data_before) : 0;
235 // Here the master EDL loads 
236 void MainUndoStackItem::load_from_undo(FileXML *file, uint32_t load_flags)
238         MWindow* mwindow = main_undo->mwindow;
239         mwindow->edl->load_xml(mwindow->plugindb, file, load_flags);
240         for(Asset *asset = mwindow->edl->assets->first;
241                 asset;
242                 asset = asset->next)
243         {
244                 mwindow->mainindexes->add_next_asset(asset);
245         }
246         mwindow->mainindexes->start_build();