mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
8.8 KiB
C++
282 lines
8.8 KiB
C++
#include "idtree.hpp"
|
|
|
|
#include "nestedtablewrapper.hpp"
|
|
|
|
#include "collectionbase.hpp"
|
|
#include "columnbase.hpp"
|
|
#include "nestedcollection.hpp"
|
|
|
|
#include <apps/opencs/model/world/columns.hpp>
|
|
#include <apps/opencs/model/world/idtable.hpp>
|
|
|
|
#include <stdexcept>
|
|
|
|
// NOTE: parent class still needs idCollection
|
|
CSMWorld::IdTree::IdTree(NestedCollection* nestedCollection, CollectionBase* idCollection, unsigned int features)
|
|
: IdTable(idCollection, features)
|
|
, mNestedCollection(nestedCollection)
|
|
{
|
|
}
|
|
|
|
int CSMWorld::IdTree::rowCount(const QModelIndex& parent) const
|
|
{
|
|
if (hasChildren(parent))
|
|
return mNestedCollection->getNestedRowsCount(parent.row(), parent.column());
|
|
|
|
return IdTable::rowCount(parent);
|
|
}
|
|
|
|
int CSMWorld::IdTree::columnCount(const QModelIndex& parent) const
|
|
{
|
|
if (hasChildren(parent))
|
|
return mNestedCollection->getNestedColumnsCount(parent.row(), parent.column());
|
|
|
|
return IdTable::columnCount(parent);
|
|
}
|
|
|
|
QVariant CSMWorld::IdTree::data(const QModelIndex& index, int role) const
|
|
{
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
if (index.internalId() != 0)
|
|
{
|
|
std::pair<int, int> parentAddress(unfoldIndexAddress(index.internalId()));
|
|
const NestableColumn* parentColumn = mNestedCollection->getNestableColumn(parentAddress.second);
|
|
|
|
if (role == ColumnBase::Role_Display)
|
|
return parentColumn->nestedColumn(index.column()).mDisplayType;
|
|
|
|
if (role == ColumnBase::Role_ColumnId)
|
|
return parentColumn->nestedColumn(index.column()).mColumnId;
|
|
|
|
if (role == Qt::EditRole && !parentColumn->nestedColumn(index.column()).isEditable())
|
|
return QVariant();
|
|
|
|
if (role != Qt::DisplayRole && role != Qt::EditRole)
|
|
return QVariant();
|
|
|
|
return mNestedCollection->getNestedData(parentAddress.first, parentAddress.second, index.row(), index.column());
|
|
}
|
|
else
|
|
{
|
|
return IdTable::data(index, role);
|
|
}
|
|
}
|
|
|
|
QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const
|
|
{
|
|
if (section < 0 || section >= idCollection()->getColumns())
|
|
return QVariant();
|
|
|
|
const NestableColumn* parentColumn = mNestedCollection->getNestableColumn(section);
|
|
|
|
if (orientation == Qt::Vertical)
|
|
return QVariant();
|
|
|
|
if (role == Qt::DisplayRole)
|
|
return tr(parentColumn->nestedColumn(subSection).getTitle().c_str());
|
|
|
|
if (role == ColumnBase::Role_Flags)
|
|
return parentColumn->nestedColumn(subSection).mFlags;
|
|
|
|
if (role == ColumnBase::Role_Display)
|
|
return parentColumn->nestedColumn(subSection).mDisplayType;
|
|
|
|
if (role == ColumnBase::Role_ColumnId)
|
|
return parentColumn->nestedColumn(subSection).mColumnId;
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
bool CSMWorld::IdTree::setData(const QModelIndex& index, const QVariant& value, int role)
|
|
{
|
|
if (index.internalId() != 0)
|
|
{
|
|
if (idCollection()->getColumn(parent(index).column()).isEditable() && role == Qt::EditRole)
|
|
{
|
|
const std::pair<int, int>& parentAddress(unfoldIndexAddress(index.internalId()));
|
|
|
|
mNestedCollection->setNestedData(
|
|
parentAddress.first, parentAddress.second, value, index.row(), index.column());
|
|
emit dataChanged(index, index);
|
|
|
|
// Modifying a value can also change the Modified status of a record.
|
|
int stateColumn = searchColumnIndex(Columns::ColumnId_Modification);
|
|
if (stateColumn != -1)
|
|
{
|
|
QModelIndex stateIndex = this->index(index.parent().row(), stateColumn);
|
|
emit dataChanged(stateIndex, stateIndex);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
return IdTable::setData(index, value, role);
|
|
}
|
|
|
|
Qt::ItemFlags CSMWorld::IdTree::flags(const QModelIndex& index) const
|
|
{
|
|
if (!index.isValid())
|
|
return Qt::ItemFlags();
|
|
|
|
if (index.internalId() != 0)
|
|
{
|
|
std::pair<int, int> parentAddress(unfoldIndexAddress(index.internalId()));
|
|
|
|
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
|
|
|
if (mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable())
|
|
flags |= Qt::ItemIsEditable;
|
|
|
|
return flags;
|
|
}
|
|
else
|
|
return IdTable::flags(index);
|
|
}
|
|
|
|
bool CSMWorld::IdTree::removeRows(int row, int count, const QModelIndex& parent)
|
|
{
|
|
if (parent.isValid())
|
|
{
|
|
beginRemoveRows(parent, row, row + count - 1);
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
{
|
|
mNestedCollection->removeNestedRows(parent.row(), parent.column(), row + i);
|
|
}
|
|
|
|
endRemoveRows();
|
|
|
|
emit dataChanged(CSMWorld::IdTree::index(parent.row(), 0),
|
|
CSMWorld::IdTree::index(parent.row(), idCollection()->getColumns() - 1));
|
|
|
|
return true;
|
|
}
|
|
else
|
|
return IdTable::removeRows(row, count, parent);
|
|
}
|
|
|
|
void CSMWorld::IdTree::addNestedRow(const QModelIndex& parent, int position)
|
|
{
|
|
if (!hasChildren(parent))
|
|
throw std::logic_error("Tried to set nested table, but index has no children");
|
|
|
|
int row = parent.row();
|
|
|
|
beginInsertRows(parent, position, position);
|
|
mNestedCollection->addNestedRow(row, parent.column(), position);
|
|
endInsertRows();
|
|
|
|
emit dataChanged(CSMWorld::IdTree::index(row, 0), CSMWorld::IdTree::index(row, idCollection()->getColumns() - 1));
|
|
}
|
|
|
|
QModelIndex CSMWorld::IdTree::index(int row, int column, const QModelIndex& parent) const
|
|
{
|
|
unsigned int encodedId = 0;
|
|
if (parent.isValid())
|
|
{
|
|
encodedId = this->foldIndexAddress(parent);
|
|
}
|
|
|
|
if (row < 0 || row >= rowCount(parent))
|
|
return QModelIndex();
|
|
|
|
if (column < 0 || column >= columnCount(parent))
|
|
return QModelIndex();
|
|
|
|
return createIndex(row, column, encodedId); // store internal id
|
|
}
|
|
|
|
QModelIndex CSMWorld::IdTree::getNestedModelIndex(const std::string& id, int column) const
|
|
{
|
|
return CSMWorld::IdTable::index(idCollection()->getIndex(ESM::RefId::stringRefId(id)), column);
|
|
}
|
|
|
|
QModelIndex CSMWorld::IdTree::parent(const QModelIndex& index) const
|
|
{
|
|
if (index.internalId() == 0) // 0 is used for indexs with invalid parent (top level data)
|
|
return QModelIndex();
|
|
|
|
unsigned int id = index.internalId();
|
|
const std::pair<int, int>& address(unfoldIndexAddress(id));
|
|
|
|
if (address.first >= this->rowCount() || address.second >= this->columnCount())
|
|
throw std::logic_error("Parent index is not present in the model");
|
|
|
|
return createIndex(address.first, address.second);
|
|
}
|
|
|
|
unsigned int CSMWorld::IdTree::foldIndexAddress(const QModelIndex& index) const
|
|
{
|
|
unsigned int out = index.row() * this->columnCount();
|
|
out += index.column();
|
|
return ++out;
|
|
}
|
|
|
|
std::pair<int, int> CSMWorld::IdTree::unfoldIndexAddress(unsigned int id) const
|
|
{
|
|
if (id == 0)
|
|
throw std::runtime_error("Attempt to unfold index id of the top level data cell");
|
|
|
|
--id;
|
|
int row = id / this->columnCount();
|
|
int column = id - row * this->columnCount();
|
|
return std::make_pair(row, column);
|
|
}
|
|
|
|
// FIXME: Not sure why this check is also needed?
|
|
//
|
|
// index.data().isValid() requires RefIdAdapter::getData() to return a valid QVariant for
|
|
// nested columns (refidadapterimp.hpp)
|
|
//
|
|
// Also see comments in refidadapter.hpp and refidadapterimp.hpp.
|
|
bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const
|
|
{
|
|
return (index.isValid() && index.internalId() == 0
|
|
&& mNestedCollection->getNestableColumn(index.column())->hasChildren() && index.data().isValid());
|
|
}
|
|
|
|
void CSMWorld::IdTree::setNestedTable(const QModelIndex& index, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
|
{
|
|
if (!hasChildren(index))
|
|
throw std::logic_error("Tried to set nested table, but index has no children");
|
|
|
|
bool removeRowsMode = false;
|
|
if (nestedTable.size() != this->nestedTable(index)->size())
|
|
{
|
|
emit resetStart(this->index(index.row(), 0).data().toString());
|
|
removeRowsMode = true;
|
|
}
|
|
|
|
mNestedCollection->setNestedTable(index.row(), index.column(), nestedTable);
|
|
|
|
emit dataChanged(CSMWorld::IdTree::index(index.row(), 0),
|
|
CSMWorld::IdTree::index(index.row(), idCollection()->getColumns() - 1));
|
|
|
|
if (removeRowsMode)
|
|
{
|
|
emit resetEnd(this->index(index.row(), 0).data().toString());
|
|
}
|
|
}
|
|
|
|
CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelIndex& index) const
|
|
{
|
|
if (!hasChildren(index))
|
|
throw std::logic_error("Tried to retrieve nested table, but index has no children");
|
|
|
|
return mNestedCollection->nestedTable(index.row(), index.column());
|
|
}
|
|
|
|
int CSMWorld::IdTree::searchNestedColumnIndex(int parentColumn, Columns::ColumnId id)
|
|
{
|
|
return mNestedCollection->searchNestedColumnIndex(parentColumn, id);
|
|
}
|
|
|
|
int CSMWorld::IdTree::findNestedColumnIndex(int parentColumn, Columns::ColumnId id)
|
|
{
|
|
return mNestedCollection->findNestedColumnIndex(parentColumn, id);
|
|
}
|