00001 #include "asset.h"
00002 #include "assets.h"
00003 #include "edl.h"
00004 #include "filexml.h"
00005 #include "mainindexes.h"
00006 #include "mainmenu.h"
00007 #include "mainsession.h"
00008 #include "mainundo.h"
00009 #include "mwindow.h"
00010 #include "mwindowgui.h"
00011 #include "undostackitem.h"
00012 #include <string.h>
00013
00014
00015 #define UNDOMINLEVELS 5
00016
00017 #define UNDOMEMORY 50000000
00018
00019
00020 class MainUndoStackItem : public UndoStackItem
00021 {
00022 public:
00023 MainUndoStackItem(MainUndo* undo, char* description,
00024 uint32_t load_flags, void* creator);
00025 virtual ~MainUndoStackItem();
00026
00027 void set_data_before(char *data);
00028 virtual void undo();
00029 virtual int get_size();
00030
00031 private:
00032
00033 unsigned long load_flags;
00034
00035
00036 char *data_before;
00037
00038 MainUndo *main_undo;
00039
00040 void load_from_undo(FileXML *file, uint32_t load_flags);
00041 };
00042
00043
00044 MainUndo::MainUndo(MWindow *mwindow)
00045 {
00046 this->mwindow = mwindow;
00047 new_entry = 0;
00048 data_after = 0;
00049 last_update = new Timer;
00050
00051
00052 capture_state();
00053 }
00054
00055 MainUndo::~MainUndo()
00056 {
00057 delete [] data_after;
00058 delete last_update;
00059 }
00060
00061 void MainUndo::update_undo(char *description, uint32_t load_flags,
00062 void *creator, int changes_made)
00063 {
00064 if (ignore_push(description, load_flags, creator))
00065 {
00066 capture_state();
00067 return;
00068 }
00069
00070 MainUndoStackItem* new_entry = new MainUndoStackItem(this, description, load_flags, creator);
00071
00072
00073 new_entry->set_data_before(data_after);
00074
00075 push_undo_item(new_entry);
00076 }
00077
00078 void MainUndo::push_undo_item(UndoStackItem *item)
00079 {
00080
00081 while (redo_stack.last)
00082 redo_stack.remove(redo_stack.last);
00083
00084
00085 undo_stack.append(item);
00086 prune_undo();
00087
00088 capture_state();
00089
00090 mwindow->session->changes_made = 1;
00091 mwindow->gui->lock_window("MainUndo::update_undo_before");
00092 mwindow->gui->mainmenu->undo->update_caption(item->description);
00093 mwindow->gui->mainmenu->redo->update_caption("");
00094 mwindow->gui->unlock_window();
00095 }
00096
00097 void MainUndo::capture_state()
00098 {
00099 FileXML file;
00100 mwindow->edl->save_xml(mwindow->plugindb,
00101 &file,
00102 "",
00103 0,
00104 0);
00105 file.terminate_string();
00106 delete [] data_after;
00107 data_after = new char[strlen(file.string)+1];
00108 strcpy(data_after, file.string);
00109 }
00110
00111 bool MainUndo::ignore_push(char *description, uint32_t load_flags, void* creator)
00112 {
00113
00114
00115 bool ignore = redo_stack.last == 0 &&
00116
00117 undo_stack.last &&
00118
00119 strcmp(undo_stack.last->description, description) == 0 &&
00120
00121 undo_stack.last->creator == creator &&
00122
00123 last_update->get_difference() < 300 ;
00124 last_update->update();
00125 return ignore;
00126 }
00127
00128 void MainUndo::push_state(char *description, uint32_t load_flags, void* creator)
00129 {
00130 if (ignore_push(description, load_flags, creator))
00131 {
00132 capture_state();
00133 }
00134 else
00135 {
00136 MainUndoStackItem* new_entry = new MainUndoStackItem(this, description, load_flags, creator);
00137
00138 new_entry->set_data_before(data_after);
00139 push_undo_item(new_entry);
00140 }
00141 mwindow->session->changes_made = 1;
00142 }
00143
00144
00145
00146
00147
00148
00149 int MainUndo::undo()
00150 {
00151 UndoStackItem* current_entry = undo_stack.last;
00152
00153 if(current_entry)
00154 {
00155
00156 undo_stack.remove_pointer(current_entry);
00157 current_entry->undo();
00158 redo_stack.append(current_entry);
00159 capture_state();
00160
00161 if(mwindow->gui)
00162 {
00163 mwindow->gui->mainmenu->redo->update_caption(current_entry->description);
00164
00165 if(undo_stack.last)
00166 mwindow->gui->mainmenu->undo->update_caption(undo_stack.last->description);
00167 else
00168 mwindow->gui->mainmenu->undo->update_caption("");
00169 }
00170 }
00171
00172 reset_creators();
00173 return 0;
00174 }
00175
00176 int MainUndo::redo()
00177 {
00178 UndoStackItem* current_entry = redo_stack.last;
00179
00180 if(current_entry)
00181 {
00182
00183 redo_stack.remove_pointer(current_entry);
00184 current_entry->undo();
00185 undo_stack.append(current_entry);
00186 capture_state();
00187
00188 if(mwindow->gui)
00189 {
00190 mwindow->gui->mainmenu->undo->update_caption(current_entry->description);
00191
00192 if(redo_stack.last)
00193 mwindow->gui->mainmenu->redo->update_caption(redo_stack.last->description);
00194 else
00195 mwindow->gui->mainmenu->redo->update_caption("");
00196 }
00197 }
00198 reset_creators();
00199 return 0;
00200 }
00201
00202
00203
00204 void MainUndo::prune_undo()
00205 {
00206 int size = 0;
00207 int levels = 0;
00208
00209 UndoStackItem* i = undo_stack.last;
00210 while (i != 0 && (levels < UNDOMINLEVELS || size <= UNDOMEMORY))
00211 {
00212 size += i->get_size();
00213 ++levels;
00214 i = i->previous;
00215 }
00216
00217 if (i != 0)
00218 {
00219
00220 while (undo_stack.first != i)
00221 undo_stack.remove(undo_stack.first);
00222 undo_stack.remove(undo_stack.first);
00223 }
00224 }
00225
00226
00227
00228
00229
00230 MainUndoStackItem::MainUndoStackItem(MainUndo* main_undo, char* description,
00231 uint32_t load_flags, void* creator)
00232 {
00233 data_before = 0;
00234 this->load_flags = load_flags;
00235 this->main_undo = main_undo;
00236 set_description(description);
00237 set_creator(creator);
00238 }
00239
00240 MainUndoStackItem::~MainUndoStackItem()
00241 {
00242 delete [] data_before;
00243 }
00244
00245 void MainUndoStackItem::set_data_before(char *data)
00246 {
00247 data_before = new char[strlen(data) + 1];
00248 strcpy(data_before, data);
00249 }
00250
00251 void MainUndoStackItem::undo()
00252 {
00253
00254 char* before = data_before;
00255 data_before = 0;
00256 set_data_before(main_undo->data_after);
00257
00258
00259 FileXML file;
00260
00261 file.read_from_string(before);
00262 load_from_undo(&file, load_flags);
00263 }
00264
00265 int MainUndoStackItem::get_size()
00266 {
00267 return data_before ? strlen(data_before) : 0;
00268 }
00269
00270
00271 void MainUndoStackItem::load_from_undo(FileXML *file, uint32_t load_flags)
00272 {
00273 MWindow* mwindow = main_undo->mwindow;
00274 mwindow->edl->load_xml(mwindow->plugindb, file, load_flags);
00275 for(Asset *asset = mwindow->edl->assets->first;
00276 asset;
00277 asset = asset->next)
00278 {
00279 mwindow->mainindexes->add_next_asset(0, asset);
00280 }
00281 mwindow->mainindexes->start_build();
00282 }
00283
00284
00285 void MainUndo::reset_creators()
00286 {
00287 for(UndoStackItem *current = undo_stack.first;
00288 current;
00289 current = NEXT)
00290 {
00291 current->set_creator(0);
00292 }
00293 }
00294
00295
00296