Skip to content

Commit

Permalink
Move all actual row mutation logic to the RowRemovalOperation dtor.
Browse files Browse the repository at this point in the history
This stops various views of the model from shitting all over the data while the removal is under way.
  • Loading branch information
JoshDreamland committed Dec 7, 2019
1 parent cdc0689 commit 5a89856
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 28 deletions.
71 changes: 49 additions & 22 deletions Models/RepeatedProtoModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,36 +100,63 @@ Qt::ItemFlags RepeatedProtoModel::flags(const QModelIndex &index) const {
return QAbstractItemModel::flags(index);
}

void RepeatedProtoModel::RowRemovalOperation::RemoveRow(int row) { return RemoveRows(row, 1); }
void RepeatedProtoModel::RowRemovalOperation::RemoveRow(int row) {
rows.insert(row);
}
void RepeatedProtoModel::RowRemovalOperation::RemoveRows(int row, int count) {
auto list = model->GetMutableModelList();
model->beginRemoveRows(QModelIndex(), row, row + count - 1);
if (left < right) {
while (right < row) {
field.SwapElements(left, right);
list[left].swap(list[right]);
left++; right++;
}
} else {
left = row;
}
right = row + count;
model->endRemoveRows();
for (int i = row; i < row + count; ++i) rows.insert(i);
}

RepeatedProtoModel::RowRemovalOperation::~RowRemovalOperation() {
auto &list = model->GetMutableModelList();
qDebug() << left << "," << right << "," << field.size();
if (left < right) {
qDebug() << "swap final " << field.size() - right << " rows backward";
while (right < field.size()) {
std::cout << "Remove " << rows.size() << " rows" << std::endl;
if (rows.empty()) return;

// Compute ranges for our deleted rows.
struct Range {
int first, last;
Range(): first(), last() {}
Range(int f, int l): first(f), last(l) {}
int size() { return last - first + 1; }
};
std::vector<Range> ranges;
for (int row : rows) {
if (ranges.empty() || row != ranges.back().last + 1) {
ranges.emplace_back(row, row);
} else {
ranges.back().last = row;
}
}

// Broadcast range removal before the model can fuck anything up.
// Do this from back to front to minimize the amount of shit it fucks up.
for (auto range = ranges.rbegin(); range != ranges.rend(); ++range) {
std::cout << "Remove range " << range->first << " - " << range->last << std::endl;
model->beginRemoveRows(QModelIndex(), range->first, range->last);
}

// Basic dense range removal. Move "deleted" rows to the end of the array.
int left = 0, right = 0;
for (auto range : ranges) {
while (right < range.first) {
field.SwapElements(left, right);
list[left].swap(list[right]);
left++; right++;
}

qDebug() << "remove final " << field.size() - left << " rows";
while (left < field.size()) field.RemoveLast();
list.resize(left);
right = range.last + 1;
}
while (right < field.size()) {
field.SwapElements(left, right);
list[left].swap(list[right]);
left++; right++;
}

// Send the endRemoveRows operations in the reverse order, removing the
// correct number of rows incrementally, or else various components in Qt
// will bitch, piss, moan, wail, whine, and cry. Actually, they will anyway.
for (Range range : ranges) {
list.resize(list.size() - range.size());
for (int j = range.first; j <= range.last; ++j) field.RemoveLast();
model->endRemoveRows();
}
}
14 changes: 8 additions & 6 deletions Models/RepeatedProtoModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
#define REPEATEDPROTOMODEL_H

#include <QAbstractItemModel>
#include <QDebug>
#include <QSharedPointer>

#include <google/protobuf/message.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/reflection.h>

#include <optional>
#include <QDebug>
#include <set>

using namespace google::protobuf;
using CppType = FieldDescriptor::CppType;
Expand Down Expand Up @@ -41,14 +42,15 @@ class RepeatedProtoModel : public QAbstractItemModel {
Qt::ItemFlags flags(const QModelIndex &index) const override;

class RowRemovalOperation {
int left = 0, right = 0;
MutableRepeatedFieldRef<Message> field;
RepeatedProtoModelPtr model;
RepeatedProtoModelPtr model;
MutableRepeatedFieldRef<Message> field;
std::set<int> rows;

public:
RowRemovalOperation(RepeatedProtoModelPtr m):
model(m),
field(m->protobuf->GetReflection()
->GetMutableRepeatedFieldRef<Message>(m->protobuf, m->field)),
model(m) {}
->GetMutableRepeatedFieldRef<Message>(m->protobuf, m->field)) {}
void RemoveRow(int row);
void RemoveRows(int row, int count);
~RowRemovalOperation();
Expand Down

0 comments on commit 5a89856

Please sign in to comment.