#include "nestedcoladapterimp.hpp" #include #include #include "idcollection.hpp" #include "pathgrid.hpp" #include "info.hpp" namespace CSMWorld { PathgridPointListAdapter::PathgridPointListAdapter () {} void PathgridPointListAdapter::addRow(Record& record, int position) const { Pathgrid pathgrid = record.get(); ESM::Pathgrid::PointList& points = pathgrid.mPoints; // blank row ESM::Pathgrid::Point point; point.mX = 0; point.mY = 0; point.mZ = 0; point.mAutogenerated = 0; point.mConnectionNum = 0; point.mUnknown = 0; // inserting a point should trigger re-indexing of the edges // // FIXME: does not auto refresh edges table view std::vector::iterator iter = pathgrid.mEdges.begin(); for (;iter != pathgrid.mEdges.end(); ++iter) { if ((*iter).mV0 >= position) (*iter).mV0++; if ((*iter).mV1 >= position) (*iter).mV1++; } points.insert(points.begin()+position, point); pathgrid.mData.mS2 += 1; // increment the number of points record.setModified (pathgrid); } void PathgridPointListAdapter::removeRow(Record& record, int rowToRemove) const { Pathgrid pathgrid = record.get(); ESM::Pathgrid::PointList& points = pathgrid.mPoints; if (rowToRemove < 0 || rowToRemove >= static_cast (points.size())) throw std::runtime_error ("index out of range"); // deleting a point should trigger re-indexing of the edges // dangling edges are not allowed and hence removed // // FIXME: does not auto refresh edges table view std::vector::iterator iter = pathgrid.mEdges.begin(); for (; iter != pathgrid.mEdges.end();) { if (((*iter).mV0 == rowToRemove) || ((*iter).mV1 == rowToRemove)) iter = pathgrid.mEdges.erase(iter); else { if ((*iter).mV0 > rowToRemove) (*iter).mV0--; if ((*iter).mV1 > rowToRemove) (*iter).mV1--; ++iter; } } points.erase(points.begin()+rowToRemove); pathgrid.mData.mS2 -= 1; // decrement the number of points record.setModified (pathgrid); } void PathgridPointListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { Pathgrid pathgrid = record.get(); pathgrid.mPoints = static_cast(nestedTable).mRecord.mPoints; pathgrid.mData.mS2 = static_cast(nestedTable).mRecord.mData.mS2; // also update edges in case points were added/removed pathgrid.mEdges = static_cast(nestedTable).mRecord.mEdges; record.setModified (pathgrid); } NestedTableWrapperBase* PathgridPointListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new PathgridPointsWrap(record.get()); } QVariant PathgridPointListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Pathgrid::Point point = record.get().mPoints[subRowIndex]; switch (subColIndex) { case 0: return subRowIndex; case 1: return point.mX; case 2: return point.mY; case 3: return point.mZ; default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); } } void PathgridPointListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); ESM::Pathgrid::Point point = pathgrid.mPoints[subRowIndex]; switch (subColIndex) { case 0: return; // return without saving case 1: point.mX = value.toInt(); break; case 2: point.mY = value.toInt(); break; case 3: point.mZ = value.toInt(); break; default: throw std::runtime_error("Pathgrid point subcolumn index out of range"); } pathgrid.mPoints[subRowIndex] = point; record.setModified (pathgrid); } int PathgridPointListAdapter::getColumnsCount(const Record& record) const { return 4; } int PathgridPointListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mPoints.size()); } PathgridEdgeListAdapter::PathgridEdgeListAdapter () {} // ToDo: seems to be auto-sorted in the dialog table display after insertion void PathgridEdgeListAdapter::addRow(Record& record, int position) const { Pathgrid pathgrid = record.get(); ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; // blank row ESM::Pathgrid::Edge edge; edge.mV0 = 0; edge.mV1 = 0; // NOTE: inserting a blank edge does not really make sense, perhaps this should be a // logic_error exception // // Currently the code assumes that the end user to know what he/she is doing. // e.g. Edges come in pairs, from points a->b and b->a edges.insert(edges.begin()+position, edge); record.setModified (pathgrid); } void PathgridEdgeListAdapter::removeRow(Record& record, int rowToRemove) const { Pathgrid pathgrid = record.get(); ESM::Pathgrid::EdgeList& edges = pathgrid.mEdges; if (rowToRemove < 0 || rowToRemove >= static_cast (edges.size())) throw std::runtime_error ("index out of range"); edges.erase(edges.begin()+rowToRemove); record.setModified (pathgrid); } void PathgridEdgeListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { Pathgrid pathgrid = record.get(); pathgrid.mEdges = static_cast &>(nestedTable).mNestedTable; record.setModified (pathgrid); } NestedTableWrapperBase* PathgridEdgeListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper(record.get().mEdges); } QVariant PathgridEdgeListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) throw std::runtime_error ("index out of range"); ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { case 0: return subRowIndex; case 1: return edge.mV0; case 2: return edge.mV1; default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); } } // ToDo: detect duplicates in mEdges void PathgridEdgeListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Pathgrid pathgrid = record.get(); if (subRowIndex < 0 || subRowIndex >= static_cast (pathgrid.mEdges.size())) throw std::runtime_error ("index out of range"); ESM::Pathgrid::Edge edge = pathgrid.mEdges[subRowIndex]; switch (subColIndex) { case 0: return; // return without saving case 1: edge.mV0 = value.toInt(); break; case 2: edge.mV1 = value.toInt(); break; default: throw std::runtime_error("Pathgrid edge subcolumn index out of range"); } pathgrid.mEdges[subRowIndex] = edge; record.setModified (pathgrid); } int PathgridEdgeListAdapter::getColumnsCount(const Record& record) const { return 3; } int PathgridEdgeListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mEdges.size()); } FactionReactionsAdapter::FactionReactionsAdapter () {} void FactionReactionsAdapter::addRow(Record& record, int position) const { ESM::Faction faction = record.get(); std::map& reactions = faction.mReactions; // blank row reactions.insert(std::make_pair("", 0)); record.setModified (faction); } void FactionReactionsAdapter::removeRow(Record& record, int rowToRemove) const { ESM::Faction faction = record.get(); std::map& reactions = faction.mReactions; if (rowToRemove < 0 || rowToRemove >= static_cast (reactions.size())) throw std::runtime_error ("index out of range"); // FIXME: how to ensure that the map entries correspond to table indicies? // WARNING: Assumed that the table view has the same order as std::map std::map::iterator iter = reactions.begin(); for(int i = 0; i < rowToRemove; ++i) iter++; reactions.erase(iter); record.setModified (faction); } void FactionReactionsAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESM::Faction faction = record.get(); faction.mReactions = static_cast >&>(nestedTable).mNestedTable; record.setModified (faction); } NestedTableWrapperBase* FactionReactionsAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mReactions); } QVariant FactionReactionsAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Faction faction = record.get(); std::map& reactions = faction.mReactions; if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) throw std::runtime_error ("index out of range"); // FIXME: how to ensure that the map entries correspond to table indicies? // WARNING: Assumed that the table view has the same order as std::map std::map::const_iterator iter = reactions.begin(); for(int i = 0; i < subRowIndex; ++i) iter++; switch (subColIndex) { case 0: return QString((*iter).first.c_str()); case 1: return (*iter).second; default: throw std::runtime_error("Faction reactions subcolumn index out of range"); } } void FactionReactionsAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESM::Faction faction = record.get(); std::map& reactions = faction.mReactions; if (subRowIndex < 0 || subRowIndex >= static_cast (reactions.size())) throw std::runtime_error ("index out of range"); // FIXME: how to ensure that the map entries correspond to table indicies? // WARNING: Assumed that the table view has the same order as std::map std::map::iterator iter = reactions.begin(); for(int i = 0; i < subRowIndex; ++i) iter++; std::string factionId = (*iter).first; int reaction = (*iter).second; switch (subColIndex) { case 0: { reactions.erase(iter); reactions.insert(std::make_pair(value.toString().toUtf8().constData(), reaction)); break; } case 1: { reactions[factionId] = value.toInt(); break; } default: throw std::runtime_error("Faction reactions subcolumn index out of range"); } record.setModified (faction); } int FactionReactionsAdapter::getColumnsCount(const Record& record) const { return 2; } int FactionReactionsAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mReactions.size()); } RegionSoundListAdapter::RegionSoundListAdapter () {} void RegionSoundListAdapter::addRow(Record& record, int position) const { ESM::Region region = record.get(); std::vector& soundList = region.mSoundList; // blank row ESM::Region::SoundRef soundRef; soundRef.mSound.assign(""); soundRef.mChance = 0; soundList.insert(soundList.begin()+position, soundRef); record.setModified (region); } void RegionSoundListAdapter::removeRow(Record& record, int rowToRemove) const { ESM::Region region = record.get(); std::vector& soundList = region.mSoundList; if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) throw std::runtime_error ("index out of range"); soundList.erase(soundList.begin()+rowToRemove); record.setModified (region); } void RegionSoundListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { ESM::Region region = record.get(); region.mSoundList = static_cast >&>(nestedTable).mNestedTable; record.setModified (region); } NestedTableWrapperBase* RegionSoundListAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mSoundList); } QVariant RegionSoundListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { ESM::Region region = record.get(); std::vector& soundList = region.mSoundList; if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) throw std::runtime_error ("index out of range"); ESM::Region::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: return QString(soundRef.mSound.toString().c_str()); case 1: return soundRef.mChance; default: throw std::runtime_error("Region sounds subcolumn index out of range"); } } void RegionSoundListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { ESM::Region region = record.get(); std::vector& soundList = region.mSoundList; if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) throw std::runtime_error ("index out of range"); ESM::Region::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break; case 1: soundRef.mChance = static_cast(value.toInt()); break; default: throw std::runtime_error("Region sounds subcolumn index out of range"); } region.mSoundList[subRowIndex] = soundRef; record.setModified (region); } int RegionSoundListAdapter::getColumnsCount(const Record& record) const { return 2; } int RegionSoundListAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mSoundList.size()); } InfoListAdapter::InfoListAdapter () {} void InfoListAdapter::addRow(Record& record, int position) const { throw std::logic_error ("cannot add a row to a fixed table"); } void InfoListAdapter::removeRow(Record& record, int rowToRemove) const { throw std::logic_error ("cannot add a row to a fixed table"); } void InfoListAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { throw std::logic_error ("table operation not supported"); } NestedTableWrapperBase* InfoListAdapter::table(const Record& record) const { throw std::logic_error ("table operation not supported"); } QVariant InfoListAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { Info info = record.get(); if (subColIndex == 0) return QString(info.mResultScript.c_str()); else throw std::runtime_error("Trying to access non-existing column in the nested table!"); } void InfoListAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Info info = record.get(); if (subColIndex == 0) info.mResultScript = value.toString().toStdString(); else throw std::runtime_error("Trying to access non-existing column in the nested table!"); record.setModified (info); } int InfoListAdapter::getColumnsCount(const Record& record) const { return 1; } int InfoListAdapter::getRowsCount(const Record& record) const { return 1; // fixed at size 1 } // ESM::DialInfo::SelectStruct.mSelectRule // 012345... // ^^^ ^^ // ||| || // ||| |+------------- condition variable string // ||| +-------------- comparison type, ['0'..'5']; e.g. !=, <, >=, etc // ||+---------------- function index (encoded, where function == '1') // |+----------------- function, ['1'..'C']; e.g. Global, Local, Not ID, etc // +------------------ unknown // InfoConditionAdapter::InfoConditionAdapter () {} void InfoConditionAdapter::addRow(Record& record, int position) const { Info info = record.get(); std::vector& conditions = info.mSelects; // blank row ESM::DialInfo::SelectStruct condStruct; condStruct.mSelectRule = "00000"; condStruct.mValue = ESM::Variant(); conditions.insert(conditions.begin()+position, condStruct); record.setModified (info); } void InfoConditionAdapter::removeRow(Record& record, int rowToRemove) const { Info info = record.get(); std::vector& conditions = info.mSelects; if (rowToRemove < 0 || rowToRemove >= static_cast (conditions.size())) throw std::runtime_error ("index out of range"); conditions.erase(conditions.begin()+rowToRemove); record.setModified (info); } void InfoConditionAdapter::setTable(Record& record, const NestedTableWrapperBase& nestedTable) const { Info info = record.get(); info.mSelects = static_cast >&>(nestedTable).mNestedTable; record.setModified (info); } NestedTableWrapperBase* InfoConditionAdapter::table(const Record& record) const { // deleted by dtor of NestedTableStoring return new NestedTableWrapper >(record.get().mSelects); } // See the mappings in MWDialogue::SelectWrapper::getArgument // from ESM::Attribute, ESM::Skill and MWMechanics::CreatureStats (for AI) static const std::map sEncToInfoFunc = { { "00", "Rank Low" }, { "01", "Rank High" }, { "02", "Rank Requirement" }, { "03", "Reputation" }, { "04", "Health Percent" }, { "05", "PC Reputation" }, { "06", "PC Level" }, { "07", "PC Health Percent" }, { "08", "PC Magicka" }, // dynamic stat { "09", "PC Fatigue" }, // dynamic stat { "10", "PC Strength" }, // attrib { "11", "PC Block" }, { "12", "PC Armoror" }, { "13", "PC Medium Armor" }, { "14", "PC Heavy Armor" }, { "15", "PC Blunt Weapon" }, { "16", "PC Long Blade" }, { "17", "PC Axe" }, { "18", "PC Spear" }, { "19", "PC Athletics" }, { "20", "PC Enchant" }, { "21", "PC Destruction" }, { "22", "PC Alteration" }, { "23", "PC Illusion" }, { "24", "PC Conjuration" }, { "25", "PC Mysticism" }, { "26", "PC Restoration" }, { "27", "PC Alchemy" }, { "28", "PC Unarmored" }, { "29", "PC Security" }, { "30", "PC Sneak" }, { "31", "PC Acrobatics" }, { "32", "PC Light Armor" }, { "33", "PC Short Blade" }, { "34", "PC Marksman" }, { "35", "PC Merchantile" }, { "36", "PC Speechcraft" }, { "37", "PC Hand To Hand" }, { "38", "PC Sex" }, { "39", "PC Expelled" }, { "40", "PC Common Disease" }, { "41", "PC Blight Disease" }, { "42", "PC Clothing Modifier" }, { "43", "PC Crime Level" }, { "44", "Same Sex" }, { "45", "Same Race" }, { "46", "Same Faction" }, { "47", "Faction Rank Difference" }, { "48", "Detected" }, { "49", "Alarmed" }, { "50", "Choice" }, { "51", "PC Intelligence" }, // attrib { "52", "PC Willpower" }, // attrib { "53", "PC Agility" }, // attrib { "54", "PC Speed" }, // attrib { "55", "PC Endurance" }, // attrib { "56", "PC Personality" }, // attrib { "57", "PC Luck" }, // attrib { "58", "PC Corpus" }, { "59", "Weather" }, { "60", "PC Vampire" }, { "61", "Level" }, { "62", "Attacked" }, { "63", "Talked To PC" }, { "64", "PC Health" }, // dynamic stat { "65", "Creature Target" }, { "66", "Friend Hit" }, { "67", "Fight" }, // AI { "68", "Hello" }, // AI { "69", "Alarm" }, // AI { "70", "Flee" }, // AI { "71", "Should Attack" }, { "72", "Werewolf" }, { "73", "PC Werewolf Kills" } }; QVariant InfoConditionAdapter::getData(const Record& record, int subRowIndex, int subColIndex) const { Info info = record.get(); std::vector& conditions = info.mSelects; if (subRowIndex < 0 || subRowIndex >= static_cast (conditions.size())) throw std::runtime_error ("index out of range"); switch (subColIndex) { case 0: { char condType = conditions[subRowIndex].mSelectRule[1]; switch (condType) { case '1': return 1; // Function case '2': return 2; // Global case '3': return 3; // Local case '4': return 4; // Journal case '5': return 5; // Item case '6': return 6; // Dead case '7': return 7; // Not ID case '8': return 8; // Not Factio case '9': return 9; // Not Class case 'A': return 10; // Not Race case 'B': return 11; // Not Cell case 'C': return 12; // Not Local default: return QVariant(); // TODO: log an error? } } case 1: { if (conditions[subRowIndex].mSelectRule[1] == '1') { // throws an exception if the encoding is not found return sEncToInfoFunc.at(conditions[subRowIndex].mSelectRule.substr(2, 2)).c_str(); } else return QString(conditions[subRowIndex].mSelectRule.substr(5).c_str()); } case 2: { char compType = conditions[subRowIndex].mSelectRule[4]; switch (compType) { case '0': return 3; // = case '1': return 0; // != case '2': return 4; // > case '3': return 5; // >= case '4': return 1; // < case '5': return 2; // <= default: return QVariant(); // TODO: log an error? } } case 3: { switch (conditions[subRowIndex].mValue.getType()) { case ESM::VT_String: { return QString::fromUtf8 (conditions[subRowIndex].mValue.getString().c_str()); } case ESM::VT_Int: case ESM::VT_Short: case ESM::VT_Long: { return conditions[subRowIndex].mValue.getInteger(); } case ESM::VT_Float: { return conditions[subRowIndex].mValue.getFloat(); } default: return QVariant(); } } default: throw std::runtime_error("Info condition subcolumn index out of range"); } } static const std::map sInfoFuncToEnc = { { "Alarm", "69" }, // AI { "Alarmed", "49" }, { "Attacked", "62" }, { "Choice", "50" }, { "Creature Target", "65" }, { "Detected", "48" }, { "Faction Rank Difference", "47" }, { "Fight", "67" }, // AI { "Flee", "70" }, // AI { "Friend Hit", "66" }, { "Health Percent", "04" }, { "Hello", "68" }, // AI { "Level", "61" }, { "PC Acrobatics", "31" }, { "PC Agility", "53" }, // attrib { "PC Alchemy", "27" }, { "PC Alteration", "22" }, { "PC Armoror", "12" }, { "PC Athletics", "19" }, { "PC Axe", "17" }, { "PC Blight Disease", "41" }, { "PC Block", "11" }, { "PC Blunt Weapon", "15" }, { "PC Clothing Modifier", "42" }, { "PC Common Disease", "40" }, { "PC Conjuration", "24" }, { "PC Corpus", "58" }, { "PC Crime Level", "43" }, { "PC Destruction", "21" }, { "PC Enchant", "20" }, { "PC Endurance", "55" }, // attrib { "PC Expelled", "39" }, { "PC Fatigue", "09" }, // dynamic stat { "PC Hand To Hand", "37" }, { "PC Health", "64" }, // dynamic stat { "PC Health Percent", "07" }, { "PC Heavy Armor", "14" }, { "PC Illusion", "23" }, { "PC Intelligence", "51" }, // attrib { "PC Level", "06" }, { "PC Light Armor", "32" }, { "PC Long Blade", "16" }, { "PC Luck", "57" }, // attrib { "PC Magicka", "08" }, // dynamic stat { "PC Marksman", "34" }, { "PC Medium Armor", "13" }, { "PC Merchantile", "35" }, { "PC Mysticism", "25" }, { "PC Personality", "56" }, // attrib { "PC Reputation", "05" }, { "PC Restoration", "26" }, { "PC Security", "29" }, { "PC Sex", "38" }, { "PC Short Blade", "33" }, { "PC Sneak", "30" }, { "PC Spear", "18" }, { "PC Speechcraft", "36" }, { "PC Speed", "54" }, // attrib { "PC Strength", "10" }, // attrib { "PC Unarmored", "28" }, { "PC Vampire", "60" }, { "PC Werewolf Kills", "73" }, { "PC Willpower", "52" }, // attrib { "Rank Requirement", "02" }, { "Rank High", "01" }, { "Rank Low", "00" }, { "Reputation", "03" }, { "Same Faction", "46" }, { "Same Race", "45" }, { "Same Sex", "44" }, { "Should Attack", "71" }, { "Talked To PC", "63" }, { "Weather", "59" }, { "Werewolf", "72" } }; void InfoConditionAdapter::setData(Record& record, const QVariant& value, int subRowIndex, int subColIndex) const { Info info = record.get(); std::vector& conditions = info.mSelects; if (subRowIndex < 0 || subRowIndex >= static_cast (conditions.size())) throw std::runtime_error ("index out of range"); switch (subColIndex) { case 0: { // See sInfoCondFunc in columns.cpp for the enum values switch (value.toInt()) { // FIXME: when these change the values of the other columns need to change // correspondingly (and automatically) case 1: conditions[subRowIndex].mSelectRule[1] = '1'; break; // Function case 2: conditions[subRowIndex].mSelectRule[1] = '2'; break; // Global case 3: conditions[subRowIndex].mSelectRule[1] = '3'; break; // Local case 4: conditions[subRowIndex].mSelectRule[1] = '4'; break; // Journal case 5: conditions[subRowIndex].mSelectRule[1] = '5'; break; // Item case 6: conditions[subRowIndex].mSelectRule[1] = '6'; break; // Dead case 7: conditions[subRowIndex].mSelectRule[1] = '7'; break; // Not ID case 8: conditions[subRowIndex].mSelectRule[1] = '8'; break; // Not Faction case 9: conditions[subRowIndex].mSelectRule[1] = '9'; break; // Not Class case 10: conditions[subRowIndex].mSelectRule[1] = 'A'; break; // Not Race case 11: conditions[subRowIndex].mSelectRule[1] = 'B'; break; // Not Cell case 12: conditions[subRowIndex].mSelectRule[1] = 'C'; break; // Not Local default: return; // return without saving } break; } case 1: { if (conditions[subRowIndex].mSelectRule[1] == '1') { // throws an exception if the function is not found const std::map::const_iterator it = sInfoFuncToEnc.find( value.toString().toUtf8().constData()); if (it != sInfoFuncToEnc.end()) { std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 2); rule.append(it->second); rule.append(std::string(1, conditions[subRowIndex].mSelectRule[4])); conditions[subRowIndex].mSelectRule = rule.append(value.toString().toUtf8().constData()); } else return; // return without saving; TODO: maybe log an error here } else { // FIXME: validate the string values before saving, based on the current function std::string rule = conditions[subRowIndex].mSelectRule.substr(0, 5); conditions[subRowIndex].mSelectRule = rule.append(value.toString().toUtf8().constData()); } break; } case 2: { // See sInfoCondComp in columns.cpp for the enum values switch (value.toInt()) { case 0: conditions[subRowIndex].mSelectRule[4] = '1'; break; // != case 1: conditions[subRowIndex].mSelectRule[4] = '4'; break; // < case 2: conditions[subRowIndex].mSelectRule[4] = '5'; break; // <= case 3: conditions[subRowIndex].mSelectRule[4] = '0'; break; // = case 4: conditions[subRowIndex].mSelectRule[4] = '2'; break; // > case 5: conditions[subRowIndex].mSelectRule[4] = '3'; break; // >= default: return; // return without saving } break; } case 3: { switch (conditions[subRowIndex].mValue.getType()) { case ESM::VT_String: { conditions[subRowIndex].mValue.setString (value.toString().toUtf8().constData()); break; } case ESM::VT_Int: case ESM::VT_Short: case ESM::VT_Long: { conditions[subRowIndex].mValue.setInteger (value.toInt()); break; } case ESM::VT_Float: { conditions[subRowIndex].mValue.setFloat (value.toFloat()); break; } default: break; } } default: throw std::runtime_error("Info condition subcolumn index out of range"); } record.setModified (info); } int InfoConditionAdapter::getColumnsCount(const Record& record) const { return 4; } int InfoConditionAdapter::getRowsCount(const Record& record) const { return static_cast(record.get().mSelects.size()); } }