From 70087e16feaeda3bdd8789b209d0f7cdbca75044 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Mon, 11 Jan 2021 13:43:44 +0200 Subject: [PATCH 1/4] Disable dialogue info table sorting --- apps/opencs/view/world/subviews.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 3e72f9a9e6..169bc2e94e 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -75,10 +75,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) new CSVDoc::SubViewFactoryWithCreator); manager.add (CSMWorld::UniversalId::Type_TopicInfos, - new CSVDoc::SubViewFactoryWithCreator); + new CSVDoc::SubViewFactoryWithCreator(false)); manager.add (CSMWorld::UniversalId::Type_JournalInfos, - new CSVDoc::SubViewFactoryWithCreator); + new CSVDoc::SubViewFactoryWithCreator(false)); manager.add (CSMWorld::UniversalId::Type_Pathgrids, new CSVDoc::SubViewFactoryWithCreator); From 16e03c151a783fc9902bce6cde73026c58cb6ddc Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 13 Jan 2021 15:38:29 +0200 Subject: [PATCH 2/4] Implement basic move algorithm, connect it to drag&drop --- apps/opencs/view/world/dragdroputils.cpp | 10 +++- apps/opencs/view/world/dragdroputils.hpp | 3 + apps/opencs/view/world/dragrecordtable.cpp | 7 ++- apps/opencs/view/world/dragrecordtable.hpp | 5 ++ apps/opencs/view/world/table.cpp | 70 ++++++++++++++++++++++ apps/opencs/view/world/table.hpp | 2 + 6 files changed, 95 insertions(+), 2 deletions(-) diff --git a/apps/opencs/view/world/dragdroputils.cpp b/apps/opencs/view/world/dragdroputils.cpp index 808125a601..bb4d972737 100644 --- a/apps/opencs/view/world/dragdroputils.cpp +++ b/apps/opencs/view/world/dragdroputils.cpp @@ -15,7 +15,15 @@ bool CSVWorld::DragDropUtils::canAcceptData(const QDropEvent &event, CSMWorld::C return data != nullptr && data->holdsType(type); } -CSMWorld::UniversalId CSVWorld::DragDropUtils::getAcceptedData(const QDropEvent &event, +bool CSVWorld::DragDropUtils::isInfo(const QDropEvent &event, CSMWorld::ColumnBase::Display type) +{ + const CSMWorld::TableMimeData *data = getTableMimeData(event); + return data != nullptr && ( + data->holdsType(CSMWorld::UniversalId::Type_TopicInfo) || + data->holdsType(CSMWorld::UniversalId::Type_JournalInfo) ); +} + +CSMWorld::UniversalId CSVWorld::DragDropUtils::getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type) { if (canAcceptData(event, type)) diff --git a/apps/opencs/view/world/dragdroputils.hpp b/apps/opencs/view/world/dragdroputils.hpp index d1d780708e..2181e7606b 100644 --- a/apps/opencs/view/world/dragdroputils.hpp +++ b/apps/opencs/view/world/dragdroputils.hpp @@ -20,6 +20,9 @@ namespace CSVWorld bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); ///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type + bool isInfo(const QDropEvent &event, CSMWorld::ColumnBase::Display type); + ///< Info types can be dragged to sort the info table + CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type); ///< Gets the accepted data from the \a event using the \a type ///< \return Type_None if the \a event data doesn't holds the \a type diff --git a/apps/opencs/view/world/dragrecordtable.cpp b/apps/opencs/view/world/dragrecordtable.cpp index f84bf639da..58041af9fc 100644 --- a/apps/opencs/view/world/dragrecordtable.cpp +++ b/apps/opencs/view/world/dragrecordtable.cpp @@ -46,7 +46,8 @@ void CSVWorld::DragRecordTable::dragEnterEvent(QDragEnterEvent *event) void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event) { QModelIndex index = indexAt(event->pos()); - if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index))) + if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index)) || + CSVWorld::DragDropUtils::isInfo(*event, getIndexDisplayType(index)) ) { if (index.flags() & Qt::ItemIsEditable) { @@ -75,6 +76,10 @@ void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event) } } } + else if (CSVWorld::DragDropUtils::isInfo(*event, display) && event->source() == this) + { + emit moveRecordsFromSameTable(event); + } } CSMWorld::ColumnBase::Display CSVWorld::DragRecordTable::getIndexDisplayType(const QModelIndex &index) const diff --git a/apps/opencs/view/world/dragrecordtable.hpp b/apps/opencs/view/world/dragrecordtable.hpp index a6b6756aa0..f6c3fa8909 100644 --- a/apps/opencs/view/world/dragrecordtable.hpp +++ b/apps/opencs/view/world/dragrecordtable.hpp @@ -23,6 +23,8 @@ namespace CSVWorld { class DragRecordTable : public QTableView { + Q_OBJECT + protected: CSMDoc::Document& mDocument; bool mEditLock; @@ -45,6 +47,9 @@ namespace CSVWorld private: CSMWorld::ColumnBase::Display getIndexDisplayType(const QModelIndex &index) const; + + signals: + void moveRecordsFromSameTable(QDropEvent *event); }; } diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index e5f4e36c5b..03d7dbbfab 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -248,6 +249,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, if (isInfoTable) { mProxyModel = new CSMWorld::InfoTableProxyModel(id.getType(), this); + connect (this, &CSVWorld::DragRecordTable::moveRecordsFromSameTable, this, &CSVWorld::Table::moveRecords); } else if (isLtexTable) { @@ -563,6 +565,74 @@ void CSVWorld::Table::moveDownRecord() } } +void CSVWorld::Table::moveRecords(QDropEvent *event) +{ + if (mEditLock || (mModel->getFeatures() & CSMWorld::IdTableBase::Feature_Constant)) + return; + + QModelIndex targedIndex = indexAt(event->pos()); + + QModelIndexList selectedRows = selectionModel()->selectedRows(); + int targetRow = targedIndex.row(); + int baseRow = targedIndex.row() - 1; + int highestDifference = 0; + + for (const auto& thisRowData : selectedRows) + { + if (std::abs(targetRow - thisRowData.row()) > highestDifference) highestDifference = std::abs(targetRow - thisRowData.row()); + if (thisRowData.row() - 1 < baseRow) baseRow = thisRowData.row() - 1; + } + + std::vector newOrder (highestDifference + 1); + + for (long unsigned int i = 0; i < newOrder.size(); ++i) + { + newOrder[i] = i; + } + + if (selectedRows.size() > 1) + { + Log(Debug::Warning) << "Move operation failed: Moving multiple selections isn't implemented."; + return; + } + + for (const auto& thisRowData : selectedRows) + { + /* + Moving algorithm description + a) Remove the (ORIGIN + 1)th list member. + b) Add (ORIGIN+1)th list member with value TARGET + c) If ORIGIN > TARGET,d_INC; ELSE d_DEC + d_INC) increase all members after (and including) the TARGET by one, stop before hitting ORIGINth address + d_DEC) decrease all members after the ORIGIN by one, stop after hitting address TARGET + */ + + int originRow = thisRowData.row(); + //int sourceMappedOriginRow = mProxyModel->mapToSource (mProxyModel->index (originRow, 0)).row(); + + newOrder.erase(newOrder.begin() + originRow - baseRow - 1); + newOrder.emplace(newOrder.begin() + originRow - baseRow - 1, targetRow - baseRow - 1); + + if (originRow > targetRow) + { + for (int i = targetRow - baseRow - 1; i < originRow - baseRow - 1; ++i) + { + ++newOrder[i]; + } + } + else + { + for (int i = originRow - baseRow; i <= targetRow - baseRow - 1; ++i) + { + --newOrder[i]; + } + } + + } + mDocument.getUndoStack().push (new CSMWorld::ReorderRowsCommand ( + dynamic_cast (*mModel), baseRow + 1, newOrder)); +} + void CSVWorld::Table::editCell() { emit editRequest(mEditIdAction->getCurrentId(), ""); diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 61dd57c061..9c4b9b5e5a 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -141,6 +141,8 @@ namespace CSVWorld void moveDownRecord(); + void moveRecords(QDropEvent *event); + void viewRecord(); void previewRecord(); From f2fc02cdff69cabafa00a33de95bd942511d2eb7 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 13 Jan 2021 15:55:16 +0200 Subject: [PATCH 3/4] Support filtered tables (mapToSource for indexes) --- apps/opencs/view/world/table.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 03d7dbbfab..c676a5ecc0 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -573,14 +573,17 @@ void CSVWorld::Table::moveRecords(QDropEvent *event) QModelIndex targedIndex = indexAt(event->pos()); QModelIndexList selectedRows = selectionModel()->selectedRows(); - int targetRow = targedIndex.row(); - int baseRow = targedIndex.row() - 1; + int targetRowRaw = targedIndex.row(); + int targetRow = mProxyModel->mapToSource (mProxyModel->index (targetRowRaw, 0)).row(); + int baseRowRaw = targedIndex.row() - 1; + int baseRow = mProxyModel->mapToSource (mProxyModel->index (baseRowRaw, 0)).row(); int highestDifference = 0; for (const auto& thisRowData : selectedRows) { - if (std::abs(targetRow - thisRowData.row()) > highestDifference) highestDifference = std::abs(targetRow - thisRowData.row()); - if (thisRowData.row() - 1 < baseRow) baseRow = thisRowData.row() - 1; + int thisRow = mProxyModel->mapToSource (mProxyModel->index (thisRowData.row(), 0)).row(); + if (std::abs(targetRow - thisRow) > highestDifference) highestDifference = std::abs(targetRow - thisRow); + if (thisRow - 1 < baseRow) baseRow = thisRow - 1; } std::vector newOrder (highestDifference + 1); @@ -607,8 +610,8 @@ void CSVWorld::Table::moveRecords(QDropEvent *event) d_DEC) decrease all members after the ORIGIN by one, stop after hitting address TARGET */ - int originRow = thisRowData.row(); - //int sourceMappedOriginRow = mProxyModel->mapToSource (mProxyModel->index (originRow, 0)).row(); + int originRowRaw = thisRowData.row(); + int originRow = mProxyModel->mapToSource (mProxyModel->index (originRowRaw, 0)).row(); newOrder.erase(newOrder.begin() + originRow - baseRow - 1); newOrder.emplace(newOrder.begin() + originRow - baseRow - 1, targetRow - baseRow - 1); From 5740258d3b006977a5a8fa78f71b4cbb5d11f837 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 13 Jan 2021 16:23:59 +0200 Subject: [PATCH 4/4] Add changelog entry --- CHANGELOG.md | 1 + CHANGELOG_PR.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 943dcbe898..b628a847a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ Bug #4055: Local scripts don't inherit variables from their base record Bug #4083: Door animation freezes when colliding with actors Bug #4247: Cannot walk up stairs in Ebonheart docks + Bug #4357: OpenMW-CS: TopicInfos index sorting and rearranging isn't fully functional Bug #4363: Editor: Defect in Clone Function for Dialogue Info records Bug #4447: Actor collision capsule shape allows looking through some walls Bug #4465: Collision shape overlapping causes twitching diff --git a/CHANGELOG_PR.md b/CHANGELOG_PR.md index f70fbad575..c7abb6fec2 100644 --- a/CHANGELOG_PR.md +++ b/CHANGELOG_PR.md @@ -35,6 +35,7 @@ Bug Fixes: Editor Bug Fixes: - Deleted and moved objects within a cell are now saved properly (#832) +- Disabled record sorting in Topic and Journal Info tables, implemented drag-move for records (#4357) - Topic and Journal Info records can now be cloned with a different parent Topic/Journal Id (#4363) - Verifier no longer checks for alleged 'race' entries in clothing body parts (#5400) - Loading mods now keeps the master index (#5675)