mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2455 lines
95 KiB
C++
2455 lines
95 KiB
C++
#ifndef CSM_WOLRD_REFIDADAPTERIMP_H
|
|
#define CSM_WOLRD_REFIDADAPTERIMP_H
|
|
|
|
#include <algorithm>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <QVariant>
|
|
|
|
#include <components/esm/defs.hpp>
|
|
#include <components/esm/esmcommon.hpp>
|
|
#include <components/esm3/aipackage.hpp>
|
|
#include <components/esm3/loadalch.hpp>
|
|
#include <components/esm3/loadappa.hpp>
|
|
#include <components/esm3/loadarmo.hpp>
|
|
#include <components/esm3/loadbook.hpp>
|
|
#include <components/esm3/loadclot.hpp>
|
|
#include <components/esm3/loadcont.hpp>
|
|
#include <components/esm3/loadcrea.hpp>
|
|
#include <components/esm3/loaddoor.hpp>
|
|
#include <components/esm3/loadingr.hpp>
|
|
#include <components/esm3/loadlevlist.hpp>
|
|
#include <components/esm3/loadligh.hpp>
|
|
#include <components/esm3/loadmisc.hpp>
|
|
#include <components/esm3/loadnpc.hpp>
|
|
#include <components/esm3/loadweap.hpp>
|
|
#include <components/esm3/transport.hpp>
|
|
|
|
#include "columnbase.hpp"
|
|
#include "nestedtablewrapper.hpp"
|
|
#include "record.hpp"
|
|
#include "refidadapter.hpp"
|
|
#include "refiddata.hpp"
|
|
#include "universalid.hpp"
|
|
|
|
namespace CSMWorld
|
|
{
|
|
class RefIdColumn;
|
|
struct BaseColumns
|
|
{
|
|
const RefIdColumn* mId;
|
|
const RefIdColumn* mModified;
|
|
const RefIdColumn* mType;
|
|
const RefIdColumn* mBlocked;
|
|
|
|
BaseColumns()
|
|
: mId(nullptr)
|
|
, mModified(nullptr)
|
|
, mType(nullptr)
|
|
, mBlocked(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
/// \brief Base adapter for all refereceable record types
|
|
/// Adapters that can handle nested tables, needs to return valid qvariant for parent columns
|
|
template <typename RecordT>
|
|
class BaseRefIdAdapter : public RefIdAdapter
|
|
{
|
|
UniversalId::Type mType;
|
|
BaseColumns mBase;
|
|
|
|
public:
|
|
BaseRefIdAdapter(UniversalId::Type type, const BaseColumns& base);
|
|
|
|
ESM::RefId getId(const RecordBase& record) const override;
|
|
|
|
void setId(RecordBase& record, const std::string& id) override;
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
|
|
UniversalId::Type getType() const;
|
|
};
|
|
|
|
template <typename RecordT>
|
|
BaseRefIdAdapter<RecordT>::BaseRefIdAdapter(UniversalId::Type type, const BaseColumns& base)
|
|
: mType(type)
|
|
, mBase(base)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void BaseRefIdAdapter<RecordT>::setId(RecordBase& record, const std::string& id)
|
|
{
|
|
(dynamic_cast<Record<RecordT>&>(record).get().mId) = ESM::RefId::stringRefId(id);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
ESM::RefId BaseRefIdAdapter<RecordT>::getId(const RecordBase& record) const
|
|
{
|
|
return dynamic_cast<const Record<RecordT>&>(record).get().mId;
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant BaseRefIdAdapter<RecordT>::getData(const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
const Record<RecordT>& record
|
|
= static_cast<const Record<RecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
if (column == mBase.mId)
|
|
return QString::fromStdString(record.get().mId.toString());
|
|
|
|
if (column == mBase.mModified)
|
|
{
|
|
if (record.mState == Record<RecordT>::State_Erased)
|
|
return static_cast<int>(Record<RecordT>::State_Deleted);
|
|
|
|
return static_cast<int>(record.mState);
|
|
}
|
|
|
|
if (column == mBase.mType)
|
|
return static_cast<int>(mType);
|
|
|
|
if (column == mBase.mBlocked)
|
|
return (record.get().mRecordFlags & ESM::FLAG_Blocked) != 0;
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void BaseRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
Record<RecordT>& record = static_cast<Record<RecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
if (column == mBase.mModified)
|
|
record.mState = static_cast<RecordBase::State>(value.toInt());
|
|
else if (column == mBase.mBlocked)
|
|
{
|
|
RecordT record2 = record.get();
|
|
|
|
if (value.toInt() != 0)
|
|
record2.mRecordFlags |= ESM::FLAG_Blocked;
|
|
else
|
|
record2.mRecordFlags &= ~ESM::FLAG_Blocked;
|
|
|
|
record.setModified(record2);
|
|
}
|
|
}
|
|
|
|
template <typename RecordT>
|
|
UniversalId::Type BaseRefIdAdapter<RecordT>::getType() const
|
|
{
|
|
return mType;
|
|
}
|
|
|
|
// NOTE: Body Part should not have persistence (but BodyPart is not listed in the Objects
|
|
// table at the moment).
|
|
//
|
|
// Spellmaking - not persistent - currently not part of objects table
|
|
// Enchanting - not persistent - currently not part of objects table
|
|
//
|
|
// Leveled Creature - no model, so not persistent
|
|
// Leveled Item - no model, so not persistent
|
|
|
|
struct ModelColumns : public BaseColumns
|
|
{
|
|
const RefIdColumn* mModel;
|
|
const RefIdColumn* mPersistence;
|
|
|
|
ModelColumns(const BaseColumns& base)
|
|
: BaseColumns(base)
|
|
, mModel(nullptr)
|
|
, mPersistence(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
/// \brief Adapter for IDs with models (all but levelled lists)
|
|
template <typename RecordT>
|
|
class ModelRefIdAdapter : public BaseRefIdAdapter<RecordT>
|
|
{
|
|
ModelColumns mModel;
|
|
|
|
public:
|
|
ModelRefIdAdapter(UniversalId::Type type, const ModelColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
template <typename RecordT>
|
|
ModelRefIdAdapter<RecordT>::ModelRefIdAdapter(UniversalId::Type type, const ModelColumns& columns)
|
|
: BaseRefIdAdapter<RecordT>(type, columns)
|
|
, mModel(columns)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant ModelRefIdAdapter<RecordT>::getData(const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
const Record<RecordT>& record = static_cast<const Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
if (column == mModel.mModel)
|
|
return QString::fromUtf8(record.get().mModel.c_str());
|
|
|
|
if (column == mModel.mPersistence)
|
|
return (record.get().mRecordFlags & ESM::FLAG_Persistent) != 0;
|
|
|
|
return BaseRefIdAdapter<RecordT>::getData(column, data, index);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void ModelRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
Record<RecordT>& record = static_cast<Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
RecordT record2 = record.get();
|
|
if (column == mModel.mModel)
|
|
record2.mModel = value.toString().toUtf8().constData();
|
|
else if (column == mModel.mPersistence)
|
|
{
|
|
if (value.toInt() != 0)
|
|
record2.mRecordFlags |= ESM::FLAG_Persistent;
|
|
else
|
|
record2.mRecordFlags &= ~ESM::FLAG_Persistent;
|
|
}
|
|
else
|
|
{
|
|
BaseRefIdAdapter<RecordT>::setData(column, data, index, value);
|
|
return;
|
|
}
|
|
|
|
record.setModified(record2);
|
|
}
|
|
|
|
struct NameColumns : public ModelColumns
|
|
{
|
|
const RefIdColumn* mName;
|
|
const RefIdColumn* mScript;
|
|
|
|
NameColumns(const ModelColumns& base)
|
|
: ModelColumns(base)
|
|
, mName(nullptr)
|
|
, mScript(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
/// \brief Adapter for IDs with names (all but levelled lists and statics)
|
|
template <typename RecordT>
|
|
class NameRefIdAdapter : public ModelRefIdAdapter<RecordT>
|
|
{
|
|
NameColumns mName;
|
|
|
|
public:
|
|
NameRefIdAdapter(UniversalId::Type type, const NameColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
template <typename RecordT>
|
|
NameRefIdAdapter<RecordT>::NameRefIdAdapter(UniversalId::Type type, const NameColumns& columns)
|
|
: ModelRefIdAdapter<RecordT>(type, columns)
|
|
, mName(columns)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant NameRefIdAdapter<RecordT>::getData(const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
const Record<RecordT>& record = static_cast<const Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
if (column == mName.mName)
|
|
return QString::fromUtf8(record.get().mName.c_str());
|
|
|
|
if (column == mName.mScript)
|
|
return QString::fromUtf8(record.get().mScript.getRefIdString().c_str());
|
|
|
|
return ModelRefIdAdapter<RecordT>::getData(column, data, index);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void NameRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
Record<RecordT>& record = static_cast<Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
RecordT record2 = record.get();
|
|
if (column == mName.mName)
|
|
record2.mName = value.toString().toUtf8().constData();
|
|
else if (column == mName.mScript)
|
|
record2.mScript = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
|
|
else
|
|
{
|
|
ModelRefIdAdapter<RecordT>::setData(column, data, index, value);
|
|
return;
|
|
}
|
|
|
|
record.setModified(record2);
|
|
}
|
|
|
|
struct InventoryColumns : public NameColumns
|
|
{
|
|
const RefIdColumn* mIcon;
|
|
const RefIdColumn* mWeight;
|
|
const RefIdColumn* mValue;
|
|
|
|
InventoryColumns(const NameColumns& base)
|
|
: NameColumns(base)
|
|
, mIcon(nullptr)
|
|
, mWeight(nullptr)
|
|
, mValue(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
/// \brief Adapter for IDs that can go into an inventory
|
|
template <typename RecordT>
|
|
class InventoryRefIdAdapter : public NameRefIdAdapter<RecordT>
|
|
{
|
|
InventoryColumns mInventory;
|
|
|
|
public:
|
|
InventoryRefIdAdapter(UniversalId::Type type, const InventoryColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
template <typename RecordT>
|
|
InventoryRefIdAdapter<RecordT>::InventoryRefIdAdapter(UniversalId::Type type, const InventoryColumns& columns)
|
|
: NameRefIdAdapter<RecordT>(type, columns)
|
|
, mInventory(columns)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant InventoryRefIdAdapter<RecordT>::getData(const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
const Record<RecordT>& record = static_cast<const Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
if (column == mInventory.mIcon)
|
|
return QString::fromUtf8(record.get().mIcon.c_str());
|
|
|
|
if (column == mInventory.mWeight)
|
|
return record.get().mData.mWeight;
|
|
|
|
if (column == mInventory.mValue)
|
|
return record.get().mData.mValue;
|
|
|
|
return NameRefIdAdapter<RecordT>::getData(column, data, index);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void InventoryRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
Record<RecordT>& record = static_cast<Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
RecordT record2 = record.get();
|
|
if (column == mInventory.mIcon)
|
|
record2.mIcon = value.toString().toUtf8().constData();
|
|
else if (column == mInventory.mWeight)
|
|
record2.mData.mWeight = value.toFloat();
|
|
else if (column == mInventory.mValue)
|
|
record2.mData.mValue = value.toInt();
|
|
else
|
|
{
|
|
NameRefIdAdapter<RecordT>::setData(column, data, index, value);
|
|
return;
|
|
}
|
|
|
|
record.setModified(record2);
|
|
}
|
|
|
|
struct PotionColumns : public InventoryColumns
|
|
{
|
|
const RefIdColumn* mEffects;
|
|
|
|
PotionColumns(const InventoryColumns& columns);
|
|
};
|
|
|
|
class PotionRefIdAdapter : public InventoryRefIdAdapter<ESM::Potion>
|
|
{
|
|
PotionColumns mColumns;
|
|
const RefIdColumn* mAutoCalc;
|
|
|
|
public:
|
|
PotionRefIdAdapter(const PotionColumns& columns, const RefIdColumn* autoCalc);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
struct IngredientColumns : public InventoryColumns
|
|
{
|
|
const RefIdColumn* mEffects;
|
|
|
|
IngredientColumns(const InventoryColumns& columns);
|
|
};
|
|
|
|
class IngredientRefIdAdapter : public InventoryRefIdAdapter<ESM::Ingredient>
|
|
{
|
|
IngredientColumns mColumns;
|
|
|
|
public:
|
|
IngredientRefIdAdapter(const IngredientColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class IngredEffectRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
public:
|
|
IngredEffectRefIdAdapter();
|
|
IngredEffectRefIdAdapter(const IngredEffectRefIdAdapter&) = delete;
|
|
IngredEffectRefIdAdapter& operator=(const IngredEffectRefIdAdapter&) = delete;
|
|
~IngredEffectRefIdAdapter() override = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override;
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override;
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override;
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override;
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
};
|
|
|
|
struct EnchantableColumns : public InventoryColumns
|
|
{
|
|
const RefIdColumn* mEnchantment;
|
|
const RefIdColumn* mEnchantmentPoints;
|
|
|
|
EnchantableColumns(const InventoryColumns& base)
|
|
: InventoryColumns(base)
|
|
, mEnchantment(nullptr)
|
|
, mEnchantmentPoints(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
/// \brief Adapter for enchantable IDs
|
|
template <typename RecordT>
|
|
class EnchantableRefIdAdapter : public InventoryRefIdAdapter<RecordT>
|
|
{
|
|
EnchantableColumns mEnchantable;
|
|
|
|
public:
|
|
EnchantableRefIdAdapter(UniversalId::Type type, const EnchantableColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
template <typename RecordT>
|
|
EnchantableRefIdAdapter<RecordT>::EnchantableRefIdAdapter(UniversalId::Type type, const EnchantableColumns& columns)
|
|
: InventoryRefIdAdapter<RecordT>(type, columns)
|
|
, mEnchantable(columns)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant EnchantableRefIdAdapter<RecordT>::getData(
|
|
const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
const Record<RecordT>& record = static_cast<const Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
if (column == mEnchantable.mEnchantment)
|
|
return QString::fromUtf8(record.get().mEnchant.getRefIdString().c_str());
|
|
|
|
if (column == mEnchantable.mEnchantmentPoints)
|
|
return static_cast<int>(record.get().mData.mEnchant);
|
|
|
|
return InventoryRefIdAdapter<RecordT>::getData(column, data, index);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void EnchantableRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
Record<RecordT>& record = static_cast<Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
RecordT record2 = record.get();
|
|
if (column == mEnchantable.mEnchantment)
|
|
record2.mEnchant = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
|
|
else if (column == mEnchantable.mEnchantmentPoints)
|
|
record2.mData.mEnchant = value.toInt();
|
|
else
|
|
{
|
|
InventoryRefIdAdapter<RecordT>::setData(column, data, index, value);
|
|
return;
|
|
}
|
|
|
|
record.setModified(record2);
|
|
}
|
|
|
|
struct ToolColumns : public InventoryColumns
|
|
{
|
|
const RefIdColumn* mQuality;
|
|
const RefIdColumn* mUses;
|
|
|
|
ToolColumns(const InventoryColumns& base)
|
|
: InventoryColumns(base)
|
|
, mQuality(nullptr)
|
|
, mUses(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
/// \brief Adapter for tools with limited uses IDs (lockpick, repair, probes)
|
|
template <typename RecordT>
|
|
class ToolRefIdAdapter : public InventoryRefIdAdapter<RecordT>
|
|
{
|
|
ToolColumns mTools;
|
|
|
|
public:
|
|
ToolRefIdAdapter(UniversalId::Type type, const ToolColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
template <typename RecordT>
|
|
ToolRefIdAdapter<RecordT>::ToolRefIdAdapter(UniversalId::Type type, const ToolColumns& columns)
|
|
: InventoryRefIdAdapter<RecordT>(type, columns)
|
|
, mTools(columns)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant ToolRefIdAdapter<RecordT>::getData(const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
const Record<RecordT>& record = static_cast<const Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
if (column == mTools.mQuality)
|
|
return record.get().mData.mQuality;
|
|
|
|
if (column == mTools.mUses)
|
|
return record.get().mData.mUses;
|
|
|
|
return InventoryRefIdAdapter<RecordT>::getData(column, data, index);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void ToolRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
Record<RecordT>& record = static_cast<Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
RecordT record2 = record.get();
|
|
if (column == mTools.mQuality)
|
|
record2.mData.mQuality = value.toFloat();
|
|
else if (column == mTools.mUses)
|
|
record2.mData.mUses = value.toInt();
|
|
else
|
|
{
|
|
InventoryRefIdAdapter<RecordT>::setData(column, data, index, value);
|
|
return;
|
|
}
|
|
|
|
record.setModified(record2);
|
|
}
|
|
|
|
struct ActorColumns : public NameColumns
|
|
{
|
|
const RefIdColumn* mHello;
|
|
const RefIdColumn* mFlee;
|
|
const RefIdColumn* mFight;
|
|
const RefIdColumn* mAlarm;
|
|
const RefIdColumn* mInventory;
|
|
const RefIdColumn* mSpells;
|
|
const RefIdColumn* mDestinations;
|
|
const RefIdColumn* mAiPackages;
|
|
std::map<const RefIdColumn*, unsigned int> mServices;
|
|
|
|
ActorColumns(const NameColumns& base)
|
|
: NameColumns(base)
|
|
, mHello(nullptr)
|
|
, mFlee(nullptr)
|
|
, mFight(nullptr)
|
|
, mAlarm(nullptr)
|
|
, mInventory(nullptr)
|
|
, mSpells(nullptr)
|
|
, mDestinations(nullptr)
|
|
, mAiPackages(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
/// \brief Adapter for actor IDs (handles common AI functionality)
|
|
template <typename RecordT>
|
|
class ActorRefIdAdapter : public NameRefIdAdapter<RecordT>
|
|
{
|
|
ActorColumns mActors;
|
|
|
|
public:
|
|
ActorRefIdAdapter(UniversalId::Type type, const ActorColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
template <typename RecordT>
|
|
ActorRefIdAdapter<RecordT>::ActorRefIdAdapter(UniversalId::Type type, const ActorColumns& columns)
|
|
: NameRefIdAdapter<RecordT>(type, columns)
|
|
, mActors(columns)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant ActorRefIdAdapter<RecordT>::getData(const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
const Record<RecordT>& record = static_cast<const Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
if (column == mActors.mHello)
|
|
return record.get().mAiData.mHello;
|
|
|
|
if (column == mActors.mFlee)
|
|
return record.get().mAiData.mFlee;
|
|
|
|
if (column == mActors.mFight)
|
|
return record.get().mAiData.mFight;
|
|
|
|
if (column == mActors.mAlarm)
|
|
return record.get().mAiData.mAlarm;
|
|
|
|
if (column == mActors.mInventory)
|
|
return QVariant::fromValue(ColumnBase::TableEdit_Full);
|
|
|
|
if (column == mActors.mSpells)
|
|
return QVariant::fromValue(ColumnBase::TableEdit_Full);
|
|
|
|
if (column == mActors.mDestinations)
|
|
return QVariant::fromValue(ColumnBase::TableEdit_Full);
|
|
|
|
if (column == mActors.mAiPackages)
|
|
return QVariant::fromValue(ColumnBase::TableEdit_Full);
|
|
|
|
std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mActors.mServices.find(column);
|
|
|
|
if (iter != mActors.mServices.end())
|
|
return (record.get().mAiData.mServices & iter->second) != 0;
|
|
|
|
return NameRefIdAdapter<RecordT>::getData(column, data, index);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void ActorRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
Record<RecordT>& record = static_cast<Record<RecordT>&>(
|
|
data.getRecord(RefIdData::LocalIndex(index, BaseRefIdAdapter<RecordT>::getType())));
|
|
|
|
RecordT record2 = record.get();
|
|
if (column == mActors.mHello)
|
|
record2.mAiData.mHello = value.toInt();
|
|
else if (column == mActors.mFlee) // Flee, Fight and Alarm ratings are probabilities.
|
|
record2.mAiData.mFlee = std::min(100, value.toInt());
|
|
else if (column == mActors.mFight)
|
|
record2.mAiData.mFight = std::min(100, value.toInt());
|
|
else if (column == mActors.mAlarm)
|
|
record2.mAiData.mAlarm = std::min(100, value.toInt());
|
|
else
|
|
{
|
|
typename std::map<const RefIdColumn*, unsigned int>::const_iterator iter = mActors.mServices.find(column);
|
|
if (iter != mActors.mServices.end())
|
|
{
|
|
if (value.toInt() != 0)
|
|
record2.mAiData.mServices |= iter->second;
|
|
else
|
|
record2.mAiData.mServices &= ~iter->second;
|
|
}
|
|
else
|
|
{
|
|
NameRefIdAdapter<RecordT>::setData(column, data, index, value);
|
|
return;
|
|
}
|
|
}
|
|
|
|
record.setModified(record2);
|
|
}
|
|
|
|
class ApparatusRefIdAdapter : public InventoryRefIdAdapter<ESM::Apparatus>
|
|
{
|
|
const RefIdColumn* mType;
|
|
const RefIdColumn* mQuality;
|
|
|
|
public:
|
|
ApparatusRefIdAdapter(const InventoryColumns& columns, const RefIdColumn* type, const RefIdColumn* quality);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class ArmorRefIdAdapter : public EnchantableRefIdAdapter<ESM::Armor>
|
|
{
|
|
const RefIdColumn* mType;
|
|
const RefIdColumn* mHealth;
|
|
const RefIdColumn* mArmor;
|
|
const RefIdColumn* mPartRef;
|
|
|
|
public:
|
|
ArmorRefIdAdapter(const EnchantableColumns& columns, const RefIdColumn* type, const RefIdColumn* health,
|
|
const RefIdColumn* armor, const RefIdColumn* partRef);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class BookRefIdAdapter : public EnchantableRefIdAdapter<ESM::Book>
|
|
{
|
|
const RefIdColumn* mBookType;
|
|
const RefIdColumn* mSkill;
|
|
const RefIdColumn* mText;
|
|
|
|
public:
|
|
BookRefIdAdapter(const EnchantableColumns& columns, const RefIdColumn* bookType, const RefIdColumn* skill,
|
|
const RefIdColumn* text);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class ClothingRefIdAdapter : public EnchantableRefIdAdapter<ESM::Clothing>
|
|
{
|
|
const RefIdColumn* mType;
|
|
const RefIdColumn* mPartRef;
|
|
|
|
public:
|
|
ClothingRefIdAdapter(const EnchantableColumns& columns, const RefIdColumn* type, const RefIdColumn* partRef);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class ContainerRefIdAdapter : public NameRefIdAdapter<ESM::Container>
|
|
{
|
|
const RefIdColumn* mWeight;
|
|
const RefIdColumn* mOrganic;
|
|
const RefIdColumn* mRespawn;
|
|
const RefIdColumn* mContent;
|
|
|
|
public:
|
|
ContainerRefIdAdapter(const NameColumns& columns, const RefIdColumn* weight, const RefIdColumn* organic,
|
|
const RefIdColumn* respawn, const RefIdColumn* content);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
struct CreatureColumns : public ActorColumns
|
|
{
|
|
std::map<const RefIdColumn*, unsigned int> mFlags;
|
|
const RefIdColumn* mType;
|
|
const RefIdColumn* mScale;
|
|
const RefIdColumn* mOriginal;
|
|
const RefIdColumn* mAttributes;
|
|
const RefIdColumn* mAttacks;
|
|
const RefIdColumn* mMisc;
|
|
const RefIdColumn* mBloodType;
|
|
|
|
CreatureColumns(const ActorColumns& actorColumns);
|
|
};
|
|
|
|
class CreatureRefIdAdapter : public ActorRefIdAdapter<ESM::Creature>
|
|
{
|
|
CreatureColumns mColumns;
|
|
|
|
public:
|
|
CreatureRefIdAdapter(const CreatureColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class DoorRefIdAdapter : public NameRefIdAdapter<ESM::Door>
|
|
{
|
|
const RefIdColumn* mOpenSound;
|
|
const RefIdColumn* mCloseSound;
|
|
|
|
public:
|
|
DoorRefIdAdapter(const NameColumns& columns, const RefIdColumn* openSound, const RefIdColumn* closeSound);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
struct LightColumns : public InventoryColumns
|
|
{
|
|
const RefIdColumn* mTime;
|
|
const RefIdColumn* mRadius;
|
|
const RefIdColumn* mColor;
|
|
const RefIdColumn* mSound;
|
|
const RefIdColumn* mEmitterType;
|
|
std::map<const RefIdColumn*, unsigned int> mFlags;
|
|
|
|
LightColumns(const InventoryColumns& columns);
|
|
};
|
|
|
|
class LightRefIdAdapter : public InventoryRefIdAdapter<ESM::Light>
|
|
{
|
|
LightColumns mColumns;
|
|
|
|
public:
|
|
LightRefIdAdapter(const LightColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class MiscRefIdAdapter : public InventoryRefIdAdapter<ESM::Miscellaneous>
|
|
{
|
|
const RefIdColumn* mKey;
|
|
|
|
public:
|
|
MiscRefIdAdapter(const InventoryColumns& columns, const RefIdColumn* key);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
struct NpcColumns : public ActorColumns
|
|
{
|
|
std::map<const RefIdColumn*, unsigned int> mFlags;
|
|
const RefIdColumn* mRace;
|
|
const RefIdColumn* mClass;
|
|
const RefIdColumn* mFaction;
|
|
const RefIdColumn* mHair;
|
|
const RefIdColumn* mHead;
|
|
const RefIdColumn* mAttributes; // depends on npc type
|
|
const RefIdColumn* mSkills; // depends on npc type
|
|
const RefIdColumn* mMisc; // may depend on npc type, e.g. FactionID
|
|
const RefIdColumn* mBloodType;
|
|
const RefIdColumn* mGender;
|
|
|
|
NpcColumns(const ActorColumns& actorColumns);
|
|
};
|
|
|
|
class NpcRefIdAdapter : public ActorRefIdAdapter<ESM::NPC>
|
|
{
|
|
NpcColumns mColumns;
|
|
|
|
public:
|
|
NpcRefIdAdapter(const NpcColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
struct WeaponColumns : public EnchantableColumns
|
|
{
|
|
const RefIdColumn* mType;
|
|
const RefIdColumn* mHealth;
|
|
const RefIdColumn* mSpeed;
|
|
const RefIdColumn* mReach;
|
|
const RefIdColumn* mChop[2];
|
|
const RefIdColumn* mSlash[2];
|
|
const RefIdColumn* mThrust[2];
|
|
std::map<const RefIdColumn*, unsigned int> mFlags;
|
|
|
|
WeaponColumns(const EnchantableColumns& columns);
|
|
};
|
|
|
|
class WeaponRefIdAdapter : public EnchantableRefIdAdapter<ESM::Weapon>
|
|
{
|
|
WeaponColumns mColumns;
|
|
|
|
public:
|
|
WeaponRefIdAdapter(const WeaponColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
class NpcAttributesRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
public:
|
|
NpcAttributesRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override;
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override;
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override;
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override;
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
};
|
|
|
|
class NpcSkillsRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
public:
|
|
NpcSkillsRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override;
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override;
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override;
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override;
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
};
|
|
|
|
class NpcMiscRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
public:
|
|
NpcMiscRefIdAdapter() = default;
|
|
NpcMiscRefIdAdapter(const NpcMiscRefIdAdapter&) = delete;
|
|
NpcMiscRefIdAdapter& operator=(const NpcMiscRefIdAdapter&) = delete;
|
|
~NpcMiscRefIdAdapter() override = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override;
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override;
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override;
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override;
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
};
|
|
|
|
class CreatureAttributesRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
public:
|
|
CreatureAttributesRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override;
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override;
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override;
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override;
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
};
|
|
|
|
class CreatureAttackRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
public:
|
|
CreatureAttackRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override;
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override;
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override;
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override;
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
};
|
|
|
|
class CreatureMiscRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
public:
|
|
CreatureMiscRefIdAdapter() = default;
|
|
CreatureMiscRefIdAdapter(const CreatureMiscRefIdAdapter&) = delete;
|
|
CreatureMiscRefIdAdapter& operator=(const CreatureMiscRefIdAdapter&) = delete;
|
|
~CreatureMiscRefIdAdapter() override = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override;
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override;
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override;
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override;
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override;
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
};
|
|
|
|
template <typename ESXRecordT>
|
|
class EffectsListAdapter;
|
|
|
|
template <typename ESXRecordT>
|
|
class EffectsRefIdAdapter : public EffectsListAdapter<ESXRecordT>, public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
EffectsRefIdAdapter(const EffectsRefIdAdapter&);
|
|
EffectsRefIdAdapter& operator=(const EffectsRefIdAdapter&);
|
|
|
|
public:
|
|
EffectsRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~EffectsRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
EffectsListAdapter<ESXRecordT>::addRow(record, position);
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
EffectsListAdapter<ESXRecordT>::removeRow(record, rowToRemove);
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
EffectsListAdapter<ESXRecordT>::setTable(record, nestedTable);
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
return EffectsListAdapter<ESXRecordT>::table(record);
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
return EffectsListAdapter<ESXRecordT>::getData(record, subRowIndex, subColIndex);
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
EffectsListAdapter<ESXRecordT>::setData(record, value, subRowIndex, subColIndex);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override
|
|
{
|
|
const Record<ESXRecordT> record; // not used, just a dummy
|
|
return EffectsListAdapter<ESXRecordT>::getColumnsCount(record);
|
|
}
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
return EffectsListAdapter<ESXRecordT>::getRowsCount(record);
|
|
}
|
|
};
|
|
|
|
template <typename ESXRecordT>
|
|
class NestedInventoryRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
NestedInventoryRefIdAdapter(const NestedInventoryRefIdAdapter&);
|
|
NestedInventoryRefIdAdapter& operator=(const NestedInventoryRefIdAdapter&);
|
|
|
|
public:
|
|
NestedInventoryRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~NestedInventoryRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT container = record.get();
|
|
|
|
std::vector<ESM::ContItem>& list = container.mInventory.mList;
|
|
|
|
ESM::ContItem newRow = ESM::ContItem();
|
|
|
|
if (position >= (int)list.size())
|
|
list.push_back(newRow);
|
|
else
|
|
list.insert(list.begin() + position, newRow);
|
|
|
|
record.setModified(container);
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT container = record.get();
|
|
|
|
std::vector<ESM::ContItem>& list = container.mInventory.mList;
|
|
|
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
list.erase(list.begin() + rowToRemove);
|
|
|
|
record.setModified(container);
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT container = record.get();
|
|
|
|
container.mInventory.mList
|
|
= static_cast<const NestedTableWrapper<std::vector<typename ESM::ContItem>>&>(nestedTable).mNestedTable;
|
|
|
|
record.setModified(container);
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
// deleted by dtor of NestedTableStoring
|
|
return new NestedTableWrapper<std::vector<typename ESM::ContItem>>(record.get().mInventory.mList);
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
const std::vector<ESM::ContItem>& list = record.get().mInventory.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
const ESM::ContItem& content = list.at(subRowIndex);
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(content.mItem.getRefIdString().c_str());
|
|
case 1:
|
|
return content.mCount;
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
ESXRecordT container = record.get();
|
|
std::vector<ESM::ContItem>& list = container.mInventory.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
list.at(subRowIndex).mItem = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
|
|
break;
|
|
|
|
case 1:
|
|
list.at(subRowIndex).mCount = value.toInt();
|
|
break;
|
|
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
|
|
record.setModified(container);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override { return 2; }
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
return static_cast<int>(record.get().mInventory.mList.size());
|
|
}
|
|
};
|
|
|
|
template <typename ESXRecordT>
|
|
class NestedSpellRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
NestedSpellRefIdAdapter(const NestedSpellRefIdAdapter&);
|
|
NestedSpellRefIdAdapter& operator=(const NestedSpellRefIdAdapter&);
|
|
|
|
public:
|
|
NestedSpellRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~NestedSpellRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT caster = record.get();
|
|
|
|
std::vector<ESM::RefId>& list = caster.mSpells.mList;
|
|
|
|
ESM::RefId newString;
|
|
|
|
if (position >= (int)list.size())
|
|
list.push_back(newString);
|
|
else
|
|
list.insert(list.begin() + position, newString);
|
|
|
|
record.setModified(caster);
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT caster = record.get();
|
|
|
|
std::vector<ESM::RefId>& list = caster.mSpells.mList;
|
|
|
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
list.erase(list.begin() + rowToRemove);
|
|
|
|
record.setModified(caster);
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT caster = record.get();
|
|
|
|
caster.mSpells.mList
|
|
= static_cast<const NestedTableWrapper<std::vector<typename ESM::RefId>>&>(nestedTable).mNestedTable;
|
|
|
|
record.setModified(caster);
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
// deleted by dtor of NestedTableStoring
|
|
return new NestedTableWrapper<std::vector<typename ESM::RefId>>(record.get().mSpells.mList);
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
const std::vector<ESM::RefId>& list = record.get().mSpells.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
const ESM::RefId& content = list.at(subRowIndex);
|
|
|
|
if (subColIndex == 0)
|
|
return QString::fromUtf8(content.getRefIdString().c_str());
|
|
else
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
ESXRecordT caster = record.get();
|
|
std::vector<ESM::RefId>& list = caster.mSpells.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
if (subColIndex == 0)
|
|
list.at(subRowIndex) = ESM::RefId::stringRefId(value.toString().toUtf8().constData());
|
|
else
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
|
|
record.setModified(caster);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override { return 1; }
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
return static_cast<int>(record.get().mSpells.mList.size());
|
|
}
|
|
};
|
|
|
|
template <typename ESXRecordT>
|
|
class NestedTravelRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
NestedTravelRefIdAdapter(const NestedTravelRefIdAdapter&);
|
|
NestedTravelRefIdAdapter& operator=(const NestedTravelRefIdAdapter&);
|
|
|
|
public:
|
|
NestedTravelRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~NestedTravelRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT traveller = record.get();
|
|
|
|
std::vector<ESM::Transport::Dest>& list = traveller.mTransport.mList;
|
|
|
|
ESM::Position newPos;
|
|
for (unsigned i = 0; i < 3; ++i)
|
|
{
|
|
newPos.pos[i] = 0;
|
|
newPos.rot[i] = 0;
|
|
}
|
|
|
|
ESM::Transport::Dest newRow;
|
|
newRow.mPos = newPos;
|
|
newRow.mCellName.clear();
|
|
|
|
if (position >= (int)list.size())
|
|
list.push_back(newRow);
|
|
else
|
|
list.insert(list.begin() + position, newRow);
|
|
|
|
record.setModified(traveller);
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT traveller = record.get();
|
|
|
|
std::vector<ESM::Transport::Dest>& list = traveller.mTransport.mList;
|
|
|
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
list.erase(list.begin() + rowToRemove);
|
|
|
|
record.setModified(traveller);
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT traveller = record.get();
|
|
|
|
traveller.mTransport.mList
|
|
= static_cast<const NestedTableWrapper<std::vector<typename ESM::Transport::Dest>>&>(nestedTable)
|
|
.mNestedTable;
|
|
|
|
record.setModified(traveller);
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
// deleted by dtor of NestedTableStoring
|
|
return new NestedTableWrapper<std::vector<typename ESM::Transport::Dest>>(record.get().mTransport.mList);
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
const std::vector<ESM::Transport::Dest>& list = record.get().mTransport.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
const ESM::Transport::Dest& content = list.at(subRowIndex);
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(content.mCellName.c_str());
|
|
case 1:
|
|
return content.mPos.pos[0];
|
|
case 2:
|
|
return content.mPos.pos[1];
|
|
case 3:
|
|
return content.mPos.pos[2];
|
|
case 4:
|
|
return content.mPos.rot[0];
|
|
case 5:
|
|
return content.mPos.rot[1];
|
|
case 6:
|
|
return content.mPos.rot[2];
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
ESXRecordT traveller = record.get();
|
|
std::vector<ESM::Transport::Dest>& list = traveller.mTransport.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
list.at(subRowIndex).mCellName = value.toString().toUtf8().constData();
|
|
break;
|
|
case 1:
|
|
list.at(subRowIndex).mPos.pos[0] = value.toFloat();
|
|
break;
|
|
case 2:
|
|
list.at(subRowIndex).mPos.pos[1] = value.toFloat();
|
|
break;
|
|
case 3:
|
|
list.at(subRowIndex).mPos.pos[2] = value.toFloat();
|
|
break;
|
|
case 4:
|
|
list.at(subRowIndex).mPos.rot[0] = value.toFloat();
|
|
break;
|
|
case 5:
|
|
list.at(subRowIndex).mPos.rot[1] = value.toFloat();
|
|
break;
|
|
case 6:
|
|
list.at(subRowIndex).mPos.rot[2] = value.toFloat();
|
|
break;
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
|
|
record.setModified(traveller);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override { return 7; }
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
return static_cast<int>(record.get().mTransport.mList.size());
|
|
}
|
|
};
|
|
|
|
template <typename ESXRecordT>
|
|
class ActorAiRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
ActorAiRefIdAdapter(const ActorAiRefIdAdapter&);
|
|
ActorAiRefIdAdapter& operator=(const ActorAiRefIdAdapter&);
|
|
|
|
public:
|
|
ActorAiRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~ActorAiRefIdAdapter() = default;
|
|
|
|
// FIXME: should check if the AI package type is already in the list and use a default
|
|
// that wasn't used already (in extreme case do not add anything at all?
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT actor = record.get();
|
|
|
|
std::vector<ESM::AIPackage>& list = actor.mAiPackage.mList;
|
|
|
|
ESM::AIPackage newRow;
|
|
newRow.mType = ESM::AI_Wander;
|
|
newRow.mWander.mDistance = 0;
|
|
newRow.mWander.mDuration = 0;
|
|
newRow.mWander.mTimeOfDay = 0;
|
|
for (int i = 0; i < 8; ++i)
|
|
newRow.mWander.mIdle[i] = 0;
|
|
newRow.mWander.mShouldRepeat = 1;
|
|
newRow.mCellName.clear();
|
|
|
|
if (position >= (int)list.size())
|
|
list.push_back(newRow);
|
|
else
|
|
list.insert(list.begin() + position, newRow);
|
|
|
|
record.setModified(actor);
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT actor = record.get();
|
|
|
|
std::vector<ESM::AIPackage>& list = actor.mAiPackage.mList;
|
|
|
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
list.erase(list.begin() + rowToRemove);
|
|
|
|
record.setModified(actor);
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT actor = record.get();
|
|
|
|
actor.mAiPackage.mList
|
|
= static_cast<const NestedTableWrapper<std::vector<typename ESM::AIPackage>>&>(nestedTable)
|
|
.mNestedTable;
|
|
|
|
record.setModified(actor);
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
// deleted by dtor of NestedTableStoring
|
|
return new NestedTableWrapper<std::vector<typename ESM::AIPackage>>(record.get().mAiPackage.mList);
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
const std::vector<ESM::AIPackage>& list = record.get().mAiPackage.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
const ESM::AIPackage& content = list.at(subRowIndex);
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
// FIXME: should more than one AI package type be allowed? Check vanilla
|
|
switch (content.mType)
|
|
{
|
|
case ESM::AI_Wander:
|
|
return 0;
|
|
case ESM::AI_Travel:
|
|
return 1;
|
|
case ESM::AI_Follow:
|
|
return 2;
|
|
case ESM::AI_Escort:
|
|
return 3;
|
|
case ESM::AI_Activate:
|
|
return 4;
|
|
default:
|
|
return QVariant();
|
|
}
|
|
case 1: // wander dist
|
|
if (content.mType == ESM::AI_Wander)
|
|
return content.mWander.mDistance;
|
|
else
|
|
return QVariant();
|
|
case 2: // wander/follow dur
|
|
if (content.mType == ESM::AI_Wander)
|
|
return content.mWander.mDuration;
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
return content.mTarget.mDuration;
|
|
else
|
|
return QVariant();
|
|
case 3: // wander ToD
|
|
if (content.mType == ESM::AI_Wander)
|
|
return content.mWander.mTimeOfDay; // FIXME: not sure of the format
|
|
else
|
|
return QVariant();
|
|
case 4: // wander idle
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
if (content.mType == ESM::AI_Wander)
|
|
return static_cast<int>(content.mWander.mIdle[subColIndex - 4]);
|
|
else
|
|
return QVariant();
|
|
case 12: // repeat
|
|
if (content.mType == ESM::AI_Wander)
|
|
return content.mWander.mShouldRepeat != 0;
|
|
else if (content.mType == ESM::AI_Travel)
|
|
return content.mTravel.mShouldRepeat != 0;
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
return content.mTarget.mShouldRepeat != 0;
|
|
else if (content.mType == ESM::AI_Activate)
|
|
return content.mActivate.mShouldRepeat != 0;
|
|
else
|
|
return QVariant();
|
|
case 13: // activate name
|
|
if (content.mType == ESM::AI_Activate)
|
|
return QString(content.mActivate.mName.toString().c_str());
|
|
else
|
|
return QVariant();
|
|
case 14: // target id
|
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
return QString(content.mTarget.mId.toString().c_str());
|
|
else
|
|
return QVariant();
|
|
case 15: // target cell
|
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
return QString::fromUtf8(content.mCellName.c_str());
|
|
else
|
|
return QVariant();
|
|
case 16:
|
|
if (content.mType == ESM::AI_Travel)
|
|
return content.mTravel.mX;
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
return content.mTarget.mX;
|
|
else
|
|
return QVariant();
|
|
case 17:
|
|
if (content.mType == ESM::AI_Travel)
|
|
return content.mTravel.mY;
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
return content.mTarget.mY;
|
|
else
|
|
return QVariant();
|
|
case 18:
|
|
if (content.mType == ESM::AI_Travel)
|
|
return content.mTravel.mZ;
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
return content.mTarget.mZ;
|
|
else
|
|
return QVariant();
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
ESXRecordT actor = record.get();
|
|
std::vector<ESM::AIPackage>& list = actor.mAiPackage.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
ESM::AIPackage& content = list.at(subRowIndex);
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0: // ai package type
|
|
switch (value.toInt())
|
|
{
|
|
case 0:
|
|
content.mType = ESM::AI_Wander;
|
|
break;
|
|
case 1:
|
|
content.mType = ESM::AI_Travel;
|
|
break;
|
|
case 2:
|
|
content.mType = ESM::AI_Follow;
|
|
break;
|
|
case 3:
|
|
content.mType = ESM::AI_Escort;
|
|
break;
|
|
case 4:
|
|
content.mType = ESM::AI_Activate;
|
|
break;
|
|
default:
|
|
return; // return without saving
|
|
}
|
|
break; // always save
|
|
|
|
case 1:
|
|
if (content.mType == ESM::AI_Wander)
|
|
content.mWander.mDistance = static_cast<short>(value.toInt());
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 2:
|
|
if (content.mType == ESM::AI_Wander)
|
|
content.mWander.mDuration = static_cast<short>(value.toInt());
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
content.mTarget.mDuration = static_cast<short>(value.toInt());
|
|
else
|
|
return; // return without saving
|
|
break;
|
|
case 3:
|
|
if (content.mType == ESM::AI_Wander)
|
|
content.mWander.mTimeOfDay = static_cast<unsigned char>(value.toInt());
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 4:
|
|
case 5:
|
|
case 6:
|
|
case 7:
|
|
case 8:
|
|
case 9:
|
|
case 10:
|
|
case 11:
|
|
if (content.mType == ESM::AI_Wander)
|
|
content.mWander.mIdle[subColIndex - 4] = static_cast<unsigned char>(value.toInt());
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 12:
|
|
if (content.mType == ESM::AI_Wander)
|
|
content.mWander.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
|
else if (content.mType == ESM::AI_Travel)
|
|
content.mTravel.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
content.mTarget.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
|
else if (content.mType == ESM::AI_Activate)
|
|
content.mActivate.mShouldRepeat = static_cast<unsigned char>(value.toInt());
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 13: // NAME32
|
|
if (content.mType == ESM::AI_Activate)
|
|
{
|
|
const QByteArray name = value.toString().toUtf8();
|
|
content.mActivate.mName.assign(std::string_view(name.constData(), name.size()));
|
|
}
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 14: // NAME32
|
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
{
|
|
const QByteArray id = value.toString().toUtf8();
|
|
content.mTarget.mId.assign(std::string_view(id.constData(), id.size()));
|
|
}
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 15:
|
|
if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
content.mCellName = std::string(value.toString().toUtf8().constData());
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 16:
|
|
if (content.mType == ESM::AI_Travel)
|
|
content.mTravel.mX = value.toFloat();
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
content.mTarget.mX = value.toFloat();
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 17:
|
|
if (content.mType == ESM::AI_Travel)
|
|
content.mTravel.mY = value.toFloat();
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
content.mTarget.mY = value.toFloat();
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
case 18:
|
|
if (content.mType == ESM::AI_Travel)
|
|
content.mTravel.mZ = value.toFloat();
|
|
else if (content.mType == ESM::AI_Follow || content.mType == ESM::AI_Escort)
|
|
content.mTarget.mZ = value.toFloat();
|
|
else
|
|
return; // return without saving
|
|
|
|
break; // always save
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
|
|
record.setModified(actor);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override { return 19; }
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
return static_cast<int>(record.get().mAiPackage.mList.size());
|
|
}
|
|
};
|
|
|
|
template <typename ESXRecordT>
|
|
class BodyPartRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
BodyPartRefIdAdapter(const BodyPartRefIdAdapter&);
|
|
BodyPartRefIdAdapter& operator=(const BodyPartRefIdAdapter&);
|
|
|
|
public:
|
|
BodyPartRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~BodyPartRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT apparel = record.get();
|
|
|
|
std::vector<ESM::PartReference>& list = apparel.mParts.mParts;
|
|
|
|
ESM::PartReference newPart;
|
|
newPart.mPart = 0; // 0 == head
|
|
newPart.mMale = ESM::RefId();
|
|
newPart.mFemale = ESM::RefId();
|
|
|
|
if (position >= (int)list.size())
|
|
list.push_back(newPart);
|
|
else
|
|
list.insert(list.begin() + position, newPart);
|
|
|
|
record.setModified(apparel);
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT apparel = record.get();
|
|
|
|
std::vector<ESM::PartReference>& list = apparel.mParts.mParts;
|
|
|
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
list.erase(list.begin() + rowToRemove);
|
|
|
|
record.setModified(apparel);
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT apparel = record.get();
|
|
|
|
apparel.mParts.mParts
|
|
= static_cast<const NestedTableWrapper<std::vector<typename ESM::PartReference>>&>(nestedTable)
|
|
.mNestedTable;
|
|
|
|
record.setModified(apparel);
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
// deleted by dtor of NestedTableStoring
|
|
return new NestedTableWrapper<std::vector<typename ESM::PartReference>>(record.get().mParts.mParts);
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
const std::vector<ESM::PartReference>& list = record.get().mParts.mParts;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
const ESM::PartReference& content = list.at(subRowIndex);
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
{
|
|
if (content.mPart < ESM::PRT_Count)
|
|
return content.mPart;
|
|
else
|
|
throw std::runtime_error("Part Reference Type unexpected value");
|
|
}
|
|
case 1:
|
|
return QString(content.mMale.getRefIdString().c_str());
|
|
case 2:
|
|
return QString(content.mFemale.getRefIdString().c_str());
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
ESXRecordT apparel = record.get();
|
|
std::vector<ESM::PartReference>& list = apparel.mParts.mParts;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
list.at(subRowIndex).mPart = static_cast<unsigned char>(value.toInt());
|
|
break;
|
|
case 1:
|
|
list.at(subRowIndex).mMale = ESM::RefId::stringRefId(value.toString().toStdString());
|
|
break;
|
|
case 2:
|
|
list.at(subRowIndex).mFemale = ESM::RefId::stringRefId(value.toString().toStdString());
|
|
break;
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
|
|
record.setModified(apparel);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override { return 3; }
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
return static_cast<int>(record.get().mParts.mParts.size());
|
|
}
|
|
};
|
|
|
|
struct LevListColumns : public BaseColumns
|
|
{
|
|
const RefIdColumn* mLevList;
|
|
const RefIdColumn* mNestedListLevList;
|
|
|
|
LevListColumns(const BaseColumns& base)
|
|
: BaseColumns(base)
|
|
, mLevList(nullptr)
|
|
, mNestedListLevList(nullptr)
|
|
{
|
|
}
|
|
};
|
|
|
|
template <typename RecordT>
|
|
class LevelledListRefIdAdapter : public BaseRefIdAdapter<RecordT>
|
|
{
|
|
LevListColumns mLevList;
|
|
|
|
public:
|
|
LevelledListRefIdAdapter(UniversalId::Type type, const LevListColumns& columns);
|
|
|
|
QVariant getData(const RefIdColumn* column, const RefIdData& data, int index) const override;
|
|
|
|
void setData(const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const override;
|
|
///< If the data type does not match an exception is thrown.
|
|
};
|
|
|
|
template <typename RecordT>
|
|
LevelledListRefIdAdapter<RecordT>::LevelledListRefIdAdapter(UniversalId::Type type, const LevListColumns& columns)
|
|
: BaseRefIdAdapter<RecordT>(type, columns)
|
|
, mLevList(columns)
|
|
{
|
|
}
|
|
|
|
template <typename RecordT>
|
|
QVariant LevelledListRefIdAdapter<RecordT>::getData(
|
|
const RefIdColumn* column, const RefIdData& data, int index) const
|
|
{
|
|
if (column == mLevList.mLevList || column == mLevList.mNestedListLevList)
|
|
return QVariant::fromValue(ColumnBase::TableEdit_Full);
|
|
|
|
return BaseRefIdAdapter<RecordT>::getData(column, data, index);
|
|
}
|
|
|
|
template <typename RecordT>
|
|
void LevelledListRefIdAdapter<RecordT>::setData(
|
|
const RefIdColumn* column, RefIdData& data, int index, const QVariant& value) const
|
|
{
|
|
BaseRefIdAdapter<RecordT>::setData(column, data, index, value);
|
|
return;
|
|
}
|
|
|
|
// for non-tables
|
|
template <typename ESXRecordT>
|
|
class NestedListLevListRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
NestedListLevListRefIdAdapter(const NestedListLevListRefIdAdapter&);
|
|
NestedListLevListRefIdAdapter& operator=(const NestedListLevListRefIdAdapter&);
|
|
|
|
public:
|
|
NestedListLevListRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~NestedListLevListRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
throw std::logic_error("cannot add a row to a fixed table");
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
throw std::logic_error("cannot remove a row to a fixed table");
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
throw std::logic_error("table operation not supported");
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
throw std::logic_error("table operation not supported");
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
if (mType == UniversalId::Type_CreatureLevelledList)
|
|
{
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
return QVariant(); // disable the checkbox editor
|
|
case 1:
|
|
return record.get().mFlags & ESM::CreatureLevList::AllLevels;
|
|
case 2:
|
|
return static_cast<int>(record.get().mChanceNone);
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in levelled creatues!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
return record.get().mFlags & ESM::ItemLevList::Each;
|
|
case 1:
|
|
return record.get().mFlags & ESM::ItemLevList::AllLevels;
|
|
case 2:
|
|
return static_cast<int>(record.get().mChanceNone);
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in levelled items!");
|
|
}
|
|
}
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
ESXRecordT leveled = record.get();
|
|
|
|
if (mType == UniversalId::Type_CreatureLevelledList)
|
|
{
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
return; // return without saving
|
|
case 1:
|
|
{
|
|
if (value.toBool())
|
|
{
|
|
leveled.mFlags |= ESM::CreatureLevList::AllLevels;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
leveled.mFlags &= ~ESM::CreatureLevList::AllLevels;
|
|
break;
|
|
}
|
|
}
|
|
case 2:
|
|
leveled.mChanceNone = static_cast<unsigned char>(value.toInt());
|
|
break;
|
|
default:
|
|
throw std::runtime_error("Trying to set non-existing column in levelled creatures!");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
{
|
|
if (value.toBool())
|
|
{
|
|
leveled.mFlags |= ESM::ItemLevList::Each;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
leveled.mFlags &= ~ESM::ItemLevList::Each;
|
|
break;
|
|
}
|
|
}
|
|
case 1:
|
|
{
|
|
if (value.toBool())
|
|
{
|
|
leveled.mFlags |= ESM::ItemLevList::AllLevels;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
leveled.mFlags &= ~ESM::ItemLevList::AllLevels;
|
|
break;
|
|
}
|
|
}
|
|
case 2:
|
|
leveled.mChanceNone = static_cast<unsigned char>(value.toInt());
|
|
break;
|
|
default:
|
|
throw std::runtime_error("Trying to set non-existing column in levelled items!");
|
|
}
|
|
}
|
|
|
|
record.setModified(leveled);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override { return 3; }
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
return 1; // fixed at size 1
|
|
}
|
|
};
|
|
|
|
// for tables
|
|
template <typename ESXRecordT>
|
|
class NestedLevListRefIdAdapter : public NestedRefIdAdapterBase
|
|
{
|
|
UniversalId::Type mType;
|
|
|
|
// not implemented
|
|
NestedLevListRefIdAdapter(const NestedLevListRefIdAdapter&);
|
|
NestedLevListRefIdAdapter& operator=(const NestedLevListRefIdAdapter&);
|
|
|
|
public:
|
|
NestedLevListRefIdAdapter(UniversalId::Type type)
|
|
: mType(type)
|
|
{
|
|
}
|
|
|
|
virtual ~NestedLevListRefIdAdapter() = default;
|
|
|
|
void addNestedRow(const RefIdColumn* column, RefIdData& data, int index, int position) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT leveled = record.get();
|
|
|
|
std::vector<ESM::LevelledListBase::LevelItem>& list = leveled.mList;
|
|
|
|
ESM::LevelledListBase::LevelItem newItem;
|
|
newItem.mId = ESM::RefId();
|
|
newItem.mLevel = 0;
|
|
|
|
if (position >= (int)list.size())
|
|
list.push_back(newItem);
|
|
else
|
|
list.insert(list.begin() + position, newItem);
|
|
|
|
record.setModified(leveled);
|
|
}
|
|
|
|
void removeNestedRow(const RefIdColumn* column, RefIdData& data, int index, int rowToRemove) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT leveled = record.get();
|
|
|
|
std::vector<ESM::LevelledListBase::LevelItem>& list = leveled.mList;
|
|
|
|
if (rowToRemove < 0 || rowToRemove >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
list.erase(list.begin() + rowToRemove);
|
|
|
|
record.setModified(leveled);
|
|
}
|
|
|
|
void setNestedTable(const RefIdColumn* column, RefIdData& data, int index,
|
|
const NestedTableWrapperBase& nestedTable) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
ESXRecordT leveled = record.get();
|
|
|
|
leveled.mList
|
|
= static_cast<const NestedTableWrapper<std::vector<typename ESM::LevelledListBase::LevelItem>>&>(
|
|
nestedTable)
|
|
.mNestedTable;
|
|
|
|
record.setModified(leveled);
|
|
}
|
|
|
|
NestedTableWrapperBase* nestedTable(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
// deleted by dtor of NestedTableStoring
|
|
return new NestedTableWrapper<std::vector<typename ESM::LevelledListBase::LevelItem>>(record.get().mList);
|
|
}
|
|
|
|
QVariant getNestedData(const RefIdColumn* column, const RefIdData& data, int index, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
const std::vector<ESM::LevelledListBase::LevelItem>& list = record.get().mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
const ESM::LevelledListBase::LevelItem& content = list.at(subRowIndex);
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
return QString(content.mId.getRefIdString().c_str());
|
|
case 1:
|
|
return content.mLevel;
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
}
|
|
|
|
void setNestedData(const RefIdColumn* column, RefIdData& data, int row, const QVariant& value, int subRowIndex,
|
|
int subColIndex) const override
|
|
{
|
|
Record<ESXRecordT>& record
|
|
= static_cast<Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(row, mType)));
|
|
ESXRecordT leveled = record.get();
|
|
std::vector<ESM::LevelledListBase::LevelItem>& list = leveled.mList;
|
|
|
|
if (subRowIndex < 0 || subRowIndex >= static_cast<int>(list.size()))
|
|
throw std::runtime_error("index out of range");
|
|
|
|
switch (subColIndex)
|
|
{
|
|
case 0:
|
|
list.at(subRowIndex).mId = ESM::RefId::stringRefId(value.toString().toStdString());
|
|
break;
|
|
case 1:
|
|
list.at(subRowIndex).mLevel = static_cast<short>(value.toInt());
|
|
break;
|
|
default:
|
|
throw std::runtime_error("Trying to access non-existing column in the nested table!");
|
|
}
|
|
|
|
record.setModified(leveled);
|
|
}
|
|
|
|
int getNestedColumnsCount(const RefIdColumn* column, const RefIdData& data) const override { return 2; }
|
|
|
|
int getNestedRowsCount(const RefIdColumn* column, const RefIdData& data, int index) const override
|
|
{
|
|
const Record<ESXRecordT>& record
|
|
= static_cast<const Record<ESXRecordT>&>(data.getRecord(RefIdData::LocalIndex(index, mType)));
|
|
|
|
return static_cast<int>(record.get().mList.size());
|
|
}
|
|
};
|
|
}
|
|
|
|
#endif
|