Added the ability to merge changes. That means undo/redo now have a
handier granularity. ReplaceChange will now try to merge with the next ReplaceChange if they are adjacent. Fixed compilation with tracing enabled. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6776 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -45,6 +45,7 @@ class DataChange {
|
|||||||
|
|
||||||
virtual void Apply(off_t offset, uint8 *buffer, size_t size) = 0;
|
virtual void Apply(off_t offset, uint8 *buffer, size_t size) = 0;
|
||||||
virtual void Revert(off_t offset, uint8 *buffer, size_t size) = 0;
|
virtual void Revert(off_t offset, uint8 *buffer, size_t size) = 0;
|
||||||
|
virtual bool Merge(DataChange *change);
|
||||||
virtual void GetRange(off_t fileSize, off_t &_offset, off_t &_size) = 0;
|
virtual void GetRange(off_t fileSize, off_t &_offset, off_t &_size) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,6 +56,7 @@ class ReplaceChange : public DataChange {
|
|||||||
|
|
||||||
virtual void Apply(off_t offset, uint8 *buffer, size_t size);
|
virtual void Apply(off_t offset, uint8 *buffer, size_t size);
|
||||||
virtual void Revert(off_t offset, uint8 *buffer, size_t size);
|
virtual void Revert(off_t offset, uint8 *buffer, size_t size);
|
||||||
|
virtual bool Merge(DataChange *change);
|
||||||
virtual void GetRange(off_t fileSize, off_t &_offset, off_t &_size);
|
virtual void GetRange(off_t fileSize, off_t &_offset, off_t &_size);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -75,7 +77,7 @@ class ReplaceChange : public DataChange {
|
|||||||
|
|
||||||
#define DUMPED_BLOCK_SIZE 16
|
#define DUMPED_BLOCK_SIZE 16
|
||||||
|
|
||||||
void
|
static void
|
||||||
dump_block(const uint8 *buffer, int size, const char *prefix)
|
dump_block(const uint8 *buffer, int size, const char *prefix)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < size;) {
|
for (int i = 0; i < size;) {
|
||||||
@@ -159,6 +161,13 @@ DataChange::~DataChange()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
DataChange::Merge(DataChange *change)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
@@ -219,10 +228,10 @@ ReplaceChange::Apply(off_t bufferOffset, uint8 *buffer, size_t bufferSize)
|
|||||||
if (size == 0)
|
if (size == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
#if TRACE_DATA_EDITOR
|
#ifdef TRACE_DATA_EDITOR
|
||||||
printf("Apply %p (buffer offset = %Ld):\n", this, bufferOffset);
|
printf("Apply %p (buffer offset = %Ld):\n", this, bufferOffset);
|
||||||
dumpBlock(buffer + offset - bufferOffset, size, "old:");
|
dump_block(buffer + offset - bufferOffset, size, "old:");
|
||||||
dumpBlock(fNewData + dataOffset, size, "new:");
|
dump_block(fNewData + dataOffset, size, "new:");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// now we can safely exchange the buffer!
|
// now we can safely exchange the buffer!
|
||||||
@@ -248,8 +257,8 @@ ReplaceChange::Revert(off_t bufferOffset, uint8 *buffer, size_t bufferSize)
|
|||||||
|
|
||||||
#ifdef TRACE_DATA_EDITOR
|
#ifdef TRACE_DATA_EDITOR
|
||||||
printf("Revert %p (buffer offset = %Ld):\n", this, bufferOffset);
|
printf("Revert %p (buffer offset = %Ld):\n", this, bufferOffset);
|
||||||
dumpBlock(buffer + offset - bufferOffset, size, "old:");
|
dump_block(buffer + offset - bufferOffset, size, "old:");
|
||||||
dumpBlock(fOldData + dataOffset, size, "new:");
|
dump_block(fOldData + dataOffset, size, "new:");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// now we can safely revert the buffer!
|
// now we can safely revert the buffer!
|
||||||
@@ -257,6 +266,60 @@ ReplaceChange::Revert(off_t bufferOffset, uint8 *buffer, size_t bufferSize)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
ReplaceChange::Merge(DataChange *_change)
|
||||||
|
{
|
||||||
|
ReplaceChange *change = dynamic_cast<ReplaceChange *>(_change);
|
||||||
|
if (change == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// are the changes adjacent?
|
||||||
|
|
||||||
|
if (change->fOffset + change->fSize != fOffset
|
||||||
|
&& fOffset + fSize != change->fOffset)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// okay, we can try to merge the two changes
|
||||||
|
|
||||||
|
uint8 *newData = fOffset < change->fOffset ? fNewData : change->fNewData;
|
||||||
|
size_t size = fSize + change->fSize;
|
||||||
|
|
||||||
|
if ((newData = (uint8 *)realloc(newData, size)) == NULL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint8 *oldData = fOffset < change->fOffset ? fOldData : change->fOldData;
|
||||||
|
if ((oldData = (uint8 *)realloc(oldData, size)) == NULL) {
|
||||||
|
fNewData = (uint8 *)realloc(newData, fSize);
|
||||||
|
// if this fails, we can't do anything about it
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fOffset < change->fOffset) {
|
||||||
|
memcpy(newData + fSize, change->fNewData, change->fSize);
|
||||||
|
memcpy(oldData + fSize, change->fOldData, change->fSize);
|
||||||
|
} else {
|
||||||
|
memcpy(newData + change->fSize, fNewData, fSize);
|
||||||
|
memcpy(oldData + change->fSize, fOldData, fSize);
|
||||||
|
change->fNewData = fNewData;
|
||||||
|
change->fOldData = fOldData;
|
||||||
|
// transfer ownership, so that they will be deleted with the change
|
||||||
|
fOffset = change->fOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
fNewData = newData;
|
||||||
|
fOldData = oldData;
|
||||||
|
fSize = size;
|
||||||
|
|
||||||
|
#ifdef TRACE_DATA_EDITOR
|
||||||
|
printf("Merge %p (offset = %Ld, size = %lu):\n", this, fOffset, fSize);
|
||||||
|
dump_block(fOldData, fSize, "old:");
|
||||||
|
dump_block(fNewData, fSize, "new:");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ReplaceChange::GetRange(off_t /*fileSize*/, off_t &_offset, off_t &_size)
|
ReplaceChange::GetRange(off_t /*fileSize*/, off_t &_offset, off_t &_size)
|
||||||
{
|
{
|
||||||
@@ -405,17 +468,18 @@ DataEditor::AddChange(DataChange *change)
|
|||||||
// update state observers
|
// update state observers
|
||||||
|
|
||||||
RemoveRedos();
|
RemoveRedos();
|
||||||
|
change->Apply(fRealViewOffset, fView, fRealViewSize);
|
||||||
|
|
||||||
fChanges.AddItem(change);
|
SendNotices(change);
|
||||||
fLastChange = change;
|
// update observers
|
||||||
fChangesFromSaved++;
|
|
||||||
|
|
||||||
fLastChange->Apply(fRealViewOffset, fView, fRealViewSize);
|
// try to join changes
|
||||||
// ToDo: try to join changes
|
if (fLastChange == NULL || !fLastChange->Merge(change)) {
|
||||||
|
fChanges.AddItem(change);
|
||||||
// update observers
|
fLastChange = change;
|
||||||
|
fChangesFromSaved++;
|
||||||
SendNotices(fLastChange);
|
} else
|
||||||
|
delete change;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user