diff --git a/CHANGELOG.md b/CHANGELOG.md index 64528e5c2e..bc47aaf00f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Bug #4083: Door animation freezes when colliding with actors Bug #4201: Projectile-projectile collision 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 944b260442..cfe709e97c 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) 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/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); diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index e5f4e36c5b..c676a5ecc0 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,77 @@ 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 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) + { + 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); + + 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 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); + + 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();