Implemented Save() functionality. ApplyChanges() can now create the editor

version of the file from any state.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6763 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-02-26 16:41:09 +00:00
parent c0ced84a62
commit a4ce63bfc4
2 changed files with 136 additions and 7 deletions
+134 -7
View File
@@ -59,6 +59,21 @@ class ReplaceChange : public DataChange {
//--------------------- //---------------------
static int
CompareOffsets(const off_t *a, const off_t *b)
{
if (*a < *b)
return -1;
else if (*a > *b)
return 1;
return 0;
}
// #pragma mark -
StateWatcher::StateWatcher(DataEditor &editor) StateWatcher::StateWatcher(DataEditor &editor)
: :
fEditor(editor) fEditor(editor)
@@ -297,6 +312,7 @@ DataEditor::SetTo(BEntry &entry, const char *attribute)
} }
fLastChange = fFirstChange = NULL; fLastChange = fFirstChange = NULL;
fChangesFromSaved = 0;
fView = NULL; fView = NULL;
fRealViewOffset = 0; fRealViewOffset = 0;
fViewOffset = 0; fViewOffset = 0;
@@ -327,6 +343,7 @@ DataEditor::AddChange(DataChange *change)
fChanges.AddItem(change); fChanges.AddItem(change);
fLastChange = change; fLastChange = change;
fChangesFromSaved++;
fLastChange->Apply(fRealViewOffset, fView, fRealViewSize); fLastChange->Apply(fRealViewOffset, fView, fRealViewSize);
// ToDo: try to join changes // ToDo: try to join changes
@@ -390,11 +407,25 @@ DataEditor::ApplyChanges()
if (fLastChange == NULL) if (fLastChange == NULL)
return; return;
int32 count = fChanges.IndexOf(fLastChange) + 1; // ToDo: we need to support ascending *and* descending the list of changes
for (int32 i = 0; i < count; i++) { int32 firstIndex = fFirstChange != NULL ? fChanges.IndexOf(fFirstChange) + 1 : 0;
DataChange *change = fChanges.ItemAt(i); int32 lastIndex = fChanges.IndexOf(fLastChange);
change->Apply(fRealViewOffset, fView, fRealViewSize);
if (fChangesFromSaved >= 0) {
// ascend changes
for (int32 i = firstIndex; i <= lastIndex; i++) {
DataChange *change = fChanges.ItemAt(i);
change->Apply(fRealViewOffset, fView, fRealViewSize);
}
} else {
// descend changes
for (int32 i = firstIndex; i >= lastIndex; i--) {
DataChange *change = fChanges.ItemAt(i);
change->Revert(fRealViewOffset, fView, fRealViewSize);
}
} }
} }
@@ -402,9 +433,91 @@ DataEditor::ApplyChanges()
status_t status_t
DataEditor::Save() DataEditor::Save()
{ {
// collect ranges of data we need to write BAutolock locker(this);
if (!IsModified())
return B_OK;
StateWatcher watcher(*this);
// Do we need to ascend or descend the list of changes?
int32 firstIndex = fFirstChange != NULL ? fChanges.IndexOf(fFirstChange) + 1 : 0;
int32 lastIndex = fChanges.IndexOf(fLastChange);
if (fChangesFromSaved < 0 && firstIndex != lastIndex) {
// swap indices
ASSERT(firstIndex > lastIndex);
int32 temp = firstIndex - 1;
firstIndex = lastIndex;
lastIndex = temp;
}
// Collect ranges of data we need to write.
// ToDo: This is a very simple implementation and could be drastically
// improved by having items that save ranges, not just offsets. If Insert()
// and Remove() are going to be implemented, it should be improved that
// way to reduce the memory footprint to something acceptable.
BObjectList<off_t> list;
for (int32 i = firstIndex; i <= lastIndex; i++) {
DataChange *change = fChanges.ItemAt(i);
off_t offset, size;
change->GetRange(FileSize(), offset, size);
offset -= offset % BlockSize();
while (size > 0) {
list.BinaryInsertCopyUnique(offset, CompareOffsets);
offset += BlockSize();
size -= BlockSize();
}
}
// read in data and apply changes, write it back to disk // read in data and apply changes, write it back to disk
off_t oldOffset = fViewOffset;
for (int32 i = 0; i < list.CountItems(); i++) {
off_t offset = *list.ItemAt(i);
// load the data into our view
SetViewOffset(offset, false);
if (fNeedsUpdate) {
status_t status = Update();
if (status < B_OK)
return status;
}
// save back to disk
// don't try to change the file size
size_t size = fRealViewSize;
if (fRealViewOffset + fRealViewSize > fSize)
size = fSize - fRealViewOffset;
ssize_t bytesWritten;
if (IsAttribute())
bytesWritten = fFile.WriteAttr(fAttribute, fType, fRealViewOffset, fView, fRealViewSize);
else
bytesWritten = fFile.WriteAt(fRealViewOffset, fView, fRealViewSize);
if (bytesWritten < B_OK)
return bytesWritten;
}
// update state
SetViewOffset(oldOffset, false);
if (fNeedsUpdate)
Update();
fChangesFromSaved = 0;
fFirstChange = fLastChange;
return B_OK;
} }
@@ -443,6 +556,7 @@ DataEditor::Undo()
DataChange *undoChange = fLastChange; DataChange *undoChange = fLastChange;
int32 index = fChanges.IndexOf(undoChange); int32 index = fChanges.IndexOf(undoChange);
fChangesFromSaved--;
undoChange->Revert(fRealViewOffset, fView, fRealViewSize); undoChange->Revert(fRealViewOffset, fView, fRealViewSize);
if (index > 0) if (index > 0)
@@ -470,6 +584,7 @@ DataEditor::Redo()
int32 index = fChanges.IndexOf(fLastChange); int32 index = fChanges.IndexOf(fLastChange);
fLastChange = fChanges.ItemAt(index + 1); fLastChange = fChanges.ItemAt(index + 1);
fChangesFromSaved++;
fLastChange->Apply(fRealViewOffset, fView, fRealViewSize); fLastChange->Apply(fRealViewOffset, fView, fRealViewSize);
@@ -503,7 +618,7 @@ DataEditor::SetFileSize(off_t size)
status_t status_t
DataEditor::SetViewOffset(off_t offset) DataEditor::SetViewOffset(off_t offset, bool sendNotices)
{ {
if (fView == NULL) { if (fView == NULL) {
status_t status = SetViewSize(fViewSize); status_t status = SetViewSize(fViewSize);
@@ -514,15 +629,27 @@ DataEditor::SetViewOffset(off_t offset)
if (offset < 0 || offset > fSize) if (offset < 0 || offset > fSize)
return B_BAD_VALUE; return B_BAD_VALUE;
if (offset == fViewOffset)
return B_OK;
fRealViewOffset = (offset / fBlockSize) * fBlockSize; fRealViewOffset = (offset / fBlockSize) * fBlockSize;
fViewOffset = offset; fViewOffset = offset;
fNeedsUpdate = true; fNeedsUpdate = true;
SendNotices(kMsgDataEditorOffsetChange); if (sendNotices)
SendNotices(kMsgDataEditorOffsetChange);
return B_OK; return B_OK;
} }
status_t
DataEditor::SetViewOffset(off_t offset)
{
return SetViewOffset(offset, true);
}
status_t status_t
DataEditor::SetViewSize(size_t size) DataEditor::SetViewSize(size_t size)
{ {
+2
View File
@@ -78,6 +78,7 @@ class DataEditor : public BLocker {
private: private:
friend class StateWatcher; friend class StateWatcher;
status_t SetViewOffset(off_t offset, bool sendNotices);
void SendNotices(uint32 what, BMessage *message = NULL); void SendNotices(uint32 what, BMessage *message = NULL);
void SendNotices(DataChange *change); void SendNotices(DataChange *change);
status_t Update(); status_t Update();
@@ -97,6 +98,7 @@ class DataEditor : public BLocker {
BObjectList<DataChange> fChanges; BObjectList<DataChange> fChanges;
DataChange *fFirstChange; DataChange *fFirstChange;
DataChange *fLastChange; DataChange *fLastChange;
int32 fChangesFromSaved;
uint8 *fView; uint8 *fView;
off_t fRealViewOffset, fViewOffset; off_t fRealViewOffset, fViewOffset;