Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

mainundo.C

Go to the documentation of this file.
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 // Minimum number of undoable operations on the undo stack
00015 #define UNDOMINLEVELS 5
00016 // Limits the bytes of memory used by the undo stack
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 // type of modification
00033         unsigned long load_flags;
00034         
00035 // data before the modification for undos
00036         char *data_before;          
00037 
00038         MainUndo *main_undo;
00039 
00040         void load_from_undo(FileXML *file, uint32_t load_flags);        // loads undo from the stringfile to the project
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 // get the initial project so we have something that the last undo reverts to
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 // the old data_after is the state before the change
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 // clear redo_stack
00081         while (redo_stack.last)
00082                 redo_stack.remove(redo_stack.last);
00083 
00084 // move item onto undo_stack
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 // ignore this push under certain conditions:
00114 // - if nothing was undone
00115         bool ignore = redo_stack.last == 0 &&
00116 // - if it is not the first push
00117                 undo_stack.last &&
00118 // - if it has the same description as the previous undo
00119                 strcmp(undo_stack.last->description, description) == 0 &&
00120 // - if it originates from the same creator
00121                 undo_stack.last->creator == creator &&
00122 // - if it follows closely after the previous undo
00123                 last_update->get_difference() < 300 /*millisec*/;
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 // the old data_after is the state before the change
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 // move item to redo_stack
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 // move item to undo_stack
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 // enforces that the undo stack does not exceed a size of UNDOMEMORY
00203 // except that it always has at least UNDOMINLEVELS entries
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 // truncate everything before and including i
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 // move the old data_after here
00254         char* before = data_before;
00255         data_before = 0;
00256         set_data_before(main_undo->data_after);
00257 
00258 // undo the state
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 // Here the master EDL loads 
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 

Generated on Sun Jan 8 13:38:56 2006 for Cinelerra-svn by  doxygen 1.4.4