diff --git a/CHANGELOG.md b/CHANGELOG.md index ff4996d05c..3d760f1b79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Bug #6133: Cannot reliably sneak or steal in the sight of the NPCs siding with player Bug #6143: Capturing a screenshot makes engine to be a temporary unresponsive Bug #6165: Paralyzed player character can pickup items when the inventory is open + Feature #2554: Modifying an object triggers the instances table to scroll to the corresponding record Feature #2780: A way to see current OpenMW version in the console Feature #5489: MCP: Telekinesis fix for activators Feature #5996: Support Lua scripts in OpenMW diff --git a/apps/opencs/model/world/idtable.cpp b/apps/opencs/model/world/idtable.cpp index 30fe6f639a..ee08158e3f 100644 --- a/apps/opencs/model/world/idtable.cpp +++ b/apps/opencs/model/world/idtable.cpp @@ -191,7 +191,7 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, const std::string& destination, CSMWorld::UniversalId::Type type) { - int index = mIdCollection->getAppendIndex (destination); + int index = mIdCollection->getAppendIndex (destination, type); beginInsertRows (QModelIndex(), index, index); mIdCollection->cloneRecord(origin, destination, type); diff --git a/apps/opencs/model/world/idtableproxymodel.cpp b/apps/opencs/model/world/idtableproxymodel.cpp index 3e24f8d12e..9d9dd7db3d 100644 --- a/apps/opencs/model/world/idtableproxymodel.cpp +++ b/apps/opencs/model/world/idtableproxymodel.cpp @@ -121,8 +121,11 @@ QString CSMWorld::IdTableProxyModel::getRecordId(int sourceRow) const void CSMWorld::IdTableProxyModel::refreshFilter() { - updateColumnMap(); - invalidateFilter(); + if (mFilter) + { + updateColumnMap(); + invalidateFilter(); + } } void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end) diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index c676a5ecc0..cbfc70e367 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -239,7 +240,7 @@ void CSVWorld::Table::mouseDoubleClickEvent (QMouseEvent *event) CSVWorld::Table::Table (const CSMWorld::UniversalId& id, bool createAndDelete, bool sorting, CSMDoc::Document& document) : DragRecordTable(document), mCreateAction (nullptr), mCloneAction(nullptr), mTouchAction(nullptr), - mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false) + mRecordStatusDisplay (0), mJumpToAddedRecord(false), mUnselectAfterJump(false), mAutoJump (false) { mModel = &dynamic_cast (*mDocument.getData().getTableModel (id)); @@ -405,7 +406,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, /// \note This signal could instead be connected to a slot that filters out changes not affecting /// the records status column (for permanence reasons) connect (mProxyModel, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), - this, SLOT (tableSizeUpdate())); + this, SLOT (dataChangedEvent(const QModelIndex&, const QModelIndex&))); connect (selectionModel(), SIGNAL (selectionChanged (const QItemSelection&, const QItemSelection&)), this, SLOT (selectionSizeUpdate ())); @@ -801,7 +802,7 @@ void CSVWorld::Table::tableSizeUpdate() case CSMWorld::RecordBase::State_BaseOnly: ++size; break; case CSMWorld::RecordBase::State_Modified: ++size; ++modified; break; case CSMWorld::RecordBase::State_ModifiedOnly: ++size; ++modified; break; - case CSMWorld::RecordBase:: State_Deleted: ++deleted; ++modified; break; + case CSMWorld::RecordBase::State_Deleted: ++deleted; ++modified; break; } } } @@ -874,15 +875,47 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const return idToDrag; } +// parent, start and end depend on the model sending the signal, in this case mProxyModel +// +// If, for example, mModel was used instead, then scrolTo() should use the index +// mProxyModel->mapFromSource(mModel->index(end, 0)) void CSVWorld::Table::rowAdded(const std::string &id) { tableSizeUpdate(); if(mJumpToAddedRecord) { int idColumn = mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id); - selectRow(mProxyModel->getModelIndex(id, idColumn).row()); + int end = mProxyModel->getModelIndex(id, idColumn).row(); + selectRow(end); + + // without this delay the scroll works but goes to top for add/clone + QMetaObject::invokeMethod(this, "queuedScrollTo", Qt::QueuedConnection, Q_ARG(int, end)); if(mUnselectAfterJump) clearSelection(); } } + +void CSVWorld::Table::queuedScrollTo(int row) +{ + scrollTo(mProxyModel->index(row, 0), QAbstractItemView::PositionAtCenter); +} + +void CSVWorld::Table::dataChangedEvent(const QModelIndex &topLeft, const QModelIndex &bottomRight) +{ + tableSizeUpdate(); + + if (mAutoJump) + { + selectRow(bottomRight.row()); + scrollTo(bottomRight, QAbstractItemView::PositionAtCenter); + } +} + +void CSVWorld::Table::jumpAfterModChanged(int state) +{ + if(state == Qt::Checked) + mAutoJump = true; + else + mAutoJump = false; +} diff --git a/apps/opencs/view/world/table.hpp b/apps/opencs/view/world/table.hpp index 9c4b9b5e5a..a7c932a383 100644 --- a/apps/opencs/view/world/table.hpp +++ b/apps/opencs/view/world/table.hpp @@ -74,6 +74,7 @@ namespace CSVWorld std::map mDoubleClickActions; bool mJumpToAddedRecord; bool mUnselectAfterJump; + bool mAutoJump; private: @@ -164,6 +165,12 @@ namespace CSVWorld void recordFilterChanged (std::shared_ptr filter); void rowAdded(const std::string &id); + + void dataChangedEvent(const QModelIndex &topLeft, const QModelIndex &bottomRight); + + void jumpAfterModChanged(int state); + + void queuedScrollTo(int state); }; } diff --git a/apps/opencs/view/world/tablesubview.cpp b/apps/opencs/view/world/tablesubview.cpp index 5413f87a6e..6b4f12738e 100644 --- a/apps/opencs/view/world/tablesubview.cpp +++ b/apps/opencs/view/world/tablesubview.cpp @@ -1,5 +1,8 @@ #include "tablesubview.hpp" +#include +#include +#include #include #include #include @@ -18,7 +21,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting) -: SubView (id) +: SubView (id), mShowOptions(false), mOptions(0) { QVBoxLayout *layout = new QVBoxLayout; @@ -30,7 +33,37 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D mFilterBox = new CSVFilter::FilterBox (document.getData(), this); - layout->insertWidget (0, mFilterBox); + QHBoxLayout *hLayout = new QHBoxLayout; + hLayout->insertWidget(0,mFilterBox); + + mOptions = new QWidget; + + QHBoxLayout *optHLayout = new QHBoxLayout; + QCheckBox *autoJump = new QCheckBox("Auto Jump"); + autoJump->setToolTip ("Whether to jump to the modified record." + "\nCan be useful in finding the moved or modified" + "\nobject instance while 3D editing."); + autoJump->setCheckState(Qt::Unchecked); + connect(autoJump, SIGNAL (stateChanged(int)), mTable, SLOT (jumpAfterModChanged(int))); + optHLayout->insertWidget(0, autoJump); + optHLayout->setContentsMargins (QMargins (0, 3, 0, 0)); + mOptions->setLayout(optHLayout); + mOptions->resize(mOptions->width(), mFilterBox->height()); + mOptions->hide(); + + QPushButton *opt = new QPushButton (); + opt->setIcon (QIcon (":startup/configure")); + opt->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); + opt->setToolTip ("Open additional options for this subview."); + connect (opt, SIGNAL (clicked()), this, SLOT (toggleOptions())); + + QVBoxLayout *buttonLayout = new QVBoxLayout; // work around margin issues + buttonLayout->setContentsMargins (QMargins (0/*left*/, 3/*top*/, 3/*right*/, 0/*bottom*/)); + buttonLayout->insertWidget(0, opt, 0, Qt::AlignVCenter|Qt::AlignRight); + hLayout->insertWidget(1, mOptions); + hLayout->insertLayout(2, buttonLayout); + + layout->insertLayout (0, hLayout); CSVDoc::SizeHintWidget *widget = new CSVDoc::SizeHintWidget; @@ -166,6 +199,20 @@ bool CSVWorld::TableSubView::eventFilter (QObject* object, QEvent* event) return false; } +void CSVWorld::TableSubView::toggleOptions() +{ + if (mShowOptions) + { + mShowOptions = false; + mOptions->hide(); + } + else + { + mShowOptions = true; + mOptions->show(); + } +} + void CSVWorld::TableSubView::requestFocus (const std::string& id) { mTable->requestFocus(id); diff --git a/apps/opencs/view/world/tablesubview.hpp b/apps/opencs/view/world/tablesubview.hpp index 337d2c7621..d89f71e8a4 100644 --- a/apps/opencs/view/world/tablesubview.hpp +++ b/apps/opencs/view/world/tablesubview.hpp @@ -6,6 +6,7 @@ #include class QModelIndex; +class QWidget; namespace CSMWorld { @@ -35,6 +36,8 @@ namespace CSVWorld Table *mTable; TableBottomBox *mBottom; CSVFilter::FilterBox *mFilterBox; + bool mShowOptions; + QWidget *mOptions; public: @@ -60,6 +63,7 @@ namespace CSVWorld void cloneRequest (const CSMWorld::UniversalId& toClone); void createFilterRequest(std::vector< CSMWorld::UniversalId >& types, Qt::DropAction action); + void toggleOptions (); public slots: