Merge remote-tracking branch 'smbas/fix-bug-2728'

This commit is contained in:
Marc Zinnschlag 2015-07-27 11:23:49 +02:00
commit 420503d5fc
6 changed files with 116 additions and 45 deletions

View file

@ -7,23 +7,23 @@
void CSMWorld::IdTableProxyModel::updateColumnMap() void CSMWorld::IdTableProxyModel::updateColumnMap()
{ {
mColumnMap.clear(); Q_ASSERT(mSourceModel != NULL);
mColumnMap.clear();
if (mFilter) if (mFilter)
{ {
std::vector<int> columns = mFilter->getReferencedColumns(); std::vector<int> columns = mFilter->getReferencedColumns();
const IdTableBase& table = dynamic_cast<const IdTableBase&> (*sourceModel());
for (std::vector<int>::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter) for (std::vector<int>::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter)
mColumnMap.insert (std::make_pair (*iter, mColumnMap.insert (std::make_pair (*iter,
table.searchColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (*iter)))); mSourceModel->searchColumnIndex (static_cast<CSMWorld::Columns::ColumnId> (*iter))));
} }
} }
bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent)
const const
{ {
Q_ASSERT(mSourceModel != NULL);
// It is not possible to use filterAcceptsColumn() and check for // It is not possible to use filterAcceptsColumn() and check for
// sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags) // sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags)
// because the sourceColumn parameter excludes the hidden columns, i.e. wrong columns can // because the sourceColumn parameter excludes the hidden columns, i.e. wrong columns can
@ -35,34 +35,37 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI
if (!mFilter) if (!mFilter)
return true; return true;
return mFilter->test ( return mFilter->test (*mSourceModel, sourceRow, mColumnMap);
dynamic_cast<IdTableBase&> (*sourceModel()), sourceRow, mColumnMap);
} }
CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
: QSortFilterProxyModel (parent) : QSortFilterProxyModel (parent),
mSourceModel(NULL)
{ {
setSortCaseSensitivity (Qt::CaseInsensitive); setSortCaseSensitivity (Qt::CaseInsensitive);
} }
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
{ {
return mapFromSource (dynamic_cast<IdTableBase&> (*sourceModel()).getModelIndex (id, column)); Q_ASSERT(mSourceModel != NULL);
return mapFromSource(mSourceModel->getModelIndex (id, column));
} }
void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model) void CSMWorld::IdTableProxyModel::setSourceModel(QAbstractItemModel *model)
{ {
QSortFilterProxyModel::setSourceModel(model); QSortFilterProxyModel::setSourceModel(model);
connect(sourceModel(), mSourceModel = dynamic_cast<IdTableBase *>(sourceModel());
SIGNAL(rowsRemoved(const QModelIndex &, int, int)), connect(mSourceModel,
this,
SLOT(sourceRowsChanged(const QModelIndex &, int, int)));
connect(sourceModel(),
SIGNAL(rowsInserted(const QModelIndex &, int, int)), SIGNAL(rowsInserted(const QModelIndex &, int, int)),
this, this,
SLOT(sourceRowsChanged(const QModelIndex &, int, int))); SLOT(sourceRowsInserted(const QModelIndex &, int, int)));
connect(sourceModel(), connect(mSourceModel,
SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
this,
SLOT(sourceRowsRemoved(const QModelIndex &, int, int)));
connect(mSourceModel,
SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
this, this,
SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &))); SLOT(sourceDataChanged(const QModelIndex &, const QModelIndex &)));
@ -95,13 +98,30 @@ bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModel
return QSortFilterProxyModel::lessThan(left, right); return QSortFilterProxyModel::lessThan(left, right);
} }
QString CSMWorld::IdTableProxyModel::getRecordId(int sourceRow) const
{
Q_ASSERT(mSourceModel != NULL);
int idColumn = mSourceModel->findColumnIndex(Columns::ColumnId_Id);
return mSourceModel->data(mSourceModel->index(sourceRow, idColumn)).toString();
}
void CSMWorld::IdTableProxyModel::refreshFilter() void CSMWorld::IdTableProxyModel::refreshFilter()
{ {
updateColumnMap(); updateColumnMap();
invalidateFilter(); invalidateFilter();
} }
void CSMWorld::IdTableProxyModel::sourceRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) void CSMWorld::IdTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end)
{
refreshFilter();
if (!parent.isValid())
{
emit rowAdded(getRecordId(end).toUtf8().constData());
}
}
void CSMWorld::IdTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/)
{ {
refreshFilter(); refreshFilter();
} }

View file

@ -27,6 +27,10 @@ namespace CSMWorld
typedef std::map<Columns::ColumnId, std::vector<std::string> > EnumColumnCache; typedef std::map<Columns::ColumnId, std::vector<std::string> > EnumColumnCache;
mutable EnumColumnCache mEnumColumnCache; mutable EnumColumnCache mEnumColumnCache;
protected:
IdTableBase *mSourceModel;
private: private:
void updateColumnMap(); void updateColumnMap();
@ -45,15 +49,23 @@ namespace CSMWorld
protected: protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const; virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
private slots: QString getRecordId(int sourceRow) const;
void sourceRowsChanged(const QModelIndex &parent, int start, int end); protected slots:
void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end);
virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
signals:
void rowAdded(const std::string &id);
}; };
} }

View file

@ -9,16 +9,17 @@ namespace
{ {
QString toLower(const QString &str) QString toLower(const QString &str)
{ {
return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str()); return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toUtf8().constData()).c_str());
} }
} }
CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent)
: IdTableProxyModel(parent), : IdTableProxyModel(parent),
mType(type), mType(type),
mSourceModel(NULL),
mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic : mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic :
Columns::ColumnId_Journal) Columns::ColumnId_Journal),
mInfoColumnIndex(-1),
mLastAddedSourceRow(-1)
{ {
Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos);
} }
@ -26,23 +27,18 @@ CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type t
void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel) void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{ {
IdTableProxyModel::setSourceModel(sourceModel); IdTableProxyModel::setSourceModel(sourceModel);
mSourceModel = dynamic_cast<IdTableBase *>(sourceModel);
if (mSourceModel != NULL) if (mSourceModel != NULL)
{ {
connect(mSourceModel, mInfoColumnIndex = mSourceModel->findColumnIndex(mInfoColumnId);
SIGNAL(rowsInserted(const QModelIndex &, int, int)),
this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
connect(mSourceModel,
SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
mFirstRowCache.clear(); mFirstRowCache.clear();
} }
} }
bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{ {
Q_ASSERT(mSourceModel != NULL);
QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column());
QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column());
@ -56,8 +52,10 @@ bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QMod
int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
{ {
Q_ASSERT(mSourceModel != NULL);
int row = currentRow; int row = currentRow;
int column = mSourceModel->findColumnIndex(mInfoColumnId); int column = mInfoColumnIndex;
QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()); QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString());
if (mFirstRowCache.contains(info)) if (mFirstRowCache.contains(info))
@ -73,7 +71,41 @@ int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
return row; return row;
} }
void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/) void CSMWorld::InfoTableProxyModel::sourceRowsRemoved(const QModelIndex &/*parent*/, int /*start*/, int /*end*/)
{ {
refreshFilter();
mFirstRowCache.clear(); mFirstRowCache.clear();
} }
void CSMWorld::InfoTableProxyModel::sourceRowsInserted(const QModelIndex &parent, int /*start*/, int end)
{
refreshFilter();
if (!parent.isValid())
{
mFirstRowCache.clear();
// We can't re-sort the model here, because the topic of the added row isn't set yet.
// Store the row index for using in the first dataChanged() after this row insertion.
mLastAddedSourceRow = end;
}
}
void CSMWorld::InfoTableProxyModel::sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
refreshFilter();
if (mLastAddedSourceRow != -1 &&
topLeft.row() <= mLastAddedSourceRow && bottomRight.row() >= mLastAddedSourceRow)
{
// Now the topic of the last added row is set,
// so we can re-sort the model to ensure the corrent position of this row
int column = sortColumn();
Qt::SortOrder order = sortOrder();
sort(mInfoColumnIndex); // Restore the correct position of an added row
sort(column, order); // Restore the original sort order
emit rowAdded(getRecordId(mLastAddedSourceRow).toUtf8().constData());
// Make sure that we perform a re-sorting only in the first dataChanged() after a row insertion
mLastAddedSourceRow = -1;
}
}

View file

@ -16,25 +16,29 @@ namespace CSMWorld
Q_OBJECT Q_OBJECT
UniversalId::Type mType; UniversalId::Type mType;
IdTableBase *mSourceModel;
Columns::ColumnId mInfoColumnId; Columns::ColumnId mInfoColumnId;
///< Contains ID for Topic or Journal ID ///< Contains ID for Topic or Journal ID
int mInfoColumnIndex;
int mLastAddedSourceRow;
mutable QHash<QString, int> mFirstRowCache; mutable QHash<QString, int> mFirstRowCache;
int getFirstInfoRow(int currentRow) const; int getFirstInfoRow(int currentRow) const;
///< Finds the first row with the same topic (journal entry) as in \a currentRow ///< Finds the first row with the same topic (journal entry) as in \a currentRow
///< \a currentRow is a row of the source model.
public: public:
InfoTableProxyModel(UniversalId::Type type, QObject *parent = 0); InfoTableProxyModel(UniversalId::Type type, QObject *parent = 0);
void setSourceModel(QAbstractItemModel *sourceModel); virtual void setSourceModel(QAbstractItemModel *sourceModel);
protected: protected:
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
private slots: protected slots:
void modelRowsChanged(const QModelIndex &parent, int start, int end); virtual void sourceRowsInserted(const QModelIndex &parent, int start, int end);
virtual void sourceRowsRemoved(const QModelIndex &parent, int start, int end);
virtual void sourceDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
}; };
} }

View file

@ -371,8 +371,10 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), connect (mProxyModel, SIGNAL (rowsRemoved (const QModelIndex&, int, int)),
this, SLOT (tableSizeUpdate())); this, SLOT (tableSizeUpdate()));
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)), //connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int))); // this, SLOT (rowsInsertedEvent(const QModelIndex&, int, int)));
connect (mProxyModel, SIGNAL (rowAdded (const std::string &)),
this, SLOT (rowAdded (const std::string &)));
/// \note This signal could instead be connected to a slot that filters out changes not affecting /// \note This signal could instead be connected to a slot that filters out changes not affecting
/// the records status column (for permanence reasons) /// the records status column (for permanence reasons)
@ -714,12 +716,13 @@ std::vector< CSMWorld::UniversalId > CSVWorld::Table::getDraggedRecords() const
return idToDrag; return idToDrag;
} }
void CSVWorld::Table::rowsInsertedEvent(const QModelIndex& parent, int start, int end) void CSVWorld::Table::rowAdded(const std::string &id)
{ {
tableSizeUpdate(); tableSizeUpdate();
if(mJumpToAddedRecord) if(mJumpToAddedRecord)
{ {
selectRow(end); int idColumn = mModel->findColumnIndex(CSMWorld::Columns::ColumnId_Id);
selectRow(mProxyModel->getModelIndex(id, idColumn).row());
if(mUnselectAfterJump) if(mUnselectAfterJump)
clearSelection(); clearSelection();

View file

@ -140,7 +140,7 @@ namespace CSVWorld
void updateUserSetting (const QString &name, const QStringList &list); void updateUserSetting (const QString &name, const QStringList &list);
void rowsInsertedEvent(const QModelIndex& parent, int start, int end); void rowAdded(const std::string &id);
}; };
} }