Reorganised class inheritance structure of collections, columns and idtable model.

test
cc9cii 10 years ago
parent ece34a1baa
commit 83bcc8d451

@ -18,15 +18,14 @@ opencs_hdrs_noqt (model/doc
opencs_units (model/world
idtable idtableproxymodel regionmap data commanddispatcher
idtablebase resourcetable nestedtableproxymodel
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree
)
opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedadapters
pathgrid landtexture land nestedtablewrapper nestedadapters nestedcollection nestablecolumn
)
opencs_hdrs_noqt (model/world

@ -1,9 +1,10 @@
#include "columnbase.hpp"
#include "columns.hpp"
CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags, bool canNest)
: mColumnId (columnId), mDisplayType (displayType), mFlags (flags), mCanNest(canNest)
CSMWorld::ColumnBase::ColumnBase (int columnId, Display displayType, int flags)
: mColumnId (columnId), mDisplayType (displayType), mFlags (flags)
{}
CSMWorld::ColumnBase::~ColumnBase() {}
@ -22,43 +23,3 @@ int CSMWorld::ColumnBase::getId() const
{
return mColumnId;
}
bool CSMWorld::NestColumn::canHaveNestedColumns() const
{
return mCanNest;
}
void CSMWorld::NestColumn::addNestedColumn(int columnId, Display displayType)
{
if (!mCanNest)
throw std::logic_error("Tried to nest inside of the non-nest column");
mNestedColumns.push_back(CSMWorld::NestedColumn(columnId, displayType, mFlags, this));
}
const CSMWorld::ColumnBase& CSMWorld::NestColumn::nestedColumn(int subColumn) const
{
if (!mCanNest)
throw std::logic_error("Tried to access nested column of the non-nest column");
return mNestedColumns.at(subColumn);
}
int CSMWorld::NestColumn::nestedColumnCount() const
{
if (!mCanNest)
throw std::logic_error("Tried to access number of the subcolumns in the non-nest column");
return mNestedColumns.size();
}
CSMWorld::NestColumn::NestColumn(int columnId, Display displayType, int flags, bool canNest)
: CSMWorld::ColumnBase(columnId, displayType, flags, canNest) {}
CSMWorld::NestedColumn::NestedColumn(int columnId, Display displayType, int flag, const CSMWorld::NestColumn* parent)
: mParent(parent), CSMWorld::ColumnBase(columnId, displayType, flag) {}
bool CSMWorld::NestedColumn::isEditable() const
{
return mParent->isEditable();
}

@ -3,7 +3,7 @@
#include <string>
#include <vector>
#include <exception>
#include <stdexcept>
#include <Qt>
#include <QVariant>
@ -117,9 +117,8 @@ namespace CSMWorld
int mColumnId;
int mFlags;
Display mDisplayType;
bool mCanNest;
ColumnBase (int columnId, Display displayType, int flag, bool canNest = false);
ColumnBase (int columnId, Display displayType, int flag);
virtual ~ColumnBase();
@ -133,39 +132,11 @@ namespace CSMWorld
virtual int getId() const;
};
class NestedColumn;
class NestColumn : public ColumnBase
{
std::vector<NestedColumn> mNestedColumns;
public:
NestColumn(int columnId, Display displayType, int flags, bool canNest);
void addNestedColumn(int columnId, Display displayType);
bool canHaveNestedColumns() const;
const ColumnBase& nestedColumn(int subColumn) const;
int nestedColumnCount() const;
};
class NestedColumn : public ColumnBase
{
const ColumnBase* mParent;
public:
NestedColumn(int columnId, Display displayType, int flag, const NestColumn* parent);
virtual bool isEditable() const;
};
template<typename ESXRecordT>
struct Column : public NestColumn
struct Column : public ColumnBase
{
Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue, bool canNest = false)
: NestColumn (columnId, displayType, flags, canNest) {}
Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue)
: ColumnBase (columnId, displayType, flags) {}
virtual QVariant get (const Record<ESXRecordT>& record) const = 0;

@ -3,6 +3,7 @@
#include <QAbstractItemModel>
#include "idtable.hpp"
#include "idtree.hpp"
#include <components/misc/stringops.hpp>
#include "nestedtablewrapper.hpp"
@ -172,10 +173,10 @@ void CSMWorld::CloneCommand::undo()
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
}
CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTable& model,
CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model,
const std::string& id,
int nestedRow,
int parentColumn,
int nestedRow,
int parentColumn,
QUndoCommand* parent) :
mId(id),
mModel(model),
@ -192,7 +193,7 @@ void CSMWorld::DeleteNestedCommand::redo()
const QModelIndex& parentIndex = mModel.getModelIndex(mId, mParentColumn);
mModel.removeRows (mNestedRow, 1, parentIndex);
}
}
void CSMWorld::DeleteNestedCommand::undo()
@ -202,7 +203,7 @@ void CSMWorld::DeleteNestedCommand::undo()
mModel.setNestedTable(parentIndex, getOld());
}
CSMWorld::AddNestedCommand::AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent)
CSMWorld::AddNestedCommand::AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent)
: mModel(model),
mId(id),
mNewRow(nestedRow),
@ -227,7 +228,7 @@ void CSMWorld::AddNestedCommand::undo()
mModel.setNestedTable(parentIndex, getOld());
}
CSMWorld::NestedTableStoring::NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn)
CSMWorld::NestedTableStoring::NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn)
: mOld(model.nestedTable(model.getModelIndex(id, parentColumn))) {}
CSMWorld::NestedTableStoring::~NestedTableStoring()

@ -10,7 +10,6 @@
#include <QVariant>
#include <QUndoCommand>
#include <QModelIndex>
#include <QVariant>
#include "universalid.hpp"
#include "nestedtablewrapper.hpp"
@ -21,7 +20,7 @@ class QAbstractItemModel;
namespace CSMWorld
{
class IdTable;
class IdTable;
class IdTree;
struct RecordBase;
class NestedTableWrapperBase;
@ -148,18 +147,18 @@ namespace CSMWorld
NestedTableWrapperBase* mOld;
public:
NestedTableStoring(const IdTable& model, const std::string& id, int parentColumn);
NestedTableStoring(const IdTree& model, const std::string& id, int parentColumn);
~NestedTableStoring();
protected:
const NestedTableWrapperBase& getOld() const;
};
class DeleteNestedCommand : public QUndoCommand, private NestedTableStoring
{
IdTable& mModel;
IdTree& mModel;
std::string mId;
@ -169,16 +168,16 @@ namespace CSMWorld
public:
DeleteNestedCommand (IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
DeleteNestedCommand (IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
virtual void redo();
virtual void undo();
};
class AddNestedCommand : public QUndoCommand, private NestedTableStoring
{
IdTable& mModel;
IdTree& mModel;
std::string mId;
@ -188,7 +187,7 @@ namespace CSMWorld
public:
AddNestedCommand(IdTable& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
AddNestedCommand(IdTree& model, const std::string& id, int nestedRow, int parentColumn, QUndoCommand* parent = 0);
virtual void redo();

@ -12,6 +12,7 @@
#include <components/esm/cellref.hpp>
#include "idtable.hpp"
#include "idtree.hpp"
#include "columnimp.hpp"
#include "regionmap.hpp"
#include "columns.hpp"
@ -332,7 +333,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect);
addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid);
addModel (new IdTable (&mStartScripts), UniversalId::Type_StartScript);
addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview),
addModel (new IdTree (&mReferenceables, IdTable::Feature_Preview),
UniversalId::Type_Referenceable);
addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference);
addModel (new IdTable (&mFilters), UniversalId::Type_Filter);

@ -1,12 +1,6 @@
#include "idtable.hpp"
#include <QDebug>
#include <cassert>
#include <iostream>
#include "nestedtablewrapper.hpp"
#include "collectionbase.hpp"
#include "nestedcollection.hpp"
#include "columnbase.hpp"
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
@ -14,26 +8,20 @@ CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
{}
CSMWorld::IdTable::~IdTable()
{
mIdCollection = 0; // FIXME: workaround only, should stop QHideEvent calling after destruction
}
{}
int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const
{
if (hasChildren(parent))
{
return dynamic_cast<NestedCollection*>(mIdCollection)->getNestedRowsCount(parent.row(), parent.column());
}
if (parent.isValid())
return 0;
return mIdCollection->getSize();
}
int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const
{
if (hasChildren(parent))
{
return dynamic_cast<NestedCollection*>(mIdCollection)->getNestedColumnsCount(parent.row(), parent.column());
}
if (parent.isValid())
return 0;
return mIdCollection->getColumns();
}
@ -46,23 +34,10 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable())
return QVariant();
if (index.internalId() != 0)
{
std::pair<int, int> parentAdress(unfoldIndexAdress(index.internalId()));
return dynamic_cast<NestedCollection*>(mIdCollection)->getNestedData(parentAdress.first,
parentAdress.second,
index.row(),
index.column());
}
else
{
return mIdCollection->getData (index.row(), index.column());
}
return mIdCollection->getData (index.row(), index.column());
}
QVariant CSMWorld::IdTable::headerData (int section,
Qt::Orientation orientation,
int role) const
QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation==Qt::Vertical)
return QVariant();
@ -74,63 +49,19 @@ QVariant CSMWorld::IdTable::headerData (int section,
return mIdCollection->getColumn (section).mFlags;
if (role==ColumnBase::Role_Display)
{
return mIdCollection->getColumn (section).mDisplayType;
}
return QVariant();
}
QVariant CSMWorld::IdTable::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const
{
// FIXME: workaround only, should stop QHideEvent calling after destruction
if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns())
return QVariant();
const NestColumn& parentColumn = dynamic_cast<const NestColumn&>(mIdCollection->getColumn(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 mIdCollection->getColumn (section).mFlags;
if (role==ColumnBase::Role_Display)
return parentColumn.nestedColumn(subSection).mDisplayType;
return QVariant();
}
bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value, int role)
{
if (index.internalId() != 0)
{
if (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole)
{
const std::pair<int, int>& parentAdress(unfoldIndexAdress(index.internalId()));
dynamic_cast<NestedCollection*>(mIdCollection)->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column());
emit dataChanged (CSMWorld::IdTable::index (parentAdress.first, 0),
CSMWorld::IdTable::index (parentAdress.second, mIdCollection->getColumns()-1));
return true;
}
else
{
return false;
}
}
if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole)
{
mIdCollection->setData (index.row(), index.column(), value);
emit dataChanged (CSMWorld::IdTable::index (index.row(), 0),
CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1));
CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1));
return true;
}
@ -150,56 +81,22 @@ Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const
bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& parent)
{
beginRemoveRows (parent, row, row+count-1);
if (parent.isValid())
{
for (int i = 0; i < count; ++i)
{
dynamic_cast<NestedCollection*>(mIdCollection)->removeNestedRows(parent.row(), parent.column(), row+i);
}
}
else
{
return false;
beginRemoveRows (parent, row, row+count-1);
beginRemoveRows (parent, row, row+count-1);
mIdCollection->removeRows (row, count);
}
mIdCollection->removeRows (row, count);
endRemoveRows();
emit dataChanged (CSMWorld::IdTable::index (parent.row(), 0),
CSMWorld::IdTable::index (parent.row(), mIdCollection->getColumns()-1));
return true;
}
void CSMWorld::IdTable::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);
dynamic_cast<NestedCollection*>(mIdCollection)->addNestedRow(row, parent.column(), position);
endInsertRows();
emit dataChanged (CSMWorld::IdTable::index (row, 0),
CSMWorld::IdTable::index (row, mIdCollection->getColumns()-1));
}
QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const
{
unsigned int encodedId = 0;
if (parent.isValid())
{
encodedId = this->foldIndexAdress(parent);
}
return QModelIndex();
if (row<0 || row>=mIdCollection->getSize())
return QModelIndex();
@ -207,24 +104,12 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa
if (column<0 || column>=mIdCollection->getColumns())
return QModelIndex();
return createIndex(row, column, encodedId);
return createIndex (row, column);
}
QModelIndex CSMWorld::IdTable::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(unfoldIndexAdress(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);
return QModelIndex();
}
void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type)
@ -346,66 +231,3 @@ int CSMWorld::IdTable::getColumnId(int column) const
{
return mIdCollection->getColumn(column).getId();
}
unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const
{
unsigned int out = index.row() * this->columnCount();
out += index.column();
return ++out;
}
std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (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);
}
bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const
{
return (index.isValid() &&
index.internalId() == 0 &&
mIdCollection->getColumn(index.column()).mCanNest &&
index.data().isValid());
}
void CSMWorld::IdTable::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;
}
dynamic_cast<NestedCollection*>(mIdCollection)->setNestedTable(index.row(), index.column(), nestedTable);
emit dataChanged (CSMWorld::IdTable::index (index.row(), 0),
CSMWorld::IdTable::index (index.row(), mIdCollection->getColumns()-1));
if (removeRowsMode)
{
emit resetEnd(this->index(index.row(), 0).data().toString());
}
}
CSMWorld::NestedTableWrapperBase* CSMWorld::IdTable::nestedTable(const QModelIndex& index) const
{
if (!hasChildren(index))
{
throw std::logic_error("Tried to retrive nested table, but index has no children");
}
return dynamic_cast<NestedCollection*>(mIdCollection)->nestedTable(index.row(), index.column());
}

@ -7,20 +7,10 @@
#include "universalid.hpp"
#include "columns.hpp"
/*! \brief
* Clas 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 CollectionBase;
struct RecordBase;
class NestedTableWrapperBase;
class IdTable : public IdTableBase
{
@ -33,8 +23,6 @@ namespace CSMWorld
// not implemented
IdTable (const IdTable&);
IdTable& operator= (const IdTable&);
unsigned int foldIndexAdress(const QModelIndex& index) const;
std::pair<int, int> unfoldIndexAdress(unsigned int id) const;
public:
@ -51,27 +39,17 @@ namespace CSMWorld
virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) 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);
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());
void addNestedRow (const QModelIndex& parent, int position);
virtual QModelIndex index (int row, int column, const QModelIndex& parent = QModelIndex())
const;
virtual QModelIndex parent (const QModelIndex& index) const;
virtual bool hasChildren (const QModelIndex& index) const;
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types
@ -105,11 +83,6 @@ namespace CSMWorld
virtual bool isDeleted (const std::string& id) const;
int getColumnId(int column) const;
signals:
void resetStart(const QString& id);
void resetEnd(const QString& id);
};
}

@ -0,0 +1,296 @@
#include "idtree.hpp"
#include "nestedtablewrapper.hpp" // FIXME: is this necessary?
#include "nestedcollection.hpp"
#include "nestablecolumn.hpp"
CSMWorld::IdTree::IdTree (NestedCollection *idCollection, unsigned int features)
: IdTable (idCollection, features), mIdCollection (idCollection)
{}
CSMWorld::IdTree::~IdTree()
{
// FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction
mIdCollection = 0;
}
int CSMWorld::IdTree::rowCount (const QModelIndex & parent) const
{
if (hasChildren(parent))
return mIdCollection->getNestedRowsCount(parent.row(), parent.column());
return mIdCollection->getSize();
}
int CSMWorld::IdTree::columnCount (const QModelIndex & parent) const
{
if (hasChildren(parent))
return mIdCollection->getNestedColumnsCount(parent.row(), parent.column());
return mIdCollection->getColumns();
}
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 (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable())
return QVariant();
if (index.internalId() != 0)
{
std::pair<int, int> parentAdress(unfoldIndexAdress(index.internalId()));
return mIdCollection->getNestedData(parentAdress.first,
parentAdress.second, index.row(), index.column());
}
else
return mIdCollection->getData (index.row(), index.column());
}
QVariant CSMWorld::IdTree::headerData (int section, Qt::Orientation orientation, int role) const
{
if (orientation==Qt::Vertical)
return QVariant();
if (orientation != Qt::Horizontal)
throw std::logic_error("Unknown header orientation specified");
if (role == Qt::DisplayRole)
return tr (mIdCollection->getColumn (section).getTitle().c_str());
if (role == ColumnBase::Role_Flags)
return mIdCollection->getColumn (section).mFlags;
if (role == ColumnBase::Role_Display)
return mIdCollection->getColumn (section).mDisplayType;
return QVariant();
}
QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Orientation orientation, int role) const
{
// FIXME: workaround only, a proper fix should stop QHideEvent calls after destruction
if (section < 0 || !mIdCollection || section >= mIdCollection->getColumns())
return QVariant();
// FIXME: dynamic cast
const NestableColumn& parentColumn = dynamic_cast<const NestableColumn&>(mIdCollection->getColumn(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 mIdCollection->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 (mIdCollection->getColumn(parent(index).column()).isEditable() && role==Qt::EditRole)
{
const std::pair<int, int>& parentAdress(unfoldIndexAdress(index.internalId()));
mIdCollection->setNestedData(parentAdress.first, parentAdress.second, value, index.row(), index.column());
emit dataChanged (CSMWorld::IdTree::index (parentAdress.first, 0),
CSMWorld::IdTree::index (parentAdress.second, mIdCollection->getColumns()-1));
return true;
}
else
return false;
}
if (mIdCollection->getColumn (index.column()).isEditable() && role==Qt::EditRole)
{
mIdCollection->setData (index.row(), index.column(), value);
emit dataChanged (CSMWorld::IdTree::index (index.row(), 0),
CSMWorld::IdTree::index (index.row(), mIdCollection->getColumns()-1));
return true;
}
return false;
}
Qt::ItemFlags CSMWorld::IdTree::flags (const QModelIndex & index) const
{
if (!index.isValid())
return 0;
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (mIdCollection->getColumn (index.column()).isUserEditable())
flags |= Qt::ItemIsEditable;
return flags;
}
bool CSMWorld::IdTree::removeRows (int row, int count, const QModelIndex& parent)
{
beginRemoveRows (parent, row, row+count-1);
if (parent.isValid())
{
for (int i = 0; i < count; ++i)
{
mIdCollection->removeNestedRows(parent.row(), parent.column(), row+i);
}
}
else
{
beginRemoveRows (parent, row, row+count-1);
mIdCollection->removeRows (row, count);
}
endRemoveRows();
emit dataChanged (CSMWorld::IdTree::index (parent.row(), 0),
CSMWorld::IdTree::index (parent.row(), mIdCollection->getColumns()-1));
return true;
}
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);
mIdCollection->addNestedRow(row, parent.column(), position);
endInsertRows();
emit dataChanged (CSMWorld::IdTree::index (row, 0),
CSMWorld::IdTree::index (row, mIdCollection->getColumns()-1));
}
QModelIndex CSMWorld::IdTree::index (int row, int column, const QModelIndex& parent) const
{
unsigned int encodedId = 0;
if (parent.isValid())
{
encodedId = this->foldIndexAdress(parent);
}
if (row<0 || row>=mIdCollection->getSize())
return QModelIndex();
if (column<0 || column>=mIdCollection->getColumns())
return QModelIndex();
return createIndex(row, column, encodedId); // store internal id
}
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(unfoldIndexAdress(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);
}
void CSMWorld::IdTree::setRecord (const std::string& id, const RecordBase& record)
{
int index = mIdCollection->searchId (id);
if (index==-1)
{
int index = mIdCollection->getAppendIndex (id);
beginInsertRows (QModelIndex(), index, index);
mIdCollection->appendRecord (record);
endInsertRows();
}
else
{
mIdCollection->replace (index, record);
emit dataChanged (CSMWorld::IdTree::index (index, 0),
CSMWorld::IdTree::index (index, mIdCollection->getColumns()-1));
}
}
unsigned int CSMWorld::IdTree::foldIndexAdress (const QModelIndex& index) const
{
unsigned int out = index.row() * this->columnCount();
out += index.column();
return ++out;
}
std::pair< int, int > CSMWorld::IdTree::unfoldIndexAdress (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);
}
bool CSMWorld::IdTree::hasChildren(const QModelIndex& index) const
{
// FIXME: dynamic cast
return (index.isValid() &&
index.internalId() == 0 &&
dynamic_cast<const CSMWorld::NestableColumn &>(mIdCollection->getColumn(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;
}
mIdCollection->setNestedTable(index.row(), index.column(), nestedTable);
emit dataChanged (CSMWorld::IdTree::index (index.row(), 0),
CSMWorld::IdTree::index (index.row(), mIdCollection->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 mIdCollection->nestedTable(index.row(), index.column());
}

@ -0,0 +1,88 @@
#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;
class NestedTableWrapperBase; // FIXME: is this necessary?
class IdTree : public IdTable // IdTable is derived from QAbstractItemModel
{
Q_OBJECT
private:
NestedCollection *mIdCollection;
// not implemented
IdTree (const IdTree&);
IdTree& operator= (const IdTree&);
unsigned int foldIndexAdress(const QModelIndex& index) const;
std::pair<int, int> unfoldIndexAdress(unsigned int id) const;
public:
IdTree (NestedCollection *idCollection, unsigned int features = 0);
///< The ownership of \a idCollection is 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 QVariant headerData (int section, Qt::Orientation orientation, 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;
void setRecord (const std::string& id, const RecordBase& record);
///< Add record or overwrite existing recrod.
// TODO: check if below methods are really needed
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,44 @@
#include "nestablecolumn.hpp"
#include <stdexcept>
void CSMWorld::NestableColumn::addColumn(CSMWorld::NestableColumn *column)
{
mNestedColumns.push_back(column);
mHasChildren = true;
}
const CSMWorld::ColumnBase& CSMWorld::NestableColumn::nestedColumn(int subColumn) const
{
if (!mHasChildren)
throw std::logic_error("Tried to access nested column of the non-nest column");
return *mNestedColumns.at(subColumn);
}
int CSMWorld::NestableColumn::nestedColumnCount() const
{
if (!mHasChildren)
throw std::logic_error("Tried to access number of the subcolumns in the non-nest column");
return mNestedColumns.size();
}
CSMWorld::NestableColumn::NestableColumn(int columnId, CSMWorld::ColumnBase::Display displayType,
int flag, const CSMWorld::NestableColumn* parent)
: mParent(parent), mHasChildren(false), CSMWorld::ColumnBase(columnId, displayType, flag)
{
}
CSMWorld::NestableColumn::~NestableColumn()
{
for (unsigned int i = 0; i < mNestedColumns.size(); ++i)
{
delete mNestedColumns[i];
}
}
bool CSMWorld::NestableColumn::hasChildren() const
{
return mHasChildren;
}

@ -0,0 +1,33 @@
#ifndef CSM_WOLRD_NESTABLECOLUMN_H
#define CSM_WOLRD_NESTABLECOLUMN_H
#include <vector>
#include "columnbase.hpp"
namespace CSMWorld
{
class NestableColumn : public ColumnBase
{
std::vector<NestableColumn *> mNestedColumns;
const NestableColumn* mParent;
bool mHasChildren; // cached
public:
NestableColumn(int columnId,
Display displayType, int flag, const NestableColumn* parent = 0);
~NestableColumn();
void addColumn(CSMWorld::NestableColumn *column);
const ColumnBase& nestedColumn(int subColumn) const;
int nestedColumnCount() const;
bool hasChildren() const;
};
}
#endif

@ -1,6 +1,8 @@
#ifndef CSM_WOLRD_NESTEDCOLLECTION_H
#define CSM_WOLRD_NESTEDCOLLECTION_H
#include <vector>
#include "collectionbase.hpp"
class QVariant;
@ -11,7 +13,12 @@ namespace CSMWorld
class NestedCollection : public CollectionBase
{
public:
NestedCollection();
virtual ~NestedCollection();
virtual void addNestedRow(int row, int col, int position) = 0;
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0;
@ -28,7 +35,10 @@ namespace CSMWorld
virtual void removeNestedRows(int row, int column, int subRow) = 0;
private:
std::vector<NestedCollection *> mChildren;
NestedCollection *mParent; // currently unused
};
}

@ -1,11 +1,11 @@
#include "nestedtableproxymodel.hpp"
#include <cassert>
#include "idtable.hpp"
#include "idtree.hpp"
CSMWorld::NestedTableProxyModel::NestedTableProxyModel(const QModelIndex& parent,
ColumnBase::Display columnId,
CSMWorld::IdTable* parentModel)
CSMWorld::IdTree* parentModel)
: mParentColumn(parent.column()),
mMainModel(parentModel)
{
@ -119,7 +119,7 @@ int CSMWorld::NestedTableProxyModel::getParentColumn() const
return mParentColumn;
}
CSMWorld::IdTable* CSMWorld::NestedTableProxyModel::model() const
CSMWorld::IdTree* CSMWorld::NestedTableProxyModel::model() const
{
return mMainModel;
}

@ -17,27 +17,27 @@ namespace CSMWorld
{
class CollectionBase;
class RecordBase;
class IdTable;
class IdTree;
class NestedTableProxyModel : public QAbstractProxyModel
{
Q_OBJECT
const int mParentColumn;
IdTable* mMainModel;
IdTree* mMainModel;
std::string mId;
public:
NestedTableProxyModel(const QModelIndex& parent,
ColumnBase::Display displayType,
IdTable* parentModel);
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::IdTable* model() const;
CSMWorld::IdTree* model() const;
virtual QModelIndex mapFromSource(const QModelIndex& sourceIndex) const;

@ -2,18 +2,17 @@
#include <stdexcept>
#include <memory>
#include <QDebug>
#include <components/esm/esmreader.hpp>
#include "refidadapter.hpp"
#include "refidadapterimp.hpp"
#include "columns.hpp"
#include "nestedtablewrapper.hpp"
#include "nestedtablewrapper.hpp" // FIXME: is this really necessary?
CSMWorld::RefIdColumn::RefIdColumn (int columnId, Display displayType, int flag,
bool editable, bool userEditable, bool canNest)
: NestColumn (columnId, displayType, flag, canNest), mEditable (editable), mUserEditable (userEditable)
bool editable, bool userEditable)
: NestableColumn (columnId, displayType, flag), mEditable (editable), mUserEditable (userEditable)
{}
bool CSMWorld::RefIdColumn::isEditable() const
@ -27,7 +26,8 @@ bool CSMWorld::RefIdColumn::isUserEditable() const
}
CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const
// FIXME: const problem
/*const*/ CSMWorld::RefIdAdapter& CSMWorld::RefIdCollection::findAdapter (UniversalId::Type type) const
{
std::map<UniversalId::Type, RefIdAdapter *>::const_iterator iter = mAdapters.find (type);
@ -99,14 +99,19 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_AiAlarm, ColumnBase::Display_Integer));
actorsColumns.mAlarm = &mColumns.back();
mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorInventory, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue));
actorsColumns.mInventory = &mColumns.back();
mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String);
mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer);
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue, true, true, true));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_ActorSpells, ColumnBase::Display_NestedSpellList, ColumnBase::Flag_Dialogue));
actorsColumns.mSpells = &mColumns.back();
mColumns.back().addNestedColumn(Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String);
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String));
static const struct
{
@ -175,10 +180,13 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean));
const RefIdColumn *respawn = &mColumns.back();
mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue, true, true, true));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_NestedItemList, ColumnBase::Flag_Dialogue));
const RefIdColumn *content = &mColumns.back();
mColumns.back().addNestedColumn(Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String);
mColumns.back().addNestedColumn(Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer);
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
CreatureColumns creatureColumns (actorsColumns);
@ -315,16 +323,24 @@ CSMWorld::RefIdCollection::RefIdCollection()
npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal));
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue, true, true, true));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, ColumnBase::Display_NestedDestinationsList, ColumnBase::Flag_Dialogue));
npcColumns.mDestinations = &mColumns.back();
mColumns.back().addNestedColumn(Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String);
mColumns.back().addNestedColumn(Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float);
mColumns.back().addNestedColumn(Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float);
mColumns.back().addNestedColumn(Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float);
mColumns.back().addNestedColumn(Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float);
mColumns.back().addNestedColumn(Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float);
mColumns.back().addNestedColumn(Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float);
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PosY, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PosZ, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_RotX, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_RotY, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_RotZ, CSMWorld::ColumnBase::Display_Float));
WeaponColumns weaponColumns (enchantableColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType));
@ -664,8 +680,10 @@ void CSMWorld::RefIdCollection::setNestedTable(int row, int column, const CSMWor
{
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (row);
// FIXME: const problem
CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast<CSMWorld::NestedRefIdAdapter&>(findAdapter (localIndex.second));
// FIXME: const problem
adaptor.setNestedTable(&mColumns.at(column), mData, localIndex.first, nestedTable);
}

@ -5,8 +5,7 @@
#include <map>
#include <deque>
#include "columnbase.hpp"
#include "collectionbase.hpp"
#include "nestablecolumn.hpp"
#include "nestedcollection.hpp"
#include "refiddata.hpp"
@ -18,9 +17,9 @@ namespace ESM
namespace CSMWorld
{
class RefIdAdapter;
class NestedTableWrapperBase;
class NestedTableWrapperBase; // FIXME: is this really needed?
class RefIdColumn : public NestColumn
class RefIdColumn : public NestableColumn
{
bool mEditable;
bool mUserEditable;
@ -29,7 +28,7 @@ namespace CSMWorld
RefIdColumn (int columnId, Display displayType,
int flag = Flag_Table | Flag_Dialogue, bool editable = true,
bool userEditable = true, bool canNest = false);
bool userEditable = true);
virtual bool isEditable() const;
@ -46,7 +45,7 @@ namespace CSMWorld
private:
RefIdAdapter& findAdapter (UniversalId::Type) const;
/*const*/ RefIdAdapter& findAdapter (UniversalId::Type) const;
///< Throws an exception if no adaptor for \a Type can be found.
public:
@ -57,10 +56,6 @@ namespace CSMWorld
virtual int getSize() const;
virtual int getNestedRowsCount(int row, int column) const;
virtual int getNestedColumnsCount(int row, int column) const;
virtual std::string getId (int index) const;
virtual int getIndex (const std::string& id) const;
@ -71,22 +66,10 @@ namespace CSMWorld
virtual QVariant getData (int index, int column) const;
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const;
virtual NestedTableWrapperBase* nestedTable(int row, int column) const;
virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable);
virtual void setData (int index, int column, const QVariant& data);
virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn);
virtual void removeRows (int index, int count);
virtual void removeNestedRows(int row, int column, int subRow);
virtual void addNestedRow(int row, int col, int position);
virtual void cloneRecord(const std::string& origin,
const std::string& destination,
const UniversalId::Type type);
@ -128,6 +111,24 @@ namespace CSMWorld
///
/// \return Success?
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const;
virtual NestedTableWrapperBase* nestedTable(int row, int column) const;
virtual void setNestedTable(int row, int column, const NestedTableWrapperBase& nestedTable);
// FIXME
virtual int getNestedRowsCount(int row, int column) const;
// FIXME
virtual int getNestedColumnsCount(int row, int column) const;
virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn);
virtual void removeNestedRows(int row, int column, int subRow);
virtual void addNestedRow(int row, int col, int position);
void save (int index, ESM::ESMWriter& writer) const;
const RefIdData& getDataSet() const; //I can't figure out a better name for this one :(

@ -52,7 +52,7 @@ namespace CSMWorld
virtual void load (int index, ESM::ESMReader& reader, bool base) = 0;
virtual void erase (int index, int count) = 0;
virtual std::string getId (int index) const = 0;
virtual void save (int index, ESM::ESMWriter& writer) const = 0;
@ -134,7 +134,7 @@ namespace CSMWorld
throw std::runtime_error ("invalid RefIdDataContainer index");
mContainer.erase (mContainer.begin()+index, mContainer.begin()+index+count);
}
}
template<typename RecordT>
std::string RefIdDataContainer<RecordT>::getId (int index) const
@ -231,7 +231,7 @@ namespace CSMWorld
void save (int index, ESM::ESMWriter& writer) const;
//RECORD CONTAINERS ACCESS METHODS
//RECORD CONTAINERS ACCESS METHODS
const RefIdDataContainer<ESM::Book>& getBooks() const;
const RefIdDataContainer<ESM::Activator>& getActivators() const;
const RefIdDataContainer<ESM::Potion>& getPotions() const;

@ -26,6 +26,7 @@
#include "../../model/world/nestedtableproxymodel.hpp"
#include "../../model/world/columnbase.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idtree.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/record.hpp"
#include "../../model/world/tablemimedata.hpp"
@ -422,7 +423,7 @@ void CSVWorld::EditWidget::remake(int row)
if (mTable->hasChildren(mTable->index(row, i)))
{
mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, mTable));
mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast<CSMWorld::IdTree*>(mTable)));
NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this);

Loading…
Cancel
Save