mirror of https://github.com/OpenMW/openmw.git
Merge branch 'master' of https://github.com/OpenMW/openmw into osg
Conflicts: apps/openmw/engine.cpp apps/openmw/mwgui/mainmenu.cpp apps/openmw/mwgui/windowmanagerimp.cpp apps/openmw/mwinput/inputmanagerimp.cpp apps/openmw/mwrender/animation.cpp apps/openmw/mwrender/debugging.cpp apps/openmw/mwrender/npcanimation.cpp apps/openmw/mwrender/renderingmanager.cpp apps/openmw/mwrender/sky.cpp components/nif/nifkey.hpp components/nif/nifstream.hpp components/nifbullet/bulletnifloader.cpp components/nifogre/ogrenifloader.hpp libs/openengine/bullet/physic.cpp libs/openengine/gui/manager.cpppull/638/head
commit
e1f4a7f647
@ -0,0 +1,259 @@
|
||||
#include "idtree.hpp"
|
||||
|
||||
#include "nestedtablewrapper.hpp"
|
||||
|
||||
#include "collectionbase.hpp"
|
||||
#include "nestedcollection.hpp"
|
||||
#include "columnbase.hpp"
|
||||
|
||||
// NOTE: parent class still needs idCollection
|
||||
CSMWorld::IdTree::IdTree (NestedCollection *nestedCollection, CollectionBase *idCollection, unsigned int features)
|
||||
: IdTable (idCollection, features), mNestedCollection (nestedCollection)
|
||||
{}
|
||||
|
||||
CSMWorld::IdTree::~IdTree()
|
||||
{}
|
||||
|
||||
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 ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0)
|
||||
return QVariant();
|
||||
|
||||
if (index.internalId() != 0)
|
||||
{
|
||||
std::pair<int, int> parentAddress(unfoldIndexAddress(index.internalId()));
|
||||
|
||||
if (role == Qt::EditRole &&
|
||||
!mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable())
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
return mNestedCollection->getNestedData(parentAddress.first,
|
||||
parentAddress.second, index.row(), index.column());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable())
|
||||
return QVariant();
|
||||
|
||||
return idCollection()->getData (index.row(), index.column());
|
||||
}
|
||||
}
|
||||
|
||||
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 idCollection()->getColumn (section).mFlags;
|
||||
|
||||
if (role==ColumnBase::Role_Display)
|
||||
return parentColumn->nestedColumn(subSection).mDisplayType;
|
||||
|
||||
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 (CSMWorld::IdTree::index (parentAddress.first, 0),
|
||||
CSMWorld::IdTree::index (parentAddress.first, idCollection()->getColumns()-1));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return IdTable::setData(index, value, role);
|
||||
}
|
||||
|
||||
Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
|
||||
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>=idCollection()->getSize())
|
||||
return QModelIndex();
|
||||
|
||||
if (column<0 || column>=idCollection()->getColumns())
|
||||
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 (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>& adress(unfoldIndexAddress(id));
|
||||
|
||||
if (adress.first >= this->rowCount() || adress.second >= this->columnCount())
|
||||
throw "Parent index is not present in the model";
|
||||
|
||||
return createIndex(adress.first, adress.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 "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 retrive nested table, but index has no children");
|
||||
|
||||
return mNestedCollection->nestedTable(index.row(), index.column());
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
#ifndef CSM_WOLRD_IDTREE_H
|
||||
#define CSM_WOLRD_IDTREE_H
|
||||
|
||||
#include "idtable.hpp"
|
||||
#include "universalid.hpp"
|
||||
#include "columns.hpp"
|
||||
|
||||
/*! \brief
|
||||
* Class for holding the model. Uses typical qt table abstraction/interface for granting access
|
||||
* to the individiual fields of the records, Some records are holding nested data (for instance
|
||||
* inventory list of the npc). In casses like this, table model offers interface to access
|
||||
* nested data in the qt way - that is specify parent. Since some of those nested data require
|
||||
* multiple columns to represent informations, single int (default way to index model in the
|
||||
* qmodelindex) is not sufficiant. Therefore tablemodelindex class can hold two ints for the
|
||||
* sake of indexing two dimensions of the table. This model does not support multiple levels of
|
||||
* the nested data. Vast majority of methods makes sense only for the top level data.
|
||||
*/
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class NestedCollection;
|
||||
struct RecordBase;
|
||||
struct NestedTableWrapperBase;
|
||||
|
||||
class IdTree : public IdTable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private:
|
||||
|
||||
NestedCollection *mNestedCollection;
|
||||
|
||||
// not implemented
|
||||
IdTree (const IdTree&);
|
||||
IdTree& operator= (const IdTree&);
|
||||
|
||||
unsigned int foldIndexAddress(const QModelIndex& index) const;
|
||||
std::pair<int, int> unfoldIndexAddress(unsigned int id) const;
|
||||
|
||||
public:
|
||||
|
||||
IdTree (NestedCollection *nestedCollection, CollectionBase *idCollection, unsigned int features = 0);
|
||||
///< The ownerships of \a nestedCollecton and \a idCollection are not transferred.
|
||||
|
||||
virtual ~IdTree();
|
||||
|
||||
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
virtual int columnCount (const QModelIndex & parent = QModelIndex()) const;
|
||||
|
||||
virtual QVariant data (const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
|
||||
virtual bool setData ( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
|
||||
|
||||
virtual Qt::ItemFlags flags (const QModelIndex & index) const;
|
||||
|
||||
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
|
||||
|
||||
virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex())
|
||||
const;
|
||||
|
||||
virtual QModelIndex parent (const QModelIndex& index) const;
|
||||
|
||||
QModelIndex getNestedModelIndex (const std::string& id, int column) const;
|
||||
|
||||
QVariant nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
|
||||
NestedTableWrapperBase* nestedTable(const QModelIndex &index) const;
|
||||
|
||||
void setNestedTable(const QModelIndex &index, const NestedTableWrapperBase& nestedTable);
|
||||
|
||||
void addNestedRow (const QModelIndex& parent, int position);
|
||||
|
||||
virtual bool hasChildren (const QModelIndex& index) const;
|
||||
|
||||
signals:
|
||||
|
||||
void resetStart(const QString& id);
|
||||
|
||||
void resetEnd(const QString& id);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,531 @@
|
||||
#include "nestedcoladapterimp.hpp"
|
||||
|
||||
#include <components/esm/loadregn.hpp>
|
||||
#include <components/esm/loadfact.hpp>
|
||||
|
||||
#include "idcollection.hpp"
|
||||
#include "pathgrid.hpp"
|
||||
#include "info.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
PathgridPointListAdapter::PathgridPointListAdapter () {}
|
||||
|
||||
void PathgridPointListAdapter::addRow(Record<Pathgrid>& record, int position) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
ESM::Pathgrid::PointList& points = pathgrid.mPoints;
|
||||
|
||||
// blank row
|
||||
ESM::Pathgrid::Point point;
|
||||
point.mX = 0;
|
||||
point.mY = 0;
|
||||
point.mZ = 0;
|
||||
point.mAutogenerated = 0;
|
||||
point.mConnectionNum = 0;
|
||||
point.mUnknown = 0;
|
||||
|
||||
// inserting a point should trigger re-indexing of the edges
|
||||
//
|
||||
// FIXME: does not auto refresh edges table view
|
||||
std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
|
||||
for (;iter != pathgrid.mEdges.end(); ++iter)
|
||||
{
|
||||
if ((*iter).mV0 >= position)
|
||||
(*iter).mV0++;
|
||||
if ((*iter).mV1 >= position)
|
||||
(*iter).mV1++;
|
||||
}
|
||||
|
||||
points.insert(points.begin()+position, point);
|
||||
pathgrid.mData.mS2 += 1; // increment the number of points
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
void PathgridPointListAdapter::removeRow(Record<Pathgrid>& record, int rowToRemove) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
ESM::Pathgrid::PointList& points = pathgrid.mPoints;
|
||||
|
||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (points.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
// deleting a point should trigger re-indexing of the edges
|
||||
// dangling edges are not allowed and hence removed
|
||||
//
|
||||
// FIXME: does not auto refresh edges table view
|
||||
std::vector<ESM::Pathgrid::Edge>::iterator iter = pathgrid.mEdges.begin();
|
||||
for (; iter != pathgrid.mEdges.end();)
|
||||
{
|
||||
if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove))
|
||||
iter = pathgrid.mEdges.erase(iter);
|
||||
else
|
||||
{
|
||||
if ((*iter).mV0 > rowToRemove)
|
||||
(*iter).mV0--;
|
||||
|
||||
if ((*iter).mV1 > rowToRemove)
|
||||
(*iter).mV1--;
|
||||
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
points.erase(points.begin()+rowToRemove);
|
||||
pathgrid.mData.mS2 -= 1; // decrement the number of points
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
void PathgridPointListAdapter::setTable(Record<Pathgrid>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
pathgrid.mPoints =
|
||||
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mPoints;
|
||||
pathgrid.mData.mS2 =
|
||||
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mData.mS2;
|
||||
// also update edges in case points were added/removed
|
||||
pathgrid.mEdges =
|
||||
static_cast<const PathgridPointsWrap &>(nestedTable).mRecord.mEdges;
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
NestedTableWrapperBase* PathgridPointListAdapter::table(const Record<Pathgrid>& record) const
|
||||
{
|
||||
// deleted by dtor of NestedTableStoring
|
||||
return new PathgridPointsWrap(record.get());
|
||||
}
|
||||
|
||||
QVariant PathgridPointListAdapter::getData(const Record<Pathgrid>& record,
|
||||
int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: return subRowIndex;
|
||||
case 1: return point.mX;
|
||||
case 2: return point.mY;
|
||||
case 3: return point.mZ;
|
||||
default: throw std::runtime_error("Pathgrid point subcolumn index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
void PathgridPointListAdapter::setData(Record<Pathgrid>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: return; // return without saving
|
||||
case 1: point.mX = value.toInt(); break;
|
||||
case 2: point.mY = value.toInt(); break;
|
||||
case 3: point.mZ = value.toInt(); break;
|
||||
default: throw std::runtime_error("Pathgrid point subcolumn index out of range");
|
||||
}
|
||||
|
||||
pathgrid.mPoints[subRowIndex] = point;
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
int PathgridPointListAdapter::getColumnsCount(const Record<Pathgrid>& record) const
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
int PathgridPointListAdapter::getRowsCount(const Record<Pathgrid>& record) const
|
||||
{
|
||||
return static_cast<int>(record.get().mPoints.size());
|
||||
}
|
||||
|
||||
PathgridEdgeListAdapter::PathgridEdgeListAdapter () {}
|
||||
|
||||
// ToDo: seems to be auto-sorted in the dialog table display after insertion
|
||||
void PathgridEdgeListAdapter::addRow(Record<Pathgrid>& record, int position) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges;
|
||||
|
||||
// blank row
|
||||
ESM::Pathgrid::Edge edge;
|
||||
edge.mV0 = 0;
|
||||
edge.mV1 = 0;
|
||||
|
||||
// NOTE: inserting a blank edge does not really make sense, perhaps this should be a
|
||||
// logic_error exception
|
||||
//
|
||||
// Currently the code assumes that the end user to know what he/she is doing.
|
||||
// e.g. Edges come in pairs, from points a->b and b->a
|
||||
edges.insert(edges.begin()+position, edge);
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
void PathgridEdgeListAdapter::removeRow(Record<Pathgrid>& record, int rowToRemove) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges;
|
||||
|
||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (edges.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
edges.erase(edges.begin()+rowToRemove);
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
void PathgridEdgeListAdapter::setTable(Record<Pathgrid>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
pathgrid.mEdges =
|
||||
static_cast<const NestedTableWrapper<ESM::Pathgrid::EdgeList> &>(nestedTable).mNestedTable;
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
NestedTableWrapperBase* PathgridEdgeListAdapter::table(const Record<Pathgrid>& record) const
|
||||
{
|
||||
// deleted by dtor of NestedTableStoring
|
||||
return new NestedTableWrapper<ESM::Pathgrid::EdgeList>(record.get().mEdges);
|
||||
}
|
||||
|
||||
QVariant PathgridEdgeListAdapter::getData(const Record<Pathgrid>& record,
|
||||
int subRowIndex, int subColIndex) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (pathgrid.mEdges.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: return subRowIndex;
|
||||
case 1: return edge.mV0;
|
||||
case 2: return edge.mV1;
|
||||
default: throw std::runtime_error("Pathgrid edge subcolumn index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
// ToDo: detect duplicates in mEdges
|
||||
void PathgridEdgeListAdapter::setData(Record<Pathgrid>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
Pathgrid pathgrid = record.get();
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (pathgrid.mEdges.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: return; // return without saving
|
||||
case 1: edge.mV0 = value.toInt(); break;
|
||||
case 2: edge.mV1 = value.toInt(); break;
|
||||
default: throw std::runtime_error("Pathgrid edge subcolumn index out of range");
|
||||
}
|
||||
|
||||
pathgrid.mEdges[subRowIndex] = edge;
|
||||
|
||||
record.setModified (pathgrid);
|
||||
}
|
||||
|
||||
int PathgridEdgeListAdapter::getColumnsCount(const Record<Pathgrid>& record) const
|
||||
{
|
||||
return 3;
|
||||
}
|
||||
|
||||
int PathgridEdgeListAdapter::getRowsCount(const Record<Pathgrid>& record) const
|
||||
{
|
||||
return static_cast<int>(record.get().mEdges.size());
|
||||
}
|
||||
|
||||
FactionReactionsAdapter::FactionReactionsAdapter () {}
|
||||
|
||||
void FactionReactionsAdapter::addRow(Record<ESM::Faction>& record, int position) const
|
||||
{
|
||||
ESM::Faction faction = record.get();
|
||||
|
||||
std::map<std::string, int>& reactions = faction.mReactions;
|
||||
|
||||
// blank row
|
||||
reactions.insert(std::make_pair("", 0));
|
||||
|
||||
record.setModified (faction);
|
||||
}
|
||||
|
||||
void FactionReactionsAdapter::removeRow(Record<ESM::Faction>& record, int rowToRemove) const
|
||||
{
|
||||
ESM::Faction faction = record.get();
|
||||
|
||||
std::map<std::string, int>& reactions = faction.mReactions;
|
||||
|
||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (reactions.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
// FIXME: how to ensure that the map entries correspond to table indicies?
|
||||
// WARNING: Assumed that the table view has the same order as std::map
|
||||
std::map<std::string, int>::iterator iter = reactions.begin();
|
||||
for(int i = 0; i < rowToRemove; ++i)
|
||||
iter++;
|
||||
reactions.erase(iter);
|
||||
|
||||
record.setModified (faction);
|
||||
}
|
||||
|
||||
void FactionReactionsAdapter::setTable(Record<ESM::Faction>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const
|
||||
{
|
||||
ESM::Faction faction = record.get();
|
||||
|
||||
faction.mReactions =
|
||||
static_cast<const NestedTableWrapper<std::map<std::string, int> >&>(nestedTable).mNestedTable;
|
||||
|
||||
record.setModified (faction);
|
||||
}
|
||||
|
||||
NestedTableWrapperBase* FactionReactionsAdapter::table(const Record<ESM::Faction>& record) const
|
||||
{
|
||||
// deleted by dtor of NestedTableStoring
|
||||
return new NestedTableWrapper<std::map<std::string, int> >(record.get().mReactions);
|
||||
}
|
||||
|
||||
QVariant FactionReactionsAdapter::getData(const Record<ESM::Faction>& record,
|
||||
int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Faction faction = record.get();
|
||||
|
||||
std::map<std::string, int>& reactions = faction.mReactions;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (reactions.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
// FIXME: how to ensure that the map entries correspond to table indicies?
|
||||
// WARNING: Assumed that the table view has the same order as std::map
|
||||
std::map<std::string, int>::const_iterator iter = reactions.begin();
|
||||
for(int i = 0; i < subRowIndex; ++i)
|
||||
iter++;
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: return QString((*iter).first.c_str());
|
||||
case 1: return (*iter).second;
|
||||
default: throw std::runtime_error("Faction reactions subcolumn index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
void FactionReactionsAdapter::setData(Record<ESM::Faction>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Faction faction = record.get();
|
||||
|
||||
std::map<std::string, int>& reactions = faction.mReactions;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (reactions.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
// FIXME: how to ensure that the map entries correspond to table indicies?
|
||||
// WARNING: Assumed that the table view has the same order as std::map
|
||||
std::map<std::string, int>::iterator iter = reactions.begin();
|
||||
for(int i = 0; i < subRowIndex; ++i)
|
||||
iter++;
|
||||
|
||||
std::string factionId = (*iter).first;
|
||||
int reaction = (*iter).second;
|
||||
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
reactions.erase(iter);
|
||||
reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
reactions[factionId] = value.toInt();
|
||||
break;
|
||||
}
|
||||
default: throw std::runtime_error("Faction reactions subcolumn index out of range");
|
||||
}
|
||||
|
||||
record.setModified (faction);
|
||||
}
|
||||
|
||||
int FactionReactionsAdapter::getColumnsCount(const Record<ESM::Faction>& record) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
int FactionReactionsAdapter::getRowsCount(const Record<ESM::Faction>& record) const
|
||||
{
|
||||
return static_cast<int>(record.get().mReactions.size());
|
||||
}
|
||||
|
||||
RegionSoundListAdapter::RegionSoundListAdapter () {}
|
||||
|
||||
void RegionSoundListAdapter::addRow(Record<ESM::Region>& record, int position) const
|
||||
{
|
||||
ESM::Region region = record.get();
|
||||
|
||||
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
|
||||
|
||||
// blank row
|
||||
ESM::Region::SoundRef soundRef;
|
||||
soundRef.mSound.assign("");
|
||||
soundRef.mChance = 0;
|
||||
|
||||
soundList.insert(soundList.begin()+position, soundRef);
|
||||
|
||||
record.setModified (region);
|
||||
}
|
||||
|
||||
void RegionSoundListAdapter::removeRow(Record<ESM::Region>& record, int rowToRemove) const
|
||||
{
|
||||
ESM::Region region = record.get();
|
||||
|
||||
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
|
||||
|
||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (soundList.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
soundList.erase(soundList.begin()+rowToRemove);
|
||||
|
||||
record.setModified (region);
|
||||
}
|
||||
|
||||
void RegionSoundListAdapter::setTable(Record<ESM::Region>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const
|
||||
{
|
||||
ESM::Region region = record.get();
|
||||
|
||||
region.mSoundList =
|
||||
static_cast<const NestedTableWrapper<std::vector<ESM::Region::SoundRef> >&>(nestedTable).mNestedTable;
|
||||
|
||||
record.setModified (region);
|
||||
}
|
||||
|
||||
NestedTableWrapperBase* RegionSoundListAdapter::table(const Record<ESM::Region>& record) const
|
||||
{
|
||||
// deleted by dtor of NestedTableStoring
|
||||
return new NestedTableWrapper<std::vector<ESM::Region::SoundRef> >(record.get().mSoundList);
|
||||
}
|
||||
|
||||
QVariant RegionSoundListAdapter::getData(const Record<ESM::Region>& record,
|
||||
int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Region region = record.get();
|
||||
|
||||
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (soundList.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
ESM::Region::SoundRef soundRef = soundList[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: return QString(soundRef.mSound.toString().c_str());
|
||||
case 1: return soundRef.mChance;
|
||||
default: throw std::runtime_error("Region sounds subcolumn index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
void RegionSoundListAdapter::setData(Record<ESM::Region>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESM::Region region = record.get();
|
||||
|
||||
std::vector<ESM::Region::SoundRef>& soundList = region.mSoundList;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (soundList.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
ESM::Region::SoundRef soundRef = soundList[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break;
|
||||
case 1: soundRef.mChance = static_cast<unsigned char>(value.toInt()); break;
|
||||
default: throw std::runtime_error("Region sounds subcolumn index out of range");
|
||||
}
|
||||
|
||||
region.mSoundList[subRowIndex] = soundRef;
|
||||
|
||||
record.setModified (region);
|
||||
}
|
||||
|
||||
int RegionSoundListAdapter::getColumnsCount(const Record<ESM::Region>& record) const
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
int RegionSoundListAdapter::getRowsCount(const Record<ESM::Region>& record) const
|
||||
{
|
||||
return static_cast<int>(record.get().mSoundList.size());
|
||||
}
|
||||
|
||||
InfoListAdapter::InfoListAdapter () {}
|
||||
|
||||
void InfoListAdapter::addRow(Record<Info>& record, int position) const
|
||||
{
|
||||
throw std::logic_error ("cannot add a row to a fixed table");
|
||||
}
|
||||
|
||||
void InfoListAdapter::removeRow(Record<Info>& record, int rowToRemove) const
|
||||
{
|
||||
throw std::logic_error ("cannot add a row to a fixed table");
|
||||
}
|
||||
|
||||
void InfoListAdapter::setTable(Record<Info>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const
|
||||
{
|
||||
throw std::logic_error ("table operation not supported");
|
||||
}
|
||||
|
||||
NestedTableWrapperBase* InfoListAdapter::table(const Record<Info>& record) const
|
||||
{
|
||||
throw std::logic_error ("table operation not supported");
|
||||
}
|
||||
|
||||
QVariant InfoListAdapter::getData(const Record<Info>& record,
|
||||
int subRowIndex, int subColIndex) const
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
if (subColIndex == 0)
|
||||
return QString(info.mResultScript.c_str());
|
||||
else
|
||||
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
||||
}
|
||||
|
||||
void InfoListAdapter::setData(Record<Info>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
Info info = record.get();
|
||||
|
||||
if (subColIndex == 0)
|
||||
info.mResultScript = value.toString().toStdString();
|
||||
else
|
||||
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
||||
|
||||
record.setModified (info);
|
||||
}
|
||||
|
||||
int InfoListAdapter::getColumnsCount(const Record<Info>& record) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int InfoListAdapter::getRowsCount(const Record<Info>& record) const
|
||||
{
|
||||
return 1; // fixed at size 1
|
||||
}
|
||||
}
|
@ -0,0 +1,417 @@
|
||||
#ifndef CSM_WOLRD_NESTEDCOLADAPTERIMP_H
|
||||
#define CSM_WOLRD_NESTEDCOLADAPTERIMP_H
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
#include <components/esm/effectlist.hpp>
|
||||
#include <components/esm/loadmgef.hpp> // for converting magic effect id to string & back
|
||||
#include <components/esm/loadskil.hpp> // for converting skill names
|
||||
#include <components/esm/attr.hpp> // for converting attributes
|
||||
|
||||
#include "nestedcolumnadapter.hpp"
|
||||
#include "nestedtablewrapper.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Faction;
|
||||
struct Region;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct Pathgrid;
|
||||
struct Info;
|
||||
|
||||
struct PathgridPointsWrap : public NestedTableWrapperBase
|
||||
{
|
||||
ESM::Pathgrid mRecord;
|
||||
|
||||
PathgridPointsWrap(ESM::Pathgrid pathgrid)
|
||||
: mRecord(pathgrid) {}
|
||||
|
||||
virtual ~PathgridPointsWrap() {}
|
||||
|
||||
virtual int size() const
|
||||
{
|
||||
return mRecord.mPoints.size(); // used in IdTree::setNestedTable()
|
||||
}
|
||||
};
|
||||
|
||||
class PathgridPointListAdapter : public NestedColumnAdapter<Pathgrid>
|
||||
{
|
||||
public:
|
||||
PathgridPointListAdapter ();
|
||||
|
||||
virtual void addRow(Record<Pathgrid>& record, int position) const;
|
||||
|
||||
virtual void removeRow(Record<Pathgrid>& record, int rowToRemove) const;
|
||||
|
||||
virtual void setTable(Record<Pathgrid>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const;
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<Pathgrid>& record) const;
|
||||
|
||||
virtual QVariant getData(const Record<Pathgrid>& record,
|
||||
int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual void setData(Record<Pathgrid>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual int getColumnsCount(const Record<Pathgrid>& record) const;
|
||||
|
||||
virtual int getRowsCount(const Record<Pathgrid>& record) const;
|
||||
};
|
||||
|
||||
class PathgridEdgeListAdapter : public NestedColumnAdapter<Pathgrid>
|
||||
{
|
||||
public:
|
||||
PathgridEdgeListAdapter ();
|
||||
|
||||
virtual void addRow(Record<Pathgrid>& record, int position) const;
|
||||
|
||||
virtual void removeRow(Record<Pathgrid>& record, int rowToRemove) const;
|
||||
|
||||
virtual void setTable(Record<Pathgrid>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const;
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<Pathgrid>& record) const;
|
||||
|
||||
virtual QVariant getData(const Record<Pathgrid>& record,
|
||||
int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual void setData(Record<Pathgrid>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual int getColumnsCount(const Record<Pathgrid>& record) const;
|
||||
|
||||
virtual int getRowsCount(const Record<Pathgrid>& record) const;
|
||||
};
|
||||
|
||||
class FactionReactionsAdapter : public NestedColumnAdapter<ESM::Faction>
|
||||
{
|
||||
public:
|
||||
FactionReactionsAdapter ();
|
||||
|
||||
virtual void addRow(Record<ESM::Faction>& record, int position) const;
|
||||
|
||||
virtual void removeRow(Record<ESM::Faction>& record, int rowToRemove) const;
|
||||
|
||||
virtual void setTable(Record<ESM::Faction>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const;
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<ESM::Faction>& record) const;
|
||||
|
||||
virtual QVariant getData(const Record<ESM::Faction>& record,
|
||||
int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual void setData(Record<ESM::Faction>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual int getColumnsCount(const Record<ESM::Faction>& record) const;
|
||||
|
||||
virtual int getRowsCount(const Record<ESM::Faction>& record) const;
|
||||
};
|
||||
|
||||
class RegionSoundListAdapter : public NestedColumnAdapter<ESM::Region>
|
||||
{
|
||||
public:
|
||||
RegionSoundListAdapter ();
|
||||
|
||||
virtual void addRow(Record<ESM::Region>& record, int position) const;
|
||||
|
||||
virtual void removeRow(Record<ESM::Region>& record, int rowToRemove) const;
|
||||
|
||||
virtual void setTable(Record<ESM::Region>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const;
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<ESM::Region>& record) const;
|
||||
|
||||
virtual QVariant getData(const Record<ESM::Region>& record,
|
||||
int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual void setData(Record<ESM::Region>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual int getColumnsCount(const Record<ESM::Region>& record) const;
|
||||
|
||||
virtual int getRowsCount(const Record<ESM::Region>& record) const;
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
class SpellListAdapter : public NestedColumnAdapter<ESXRecordT>
|
||||
{
|
||||
public:
|
||||
SpellListAdapter () {}
|
||||
|
||||
virtual void addRow(Record<ESXRecordT>& record, int position) const
|
||||
{
|
||||
ESXRecordT raceOrBthSgn = record.get();
|
||||
|
||||
std::vector<std::string>& spells = raceOrBthSgn.mPowers.mList;
|
||||
|
||||
// blank row
|
||||
std::string spell = "";
|
||||
|
||||
spells.insert(spells.begin()+position, spell);
|
||||
|
||||
record.setModified (raceOrBthSgn);
|
||||
}
|
||||
|
||||
virtual void removeRow(Record<ESXRecordT>& record, int rowToRemove) const
|
||||
{
|
||||
ESXRecordT raceOrBthSgn = record.get();
|
||||
|
||||
std::vector<std::string>& spells = raceOrBthSgn.mPowers.mList;
|
||||
|
||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (spells.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
spells.erase(spells.begin()+rowToRemove);
|
||||
|
||||
record.setModified (raceOrBthSgn);
|
||||
}
|
||||
|
||||
virtual void setTable(Record<ESXRecordT>& record, const NestedTableWrapperBase& nestedTable) const
|
||||
{
|
||||
ESXRecordT raceOrBthSgn = record.get();
|
||||
|
||||
raceOrBthSgn.mPowers.mList =
|
||||
static_cast<const NestedTableWrapper<std::vector<std::string> >&>(nestedTable).mNestedTable;
|
||||
|
||||
record.setModified (raceOrBthSgn);
|
||||
}
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<ESXRecordT>& record) const
|
||||
{
|
||||
// deleted by dtor of NestedTableStoring
|
||||
return new NestedTableWrapper<std::vector<std::string> >(record.get().mPowers.mList);
|
||||
}
|
||||
|
||||
virtual QVariant getData(const Record<ESXRecordT>& record, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESXRecordT raceOrBthSgn = record.get();
|
||||
|
||||
std::vector<std::string>& spells = raceOrBthSgn.mPowers.mList;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (spells.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
std::string spell = spells[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: return QString(spell.c_str());
|
||||
default: throw std::runtime_error("Spells subcolumn index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setData(Record<ESXRecordT>& record, const QVariant& value,
|
||||
int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESXRecordT raceOrBthSgn = record.get();
|
||||
|
||||
std::vector<std::string>& spells = raceOrBthSgn.mPowers.mList;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (spells.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
std::string spell = spells[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0: spell = value.toString().toUtf8().constData(); break;
|
||||
default: throw std::runtime_error("Spells subcolumn index out of range");
|
||||
}
|
||||
|
||||
raceOrBthSgn.mPowers.mList[subRowIndex] = spell;
|
||||
|
||||
record.setModified (raceOrBthSgn);
|
||||
}
|
||||
|
||||
virtual int getColumnsCount(const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual int getRowsCount(const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return static_cast<int>(record.get().mPowers.mList.size());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
class EffectsListAdapter : public NestedColumnAdapter<ESXRecordT>
|
||||
{
|
||||
public:
|
||||
EffectsListAdapter () {}
|
||||
|
||||
virtual void addRow(Record<ESXRecordT>& record, int position) const
|
||||
{
|
||||
ESXRecordT magic = record.get();
|
||||
|
||||
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList;
|
||||
|
||||
// blank row
|
||||
ESM::ENAMstruct effect;
|
||||
effect.mEffectID = 0;
|
||||
effect.mSkill = -1;
|
||||
effect.mAttribute = -1;
|
||||
effect.mRange = 0;
|
||||
effect.mArea = 0;
|
||||
effect.mDuration = 0;
|
||||
effect.mMagnMin = 0;
|
||||
effect.mMagnMax = 0;
|
||||
|
||||
effectsList.insert(effectsList.begin()+position, effect);
|
||||
|
||||
record.setModified (magic);
|
||||
}
|
||||
|
||||
virtual void removeRow(Record<ESXRecordT>& record, int rowToRemove) const
|
||||
{
|
||||
ESXRecordT magic = record.get();
|
||||
|
||||
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList;
|
||||
|
||||
if (rowToRemove < 0 || rowToRemove >= static_cast<int> (effectsList.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
effectsList.erase(effectsList.begin()+rowToRemove);
|
||||
|
||||
record.setModified (magic);
|
||||
}
|
||||
|
||||
virtual void setTable(Record<ESXRecordT>& record, const NestedTableWrapperBase& nestedTable) const
|
||||
{
|
||||
ESXRecordT magic = record.get();
|
||||
|
||||
magic.mEffects.mList =
|
||||
static_cast<const NestedTableWrapper<std::vector<ESM::ENAMstruct> >&>(nestedTable).mNestedTable;
|
||||
|
||||
record.setModified (magic);
|
||||
}
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<ESXRecordT>& record) const
|
||||
{
|
||||
// deleted by dtor of NestedTableStoring
|
||||
return new NestedTableWrapper<std::vector<ESM::ENAMstruct> >(record.get().mEffects.mList);
|
||||
}
|
||||
|
||||
virtual QVariant getData(const Record<ESXRecordT>& record, int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESXRecordT magic = record.get();
|
||||
|
||||
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (effectsList.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
ESM::ENAMstruct effect = effectsList[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (effect.mEffectID >=0 && effect.mEffectID < ESM::MagicEffect::Length)
|
||||
return effect.mRange;
|
||||
else
|
||||
throw std::runtime_error("Magic effects ID unexpected value");
|
||||
}
|
||||
case 1: return effect.mSkill;
|
||||
case 2: return effect.mAttribute;
|
||||
case 3:
|
||||
{
|
||||
if (effect.mRange >=0 && effect.mRange <=2)
|
||||
return effect.mRange;
|
||||
else
|
||||
throw std::runtime_error("Magic effects range unexpected value");
|
||||
}
|
||||
case 4: return effect.mArea;
|
||||
case 5: return effect.mDuration;
|
||||
case 6: return effect.mMagnMin;
|
||||
case 7: return effect.mMagnMax;
|
||||
default: throw std::runtime_error("Magic Effects subcolumn index out of range");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setData(Record<ESXRecordT>& record, const QVariant& value,
|
||||
int subRowIndex, int subColIndex) const
|
||||
{
|
||||
ESXRecordT magic = record.get();
|
||||
|
||||
std::vector<ESM::ENAMstruct>& effectsList = magic.mEffects.mList;
|
||||
|
||||
if (subRowIndex < 0 || subRowIndex >= static_cast<int> (effectsList.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
ESM::ENAMstruct effect = effectsList[subRowIndex];
|
||||
switch (subColIndex)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
effect.mEffectID = static_cast<short>(value.toInt());
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
effect.mSkill = static_cast<signed char>(value.toInt());
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
effect.mAttribute = static_cast<signed char>(value.toInt());
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
effect.mRange = value.toInt();
|
||||
break;
|
||||
}
|
||||
case 4: effect.mArea = value.toInt(); break;
|
||||
case 5: effect.mDuration = value.toInt(); break;
|
||||
case 6: effect.mMagnMin = value.toInt(); break;
|
||||
case 7: effect.mMagnMax = value.toInt(); break;
|
||||
default: throw std::runtime_error("Magic Effects subcolumn index out of range");
|
||||
}
|
||||
|
||||
magic.mEffects.mList[subRowIndex] = effect;
|
||||
|
||||
record.setModified (magic);
|
||||
}
|
||||
|
||||
virtual int getColumnsCount(const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
virtual int getRowsCount(const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return static_cast<int>(record.get().mEffects.mList.size());
|
||||
}
|
||||
};
|
||||
|
||||
class InfoListAdapter : public NestedColumnAdapter<Info>
|
||||
{
|
||||
public:
|
||||
InfoListAdapter ();
|
||||
|
||||
virtual void addRow(Record<Info>& record, int position) const;
|
||||
|
||||
virtual void removeRow(Record<Info>& record, int rowToRemove) const;
|
||||
|
||||
virtual void setTable(Record<Info>& record,
|
||||
const NestedTableWrapperBase& nestedTable) const;
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<Info>& record) const;
|
||||
|
||||
virtual QVariant getData(const Record<Info>& record,
|
||||
int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual void setData(Record<Info>& record,
|
||||
const QVariant& value, int subRowIndex, int subColIndex) const;
|
||||
|
||||
virtual int getColumnsCount(const Record<Info>& record) const;
|
||||
|
||||
virtual int getRowsCount(const Record<Info>& record) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H
|
@ -0,0 +1,17 @@
|
||||
#include "nestedcollection.hpp"
|
||||
|
||||
CSMWorld::NestedCollection::NestedCollection()
|
||||
{}
|
||||
|
||||
CSMWorld::NestedCollection::~NestedCollection()
|
||||
{}
|
||||
|
||||
int CSMWorld::NestedCollection::getNestedRowsCount(int row, int column) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CSMWorld::NestedCollection::getNestedColumnsCount(int row, int column) const
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
#ifndef CSM_WOLRD_NESTEDCOLLECTION_H
|
||||
#define CSM_WOLRD_NESTEDCOLLECTION_H
|
||||
|
||||
class QVariant;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class NestableColumn;
|
||||
struct NestedTableWrapperBase;
|
||||
|
||||
class NestedCollection
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
NestedCollection();
|
||||
virtual ~NestedCollection();
|
||||
|
||||
virtual void addNestedRow(int row, int col, int position) = 0;
|
||||
|
||||
virtual void removeNestedRows(int row, int column, int subRow) = 0;
|
||||
|
||||
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0;
|
||||
|
||||
virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn) = 0;
|
||||
|
||||
virtual NestedTableWrapperBase* nestedTable(int row, int column) const = 0;
|
||||
|
||||
virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable) = 0;
|
||||
|
||||
virtual int getNestedRowsCount(int row, int column) const;
|
||||
|
||||
virtual int getNestedColumnsCount(int row, int column) const;
|
||||
|
||||
virtual NestableColumn *getNestableColumn(int column) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CSM_WOLRD_NESTEDCOLLECTION_H
|
@ -0,0 +1,40 @@
|
||||
#ifndef CSM_WOLRD_NESTEDCOLUMNADAPTER_H
|
||||
#define CSM_WOLRD_NESTEDCOLUMNADAPTER_H
|
||||
|
||||
class QVariant;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct NestedTableWrapperBase;
|
||||
|
||||
template <typename ESXRecordT>
|
||||
struct Record;
|
||||
|
||||
template<typename ESXRecordT>
|
||||
class NestedColumnAdapter
|
||||
{
|
||||
public:
|
||||
|
||||
NestedColumnAdapter() {}
|
||||
|
||||
virtual ~NestedColumnAdapter() {}
|
||||
|
||||
virtual void addRow(Record<ESXRecordT>& record, int position) const = 0;
|
||||
|
||||
virtual void removeRow(Record<ESXRecordT>& record, int rowToRemove) const = 0;
|
||||
|
||||
virtual void setTable(Record<ESXRecordT>& record, const NestedTableWrapperBase& nestedTable) const = 0;
|
||||
|
||||
virtual NestedTableWrapperBase* table(const Record<ESXRecordT>& record) const = 0;
|
||||
|
||||
virtual QVariant getData(const Record<ESXRecordT>& record, int subRowIndex, int subColIndex) const = 0;
|
||||
|
||||
virtual void setData(Record<ESXRecordT>& record, const QVariant& value, int subRowIndex, int subColIndex) const = 0;
|
||||
|
||||
virtual int getColumnsCount(const Record<ESXRecordT>& record) const = 0;
|
||||
|
||||
virtual int getRowsCount(const Record<ESXRecordT>& record) const = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CSM_WOLRD_NESTEDCOLUMNADAPTER_H
|
@ -0,0 +1,175 @@
|
||||
#ifndef CSM_WOLRD_NESTEDIDCOLLECTION_H
|
||||
#define CSM_WOLRD_NESTEDIDCOLLECTION_H
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "nestedcollection.hpp"
|
||||
#include "nestedcoladapterimp.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class ESMReader;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct NestedTableWrapperBase;
|
||||
struct Cell;
|
||||
|
||||
template<typename T, typename AT>
|
||||
class IdCollection;
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
|
||||
class NestedIdCollection : public IdCollection<ESXRecordT, IdAccessorT>, public NestedCollection
|
||||
{
|
||||
std::map<const ColumnBase*, NestedColumnAdapter<ESXRecordT>* > mAdapters;
|
||||
|
||||
const NestedColumnAdapter<ESXRecordT>& getAdapter(const ColumnBase &column) const;
|
||||
|
||||
public:
|
||||
|
||||
NestedIdCollection ();
|
||||
~NestedIdCollection();
|
||||
|
||||
virtual void addNestedRow(int row, int column, int position);
|
||||
|
||||
virtual void removeNestedRows(int row, int column, int subRow);
|
||||
|
||||
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const;
|
||||
|
||||
virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn);
|
||||
|
||||
virtual NestedTableWrapperBase* nestedTable(int row, int column) const;
|
||||
|
||||
virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable);
|
||||
|
||||
virtual int getNestedRowsCount(int row, int column) const;
|
||||
|
||||
virtual int getNestedColumnsCount(int row, int column) const;
|
||||
|
||||
// this method is inherited from NestedCollection, not from Collection<ESXRecordT>
|
||||
virtual NestableColumn *getNestableColumn(int column);
|
||||
|
||||
void addAdapter(std::pair<const ColumnBase*, NestedColumnAdapter<ESXRecordT>* > adapter);
|
||||
};
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
NestedIdCollection<ESXRecordT, IdAccessorT>::NestedIdCollection ()
|
||||
{}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
NestedIdCollection<ESXRecordT, IdAccessorT>::~NestedIdCollection()
|
||||
{
|
||||
for (typename std::map<const ColumnBase *, NestedColumnAdapter<ESXRecordT>* >::iterator
|
||||
iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter)
|
||||
{
|
||||
delete (*iter).second;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::addAdapter(std::pair<const ColumnBase*,
|
||||
NestedColumnAdapter<ESXRecordT>* > adapter)
|
||||
{
|
||||
mAdapters.insert(adapter);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
const NestedColumnAdapter<ESXRecordT>& NestedIdCollection<ESXRecordT, IdAccessorT>::getAdapter(const ColumnBase &column) const
|
||||
{
|
||||
typename std::map<const ColumnBase *, NestedColumnAdapter<ESXRecordT>* >::const_iterator iter =
|
||||
mAdapters.find (&column);
|
||||
|
||||
if (iter==mAdapters.end())
|
||||
throw std::logic_error("No such column in the nestedidadapter");
|
||||
|
||||
return *iter->second;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::addNestedRow(int row, int column, int position)
|
||||
{
|
||||
Record<ESXRecordT> record;
|
||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||
|
||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).addRow(record, position);
|
||||
|
||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::removeNestedRows(int row, int column, int subRow)
|
||||
{
|
||||
Record<ESXRecordT> record;
|
||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||
|
||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).removeRow(record, subRow);
|
||||
|
||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
QVariant NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedData (int row,
|
||||
int column, int subRow, int subColumn) const
|
||||
{
|
||||
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).getData(
|
||||
Collection<ESXRecordT, IdAccessorT>::getRecord(row), subRow, subColumn);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::setNestedData(int row,
|
||||
int column, const QVariant& data, int subRow, int subColumn)
|
||||
{
|
||||
Record<ESXRecordT> record;
|
||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||
|
||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).setData(
|
||||
record, data, subRow, subColumn);
|
||||
|
||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
CSMWorld::NestedTableWrapperBase* NestedIdCollection<ESXRecordT, IdAccessorT>::nestedTable(int row,
|
||||
int column) const
|
||||
{
|
||||
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).table(
|
||||
Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void NestedIdCollection<ESXRecordT, IdAccessorT>::setNestedTable(int row,
|
||||
int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
||||
{
|
||||
Record<ESXRecordT> record;
|
||||
record.assign(Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||
|
||||
getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).setTable(
|
||||
record, nestedTable);
|
||||
|
||||
Collection<ESXRecordT, IdAccessorT>::setRecord(row, record);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedRowsCount(int row, int column) const
|
||||
{
|
||||
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).getRowsCount(
|
||||
Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const
|
||||
{
|
||||
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).getColumnsCount(
|
||||
Collection<ESXRecordT, IdAccessorT>::getRecord(row));
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
CSMWorld::NestableColumn *NestedIdCollection<ESXRecordT, IdAccessorT>::getNestableColumn(int column)
|
||||
{
|
||||
return Collection<ESXRecordT, IdAccessorT>::getNestableColumn(column);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CSM_WOLRD_NESTEDIDCOLLECTION_H
|
@ -0,0 +1,110 @@
|
||||
#include "nestedinfocollection.hpp"
|
||||
|
||||
#include "nestedcoladapterimp.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
NestedInfoCollection::NestedInfoCollection ()
|
||||
{}
|
||||
|
||||
NestedInfoCollection::~NestedInfoCollection()
|
||||
{
|
||||
for (std::map<const ColumnBase *, NestedColumnAdapter<Info>* >::iterator
|
||||
iter (mAdapters.begin()); iter!=mAdapters.end(); ++iter)
|
||||
{
|
||||
delete (*iter).second;
|
||||
}
|
||||
}
|
||||
|
||||
void NestedInfoCollection::addAdapter(std::pair<const ColumnBase*,
|
||||
NestedColumnAdapter<Info>* > adapter)
|
||||
{
|
||||
mAdapters.insert(adapter);
|
||||
}
|
||||
|
||||
const NestedColumnAdapter<Info>& NestedInfoCollection::getAdapter(const ColumnBase &column) const
|
||||
{
|
||||
std::map<const ColumnBase *, NestedColumnAdapter<Info>* >::const_iterator iter =
|
||||
mAdapters.find (&column);
|
||||
|
||||
if (iter==mAdapters.end())
|
||||
throw std::logic_error("No such column in the nestedidadapter");
|
||||
|
||||
return *iter->second;
|
||||
}
|
||||
|
||||
void NestedInfoCollection::addNestedRow(int row, int column, int position)
|
||||
{
|
||||
Record<Info> record;
|
||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||
|
||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).addRow(record, position);
|
||||
|
||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
||||
}
|
||||
|
||||
void NestedInfoCollection::removeNestedRows(int row, int column, int subRow)
|
||||
{
|
||||
Record<Info> record;
|
||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||
|
||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).removeRow(record, subRow);
|
||||
|
||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
||||
}
|
||||
|
||||
QVariant NestedInfoCollection::getNestedData (int row,
|
||||
int column, int subRow, int subColumn) const
|
||||
{
|
||||
return getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).getData(
|
||||
Collection<Info, IdAccessor<Info> >::getRecord(row), subRow, subColumn);
|
||||
}
|
||||
|
||||
void NestedInfoCollection::setNestedData(int row,
|
||||
int column, const QVariant& data, int subRow, int subColumn)
|
||||
{
|
||||
Record<Info> record;
|
||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||
|
||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).setData(
|
||||
record, data, subRow, subColumn);
|
||||
|
||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
||||
}
|
||||
|
||||
CSMWorld::NestedTableWrapperBase* NestedInfoCollection::nestedTable(int row,
|
||||
int column) const
|
||||
{
|
||||
return getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).table(
|
||||
Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||
}
|
||||
|
||||
void NestedInfoCollection::setNestedTable(int row,
|
||||
int column, const CSMWorld::NestedTableWrapperBase& nestedTable)
|
||||
{
|
||||
Record<Info> record;
|
||||
record.assign(Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||
|
||||
getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).setTable(
|
||||
record, nestedTable);
|
||||
|
||||
Collection<Info, IdAccessor<Info> >::setRecord(row, record);
|
||||
}
|
||||
|
||||
int NestedInfoCollection::getNestedRowsCount(int row, int column) const
|
||||
{
|
||||
return getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).getRowsCount(
|
||||
Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||
}
|
||||
|
||||
int NestedInfoCollection::getNestedColumnsCount(int row, int column) const
|
||||
{
|
||||
return getAdapter(Collection<Info, IdAccessor<Info> >::getColumn(column)).getColumnsCount(
|
||||
Collection<Info, IdAccessor<Info> >::getRecord(row));
|
||||
}
|
||||
|
||||
CSMWorld::NestableColumn *NestedInfoCollection::getNestableColumn(int column)
|
||||
{
|
||||
return Collection<Info, IdAccessor<Info> >::getNestableColumn(column);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
#ifndef CSM_WOLRD_NESTEDINFOCOLLECTION_H
|
||||
#define CSM_WOLRD_NESTEDINFOCOLLECTION_H
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "infocollection.hpp"
|
||||
#include "nestedcollection.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct NestedTableWrapperBase;
|
||||
|
||||
template<typename ESXRecordT>
|
||||
class NestedColumnAdapter;
|
||||
|
||||
class NestedInfoCollection : public InfoCollection, public NestedCollection
|
||||
{
|
||||
std::map<const ColumnBase*, NestedColumnAdapter<Info>* > mAdapters;
|
||||
|
||||
const NestedColumnAdapter<Info>& getAdapter(const ColumnBase &column) const;
|
||||
|
||||
public:
|
||||
|
||||
NestedInfoCollection ();
|
||||
~NestedInfoCollection();
|
||||
|
||||
virtual void addNestedRow(int row, int column, int position);
|
||||
|
||||
virtual void removeNestedRows(int row, int column, int subRow);
|
||||
|
||||
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const;
|
||||
|
||||
virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn);
|
||||
|
||||
virtual NestedTableWrapperBase* nestedTable(int row, int column) const;
|
||||
|
||||
virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable);
|
||||
|
||||
virtual int getNestedRowsCount(int row, int column) const;
|
||||
|
||||
virtual int getNestedColumnsCount(int row, int column) const;
|
||||
|
||||
// this method is inherited from NestedCollection, not from Collection<Info, IdAccessor<Info> >
|
||||
virtual NestableColumn *getNestableColumn(int column);
|
||||
|
||||
void addAdapter(std::pair<const ColumnBase*, NestedColumnAdapter<Info>* > adapter);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CSM_WOLRD_NESTEDINFOCOLLECTION_H
|
@ -0,0 +1,195 @@
|
||||
#include "nestedtableproxymodel.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include "idtree.hpp"
|
||||
|
||||
CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent,
|
||||
ColumnBase::Display columnId,
|
||||
CSMWorld::IdTree* parentModel)
|
||||
: mParentColumn(parent.column()),
|
||||
mMainModel(parentModel)
|
||||
{
|
||||
const int parentRow = parent.row();
|
||||
|
||||
mId = std::string(parentModel->index(parentRow, 0).data().toString().toUtf8());
|
||||
|
||||
QAbstractProxyModel::setSourceModel(parentModel);
|
||||
|
||||
connect(mMainModel, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(forwardRowsAboutToInserted(const QModelIndex &, int, int)));
|
||||
|
||||
connect(mMainModel, SIGNAL(rowsInserted(const QModelIndex &, int, int)),
|
||||
this, SLOT(forwardRowsInserted(const QModelIndex &, int, int)));
|
||||
|
||||
connect(mMainModel, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(forwardRowsAboutToRemoved(const QModelIndex &, int, int)));
|
||||
|
||||
connect(mMainModel, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
|
||||
this, SLOT(forwardRowsRemoved(const QModelIndex &, int, int)));
|
||||
|
||||
connect(mMainModel, SIGNAL(resetStart(const QString&)),
|
||||
this, SLOT(forwardResetStart(const QString&)));
|
||||
|
||||
connect(mMainModel, SIGNAL(resetEnd(const QString&)),
|
||||
this, SLOT(forwardResetEnd(const QString&)));
|
||||
|
||||
connect(mMainModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
|
||||
this, SLOT(forwardDataChanged(const QModelIndex &, const QModelIndex &)));
|
||||
}
|
||||
|
||||
QModelIndex CSMWorld::NestedTableProxyModel::mapFromSource(const QModelIndex& sourceIndex) const
|
||||
{
|
||||
const QModelIndex& testedParent = mMainModel->parent(sourceIndex);
|
||||
const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn);
|
||||
if (testedParent == parent)
|
||||
{
|
||||
return createIndex(sourceIndex.row(), sourceIndex.column());
|
||||
}
|
||||
else
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex CSMWorld::NestedTableProxyModel::mapToSource(const QModelIndex& proxyIndex) const
|
||||
{
|
||||
const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn);
|
||||
return mMainModel->index(proxyIndex.row(), proxyIndex.column(), parent);
|
||||
}
|
||||
|
||||
int CSMWorld::NestedTableProxyModel::rowCount(const QModelIndex& index) const
|
||||
{
|
||||
assert (!index.isValid());
|
||||
|
||||
return mMainModel->rowCount(mMainModel->getModelIndex(mId, mParentColumn));
|
||||
}
|
||||
|
||||
int CSMWorld::NestedTableProxyModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
assert (!parent.isValid());
|
||||
|
||||
return mMainModel->columnCount(mMainModel->getModelIndex(mId, mParentColumn));
|
||||
}
|
||||
|
||||
QModelIndex CSMWorld::NestedTableProxyModel::index(int row, int column, const QModelIndex& parent) const
|
||||
{
|
||||
assert (!parent.isValid());
|
||||
|
||||
int rows = mMainModel->rowCount(parent);
|
||||
int columns = mMainModel->columnCount(parent);
|
||||
|
||||
if (row < 0 || row >= rows || column < 0 || column >= columns)
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(row, column);
|
||||
}
|
||||
|
||||
QModelIndex CSMWorld::NestedTableProxyModel::parent(const QModelIndex& index) const
|
||||
{
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QVariant CSMWorld::NestedTableProxyModel::headerData(int section,
|
||||
Qt::Orientation orientation,
|
||||
int role) const
|
||||
{
|
||||
return mMainModel->nestedHeaderData(mParentColumn, section, orientation, role);
|
||||
}
|
||||
|
||||
QVariant CSMWorld::NestedTableProxyModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
return mMainModel->data(mapToSource(index), role);
|
||||
}
|
||||
|
||||
// NOTE: Due to mapToSouce(index) the dataChanged() signal resulting from setData() will have the
|
||||
// source model's index values. The indicies need to be converted to the proxy space values.
|
||||
// See forwardDataChanged()
|
||||
bool CSMWorld::NestedTableProxyModel::setData (const QModelIndex & index, const QVariant & value, int role)
|
||||
{
|
||||
return mMainModel->setData(mapToSource(index), value, role);
|
||||
}
|
||||
|
||||
Qt::ItemFlags CSMWorld::NestedTableProxyModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
return mMainModel->flags(mapToSource(index));
|
||||
}
|
||||
|
||||
std::string CSMWorld::NestedTableProxyModel::getParentId() const
|
||||
{
|
||||
return mId;
|
||||
}
|
||||
|
||||
int CSMWorld::NestedTableProxyModel::getParentColumn() const
|
||||
{
|
||||
return mParentColumn;
|
||||
}
|
||||
|
||||
CSMWorld::IdTree* CSMWorld::NestedTableProxyModel::model() const
|
||||
{
|
||||
return mMainModel;
|
||||
}
|
||||
|
||||
void CSMWorld::NestedTableProxyModel::forwardRowsAboutToInserted(const QModelIndex& parent,
|
||||
int first, int last)
|
||||
{
|
||||
if (indexIsParent(parent))
|
||||
{
|
||||
beginInsertRows(QModelIndex(), first, last);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMWorld::NestedTableProxyModel::forwardRowsInserted(const QModelIndex& parent, int first, int last)
|
||||
{
|
||||
if (indexIsParent(parent))
|
||||
{
|
||||
endInsertRows();
|
||||
}
|
||||
}
|
||||
|
||||
bool CSMWorld::NestedTableProxyModel::indexIsParent(const QModelIndex& index)
|
||||
{
|
||||
return (index.isValid() &&
|
||||
index.column() == mParentColumn &&
|
||||
mMainModel->data(mMainModel->index(index.row(), 0)).toString().toUtf8().constData() == mId);
|
||||
}
|
||||
|
||||
void CSMWorld::NestedTableProxyModel::forwardRowsAboutToRemoved(const QModelIndex& parent,
|
||||
int first, int last)
|
||||
{
|
||||
if (indexIsParent(parent))
|
||||
{
|
||||
beginRemoveRows(QModelIndex(), first, last);
|
||||
}
|
||||
}
|
||||
|
||||
void CSMWorld::NestedTableProxyModel::forwardRowsRemoved(const QModelIndex& parent, int first, int last)
|
||||
{
|
||||
if (indexIsParent(parent))
|
||||
{
|
||||
endRemoveRows();
|
||||
}
|
||||
}
|
||||
|
||||
void CSMWorld::NestedTableProxyModel::forwardResetStart(const QString& id)
|
||||
{
|
||||
if (id.toUtf8() == mId.c_str())
|
||||
beginResetModel();
|
||||
}
|
||||
|
||||
void CSMWorld::NestedTableProxyModel::forwardResetEnd(const QString& id)
|
||||
{
|
||||
if (id.toUtf8() == mId.c_str())
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& topLeft,
|
||||
const QModelIndex& bottomRight)
|
||||
{
|
||||
const QModelIndex& parent = mMainModel->getNestedModelIndex (mId, mParentColumn);
|
||||
|
||||
if (topLeft.column() <= parent.column() && bottomRight.column() >= parent.column())
|
||||
{
|
||||
emit dataChanged(index(0,0),
|
||||
index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1));
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
#ifndef CSM_WOLRD_NESTEDTABLEPROXYMODEL_H
|
||||
#define CSM_WOLRD_NESTEDTABLEPROXYMODEL_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QAbstractProxyModel>
|
||||
|
||||
#include "universalid.hpp"
|
||||
#include "columns.hpp"
|
||||
#include "columnbase.hpp"
|
||||
|
||||
/*! \brief
|
||||
* Proxy model used to connect view in the dialogue into the nested columns of the main model.
|
||||
*/
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class CollectionBase;
|
||||
struct RecordBase;
|
||||
class IdTree;
|
||||
|
||||
class NestedTableProxyModel : public QAbstractProxyModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
const int mParentColumn;
|
||||
IdTree* mMainModel;
|
||||
std::string mId;
|
||||
|
||||
public:
|
||||
NestedTableProxyModel(const QModelIndex& parent,
|
||||
ColumnBase::Display displayType,
|
||||
IdTree* parentModel);
|
||||
//parent is the parent of columns to work with. Columnid provides information about the column
|
||||
|
||||
std::string getParentId() const;
|
||||
|
||||
int getParentColumn() const;
|
||||
|
||||
CSMWorld::IdTree* model() const;
|
||||
|
||||
virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const;
|
||||
|
||||
virtual QModelIndex mapToSource(const QModelIndex& proxyIndex) const;
|
||||
|
||||
virtual int rowCount(const QModelIndex& parent) const;
|
||||
|
||||
virtual int columnCount(const QModelIndex& parent) const;
|
||||
|
||||
virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
|
||||
|
||||
virtual QModelIndex parent(const QModelIndex& index) const;
|
||||
|
||||
virtual QVariant headerData (int section, Qt::Orientation orientation, int role) const;
|
||||
|
||||
virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
|
||||
virtual bool setData (const QModelIndex & index, const QVariant & value, int role = Qt::EditRole);
|
||||
|
||||
virtual Qt::ItemFlags flags(const QModelIndex& index) const;
|
||||
|
||||
private:
|
||||
void setupHeaderVectors(ColumnBase::Display columnId);
|
||||
|
||||
bool indexIsParent(const QModelIndex& index);
|
||||
|
||||
private slots:
|
||||
void forwardRowsAboutToInserted(const QModelIndex & parent, int first, int last);
|
||||
|
||||
void forwardRowsInserted(const QModelIndex & parent, int first, int last);
|
||||
|
||||
void forwardRowsAboutToRemoved(const QModelIndex & parent, int first, int last);
|
||||
|
||||
void forwardRowsRemoved(const QModelIndex & parent, int first, int last);
|
||||
|
||||
void forwardResetStart(const QString& id);
|
||||
|
||||
void forwardResetEnd(const QString& id);
|
||||
|
||||
void forwardDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,12 @@
|
||||
#include "nestedtablewrapper.hpp"
|
||||
|
||||
CSMWorld::NestedTableWrapperBase::NestedTableWrapperBase()
|
||||
{}
|
||||
|
||||
CSMWorld::NestedTableWrapperBase::~NestedTableWrapperBase()
|
||||
{}
|
||||
|
||||
int CSMWorld::NestedTableWrapperBase::size() const
|
||||
{
|
||||
return -5;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
#ifndef CSM_WOLRD_NESTEDTABLEWRAPPER_H
|
||||
#define CSM_WOLRD_NESTEDTABLEWRAPPER_H
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct NestedTableWrapperBase
|
||||
{
|
||||
virtual ~NestedTableWrapperBase();
|
||||
|
||||
virtual int size() const;
|
||||
|
||||
NestedTableWrapperBase();
|
||||
};
|
||||
|
||||
template<typename NestedTable>
|
||||
struct NestedTableWrapper : public NestedTableWrapperBase
|
||||
{
|
||||
NestedTable mNestedTable;
|
||||
|
||||
NestedTableWrapper(const NestedTable& nestedTable)
|
||||
: mNestedTable(nestedTable) {}
|
||||
|
||||
virtual ~NestedTableWrapper() {}
|
||||
|
||||
virtual int size() const
|
||||
{
|
||||
return mNestedTable.size(); //i hope that this will be enough
|
||||
}
|
||||
};
|
||||
}
|
||||
#endif
|
@ -1,8 +1,18 @@
|
||||
|
||||
#include "ref.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
CSMWorld::CellRef::CellRef()
|
||||
{
|
||||
mRefNum.mIndex = 0;
|
||||
mRefNum.mContentFile = 0;
|
||||
}
|
||||
|
||||
std::pair<int, int> CSMWorld::CellRef::getCellIndex() const
|
||||
{
|
||||
const int cellSize = 8192;
|
||||
|
||||
return std::make_pair (
|
||||
std::floor (mPos.pos[0]/cellSize), std::floor (mPos.pos[1]/cellSize));
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
|
||||
#include "refidadapter.hpp"
|
||||
|
||||
CSMWorld::RefIdAdapter::RefIdAdapter() {}
|
||||
|
||||
CSMWorld::RefIdAdapter::~RefIdAdapter() {}
|
||||
|
||||
CSMWorld::NestedRefIdAdapterBase::NestedRefIdAdapterBase() {}
|
||||
|
||||
CSMWorld::NestedRefIdAdapterBase::~NestedRefIdAdapterBase() {}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,95 @@
|
||||
#include "nestedtable.hpp"
|
||||
#include "../../model/world/nestedtableproxymodel.hpp"
|
||||
#include "../../model/world/universalid.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/commanddispatcher.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QContextMenuEvent>
|
||||
#include <QMenu>
|
||||
#include <QDebug>
|
||||
|
||||
CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
|
||||
CSMWorld::UniversalId id,
|
||||
CSMWorld::NestedTableProxyModel* model,
|
||||
QWidget* parent)
|
||||
: QTableView(parent),
|
||||
mUndoStack(document.getUndoStack()),
|
||||
mModel(model)
|
||||
{
|
||||
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
|
||||
|
||||
setSelectionBehavior (QAbstractItemView::SelectRows);
|
||||
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||
|
||||
horizontalHeader()->setResizeMode (QHeaderView::Interactive);
|
||||
verticalHeader()->hide();
|
||||
|
||||
int columns = model->columnCount(QModelIndex());
|
||||
|
||||
for(int i = 0 ; i < columns; ++i)
|
||||
{
|
||||
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display> (
|
||||
model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display,
|
||||
mDispatcher,
|
||||
document,
|
||||
this);
|
||||
|
||||
setItemDelegateForColumn(i, delegate);
|
||||
}
|
||||
|
||||
setModel(model);
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
mAddNewRowAction = new QAction (tr ("Add new row"), this);
|
||||
|
||||
connect(mAddNewRowAction, SIGNAL(triggered()),
|
||||
this, SLOT(addNewRowActionTriggered()));
|
||||
|
||||
mRemoveRowAction = new QAction (tr ("Remove row"), this);
|
||||
|
||||
connect(mRemoveRowAction, SIGNAL(triggered()),
|
||||
this, SLOT(removeRowActionTriggered()));
|
||||
}
|
||||
|
||||
void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
}
|
||||
|
||||
void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event)
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
QMenu menu(this);
|
||||
|
||||
if (selectionModel()->selectedRows().size() == 1)
|
||||
menu.addAction(mRemoveRowAction);
|
||||
|
||||
menu.addAction(mAddNewRowAction);
|
||||
|
||||
menu.exec (event->globalPos());
|
||||
}
|
||||
|
||||
void CSVWorld::NestedTable::removeRowActionTriggered()
|
||||
{
|
||||
mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()),
|
||||
mModel->getParentId(),
|
||||
selectionModel()->selectedRows().begin()->row(),
|
||||
mModel->getParentColumn()));
|
||||
}
|
||||
|
||||
void CSVWorld::NestedTable::addNewRowActionTriggered()
|
||||
{
|
||||
mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()),
|
||||
mModel->getParentId(),
|
||||
selectionModel()->selectedRows().size(),
|
||||
mModel->getParentColumn()));
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
#ifndef CSV_WORLD_NESTEDTABLE_H
|
||||
#define CSV_WORLD_NESTEDTABLE_H
|
||||
|
||||
#include <QTableView>
|
||||
#include <QtGui/qevent.h>
|
||||
|
||||
class QUndoStack;
|
||||
class QAction;
|
||||
class QContextMenuEvent;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class NestedTableProxyModel;
|
||||
class UniversalId;
|
||||
class CommandDispatcher;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class NestedTable : public QTableView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QAction *mAddNewRowAction;
|
||||
QAction *mRemoveRowAction;
|
||||
QUndoStack& mUndoStack;
|
||||
CSMWorld::NestedTableProxyModel* mModel;
|
||||
CSMWorld::CommandDispatcher *mDispatcher;
|
||||
|
||||
public:
|
||||
NestedTable(CSMDoc::Document& document,
|
||||
CSMWorld::UniversalId id,
|
||||
CSMWorld::NestedTableProxyModel* model,
|
||||
QWidget* parent = NULL);
|
||||
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent *event);
|
||||
|
||||
void dragMoveEvent(QDragMoveEvent *event);
|
||||
|
||||
private:
|
||||
void contextMenuEvent (QContextMenuEvent *event);
|
||||
|
||||
private slots:
|
||||
void removeRowActionTriggered();
|
||||
|
||||
void addNewRowActionTriggered();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue