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