allow editing multiple items at once

Values from the editor are copied to all applicable selected nodes
This commit is contained in:
Jussi Kuokkanen 2023-10-20 10:47:24 +03:00
parent cc7ae7a086
commit 49b28238ce
2 changed files with 78 additions and 3 deletions

View File

@ -21,6 +21,8 @@ DeviceTreeView::DeviceTreeView(QWidget *parent) : QTreeView(parent) {
setEditTriggers(SelectedClicked | EditKeyPressed);
setContextMenuPolicy(Qt::DefaultContextMenu);
setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(this, &QTreeView::collapsed, [=](auto &index) {
// Traverse model, recursively suspend everything
suspendChildren(index);
@ -72,3 +74,68 @@ void DeviceTreeView::resumeChildren(const QModelIndex &index) {
};
Utils::traverseModel(cb, model(), index);
}
bool assignableInfoEquals(AssignableInfo a, AssignableInfo b) {
if (a.index() != b.index())
return false;
if (std::holds_alternative<RangeInfo>(a)) {
auto rinfoA = std::get<RangeInfo>(a);
auto rinfoB = std::get<RangeInfo>(b);
if (rinfoA.index() != rinfoB.index())
return false;
if (std::holds_alternative<Range<int>>(rinfoA)) {
auto rangeA = std::get<Range<int>>(rinfoA);
auto rangeB = std::get<Range<int>>(rinfoB);
return rangeA.max == rangeB.max && rangeA.min == rangeB.min;
}
if (std::holds_alternative<Range<double>>(rinfoA)) {
auto rangeA = std::get<Range<double>>(rinfoA);
auto rangeB = std::get<Range<double>>(rinfoB);
return qFuzzyCompare(rangeA.max, rangeB.max) &&
qFuzzyCompare(rangeA.min, rangeB.min);
}
}
if (std::holds_alternative<EnumerationVec>(a)) {
auto enumsA = std::get<EnumerationVec>(a);
auto enumsB = std::get<EnumerationVec>(b);
if (enumsA.size() != enumsB.size())
return false;
for (int i = 0; i < enumsA.size(); i++) {
if (enumsA[i].key != enumsB[i].key || enumsA[i].name != enumsB[i].name)
return false;
}
return true;
}
return false;
}
bool indexApplicableForIndex(QModelIndex &orig, QModelIndex &other) {
if (orig.column() != other.column())
return false;
auto origAssInfoV = orig.data(DeviceModel::AssignableRole);
auto otherAssInfoV = other.data(DeviceModel::AssignableRole);
if (!origAssInfoV.isValid() || !otherAssInfoV.isValid())
return false;
auto origAssData = qvariant_cast<AssignableItemData>(origAssInfoV);
auto otherAssData = qvariant_cast<AssignableItemData>(otherAssInfoV);
return assignableInfoEquals(origAssData.assignableInfo(), otherAssData.assignableInfo());
}
void DeviceTreeView::commitData(QWidget *w) {
for (auto &index : m_editSelection) {
// See if node is applicable to being set the same value
// as the node the editor was opened for
if (indexApplicableForIndex(m_editedIndex, index))
m_delegate->setModelData(w, model(), index);
}
QTreeView::commitData(w);
}

View File

@ -21,9 +21,14 @@ public:
// TODO: this can be handled in the delegate with QAbstractItemDelegate::editorEvent
boost::signals2::signal<void(QModelIndex &)> functionEditorRequested;
protected:
/* Workaround for the retarded behavior of waiting for a double click,
you can't even disable it! */
bool edit(const QModelIndex &index, QAbstractItemView::EditTrigger trigger, QEvent *event) {
bool edit(const QModelIndex &index, QAbstractItemView::EditTrigger trigger,
QEvent *event) override {
// The editor value is applied to all applicable indices from these
m_editSelection = selectedIndexes();
// Used as the baseline
m_editedIndex = index;
// Don't wait for double click
return QTreeView::edit(index,
trigger == QAbstractItemView::SelectedClicked
? QAbstractItemView::AllEditTriggers
@ -32,11 +37,14 @@ protected:
}
// TODO: allow to start editing with the keyboard
EditTriggers editTriggers() { return QAbstractItemView::AllEditTriggers; }
void commitData(QWidget *) override;
private:
// Suspend/resume readable updates
void suspendChildren(const QModelIndex &);
void resumeChildren(const QModelIndex &);
// DeviceModel &m_deviceModel;
QModelIndexList m_editSelection;
QModelIndex m_editedIndex;
DeviceModelDelegate *m_delegate;
};