olaf neophyte and de.po updates, valgrind tweaks, delete green lady, inkscape dpi=96
[goodguy/history.git] / cinelerra-5.1 / cinelerra / undostack.C
index 0c49981b22ff63f025deab29a4f2561de1633bad..23f33bc193148fadc237dc9ed85d8e8133429778 100644 (file)
@@ -27,6 +27,9 @@
 #include "undostack.h"
 #include <string.h>
 
+// undo can be incremental or direct, from key to current
+//#define UNDO_INCREMENTAL
+
 UndoStack::UndoStack() : List<UndoStackItem>()
 {
        current = 0;
@@ -55,37 +58,30 @@ UndoStackItem *UndoStack::get_current_redo()
 
 UndoStackItem* UndoStack::push()
 {
-// current is only 0 if before first undo
-       if( current )
-               current = insert_after(current);
-       else
-               current = insert_before(first);
-
-// delete future undos if necessary
-       if( current && current->next ) {
-               while( current->next ) remove(last);
-       }
-
 // delete oldest 2 undos if necessary
        if( total() > UNDOLEVELS ) {
-               for( int i=0; i<2; ++i ) {
-                       UndoStackItem *second = first->next;
-                       char *temp_data = 0;
-
-
-                       if( !second->is_key() ) {
-                               temp_data = second->get_data();
-                       }
-                       remove(first);
-
-// Convert new first to key buffer.
-                       if( !second->is_key() ) {
-                               second->set_data(temp_data);
-                       }
-                       delete [] temp_data;
+               UndoStackItem *item = first, *key = item;
+#ifdef UNDO_INCREMENTAL
+               for( int i=2; --i>=0; item=item->next );
+#else
+               for( int i=2; --i>=0; item=item->next )
+                       if( item->is_key() ) key = item;
+#endif
+               char *data = !item->is_key() ? key->get_data() : 0;
+               while( first != item ) {
+                       if( current == first ) current = first->next;
+                       delete first;
+               }
+               if( data ) {
+                       item->set_data(data);
+                       delete [] data;
                }
        }
 
+// current is only 0 if before first undo
+       current = current ? insert_after(current) : insert_before(first);
+// delete future undos if necessary
+       while( current->next ) remove(last);
        return current;
 }
 
@@ -120,9 +116,6 @@ void UndoStack::dump(FILE *fp)
        }
 }
 
-// undo can be incremental or direct, from key to current
-//#define UNDO_INCREMENTAL
-
 class undo_record {
 public:
        int32_t new_ofs;
@@ -257,9 +250,9 @@ UndoHash *UndoHashTable::add(char *txt, int len)
        return hp;
 }
 
-UndoLine::UndoLine(UndoHash *hash)
+UndoLine::UndoLine(UndoHash *hash, char *tp)
 {
-       this->txt = 0;  this->len = 0;
+       this->txt = tp;  this->len = 0;
        this->hash = hash;
        hash->occurs[va] = hash->occurs[vb] = 1;
 }
@@ -280,7 +273,6 @@ int UndoLine::eq(UndoLine *ln)
 
 void UndoVersion::scan_lines(UndoHashTable *hash, char *sp, char *ep)
 {
-       append(new UndoLine(hash->bof));
        for( int line=1; sp<ep; ++line ) {
                char *txt = sp;
                while( sp<ep && *sp++ != '\n' );
@@ -289,7 +281,6 @@ void UndoVersion::scan_lines(UndoHashTable *hash, char *sp, char *ep)
                ++ln->hash->occurs[ver];
                append(ln);
        }
-       append(new UndoLine(hash->eof));
 }
 
 
@@ -334,13 +325,21 @@ void UndoStackItem::set_data(char *data)
                UndoVersion alines(va), blines(vb);
                char *asp = data, *aep = asp + data_size-1;
                char *bsp = prev, *bep = bsp + prev_size-1;
+               alines.append(new UndoLine(hash.bof, asp));
+               blines.append(new UndoLine(hash.bof, bsp));
                alines.scan_lines(&hash, asp, aep);
                blines.scan_lines(&hash, bsp, bep);
-// trim suffix
                int asz = alines.size(), bsz = blines.size();
+// trim matching suffix
                while( asz > 0 && bsz > 0 && alines[asz-1]->eq(blines[bsz-1]) ) {
-                       --asz;  --bsz;
+                       aep = alines[--asz]->txt;  alines.remove_object();
+                       bep = blines[--bsz]->txt;  blines.remove_object();
                }
+// include for matching last item
+               alines.append(new UndoLine(hash.eof, aep));
+               blines.append(new UndoLine(hash.eof, bep));
+               hash.eof->line[va] = asz++;
+               hash.eof->line[vb] = bsz++;
 
                int ai = 0, bi = 0;
                while( ai < asz || bi < bsz ) {
@@ -482,3 +481,58 @@ void* UndoStackItem::get_creator()
        return creator;
 }
 
+void UndoStackItem::save(FILE *fp)
+{
+       fwrite(&key,1,sizeof(key),fp);
+       fwrite(&load_flags,1,sizeof(load_flags),fp);
+       fwrite(&data_size,1,sizeof(data_size),fp);
+       fwrite(data,1,data_size,fp);
+       for( char *bp=session_filename; *bp; ++bp ) fputc(*bp, fp);
+       fputc(0, fp);
+       for( char *bp=description; *bp; ++bp ) fputc(*bp, fp);
+       fputc(0, fp);
+}
+
+void UndoStackItem::load(FILE *fp)
+{
+       fread(&key,1,sizeof(key),fp);
+       fread(&load_flags,1,sizeof(load_flags),fp);
+       fread(&data_size,1,sizeof(data_size),fp);
+       fread(data=new char[data_size],1,data_size,fp);
+       char filename[BCTEXTLEN], descr[BCTEXTLEN];
+       char *bp = filename, *ep = bp+sizeof(filename)-1;
+       for( int ch; bp<ep && (ch=fgetc(fp))>0; ++bp ) *bp = ch;
+       *bp = 0;
+       session_filename = cstrdup(filename);
+       bp = descr;  ep = bp+sizeof(descr)-1;
+       for( int ch; bp<ep && (ch=fgetc(fp))>0; ++bp ) *bp = ch;
+       *bp = 0;
+       description = cstrdup(descr);
+//printf("read undo key=%d,flags=%jx,data_size=%d,data=%p,file=%s,descr=%s\n",
+// key, load_flags, data_size, data, session_filename, description);
+}
+
+void UndoStack::save(FILE *fp)
+{
+       for( UndoStackItem *item=first; item; item=item->next ) {
+               int is_current = item == current ? 1 : 0;
+               fwrite(&is_current,1,sizeof(is_current),fp);
+               item->save(fp);
+//             if( item == current ) break; // stop at current
+       }
+}
+
+void UndoStack::load(FILE *fp)
+{
+       while( last ) delete last;
+       current = 0;
+       UndoStackItem *current_item = 0;
+       int is_current = 0;
+       while( fread(&is_current,1,sizeof(is_current),fp) == sizeof(is_current) ) {
+               UndoStackItem *item = push();
+               item->load(fp);
+               if( is_current ) current_item = item;
+       }
+       if( current_item ) current = current_item;
+}
+