diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 3902a009b..c994ced15 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -99,7 +99,7 @@ namespace CSMWorld Display_NestedDestinationsList, Display_PathgridPointList, Display_PathgridEdgeList, - Display_RegionSoundList, + Display_NestedHeader, Display_EnchantmentType, Display_BodyPartType, diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 06467a632..675352d35 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -2357,11 +2357,10 @@ namespace CSMWorld }; template - struct RegionSoundListColumn : public Column + struct NestedParentColumn : public Column { - RegionSoundListColumn () - : Column (Columns::ColumnId_RegionSounds, - ColumnBase::Display_RegionSoundList, ColumnBase::Flag_Dialogue) + NestedParentColumn (Columns::ColumnId id) + : Column (id, ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue) {} virtual QVariant get (const Record& record) const @@ -2376,11 +2375,10 @@ namespace CSMWorld }; - struct RegionSoundNameColumn : public NestableColumn + struct NestedStringColumn : public NestableColumn { - RegionSoundNameColumn () - : NestableColumn (Columns::ColumnId_SoundName, - ColumnBase::Display_String, ColumnBase::Flag_Dialogue) + NestedStringColumn (Columns::ColumnId id) + : NestableColumn (id, ColumnBase::Display_String, ColumnBase::Flag_Dialogue) {} virtual bool isEditable() const @@ -2389,11 +2387,10 @@ namespace CSMWorld } }; - struct RegionSoundChanceColumn : public NestableColumn + struct NestedIntegerColumn : public NestableColumn { - RegionSoundChanceColumn () - : NestableColumn (Columns::ColumnId_SoundChance, - ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) + NestedIntegerColumn (Columns::ColumnId id) + : NestableColumn (id, ColumnBase::Display_Integer, ColumnBase::Flag_Dialogue) {} virtual bool isEditable() const diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 39b3ea2e3..c9155a5ad 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -237,6 +237,10 @@ namespace CSMWorld { ColumnId_SoundName, "Name"}, { ColumnId_SoundChance, "Chance"}, + { ColumnId_FactionReactions, "Reactions"}, + //{ ColumnId_FactionID, "Faction ID"}, + { ColumnId_FactionReaction, "Reaction"}, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, @@ -263,6 +267,7 @@ namespace CSMWorld { ColumnId_Skill4, "Skill 4" }, { ColumnId_Skill5, "Skill 5" }, { ColumnId_Skill6, "Skill 6" }, + { ColumnId_Skill7, "Skill 7" }, { -1, 0 } // end marker }; diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 49a9208b0..531cf9972 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -226,6 +226,10 @@ namespace CSMWorld ColumnId_SoundName = 209, ColumnId_SoundChance = 210, + ColumnId_FactionReactions = 211, + //ColumnId_FactionID = 212, + ColumnId_FactionReaction = 213, + // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. ColumnId_UseValue1 = 0x10000, @@ -259,7 +263,8 @@ namespace CSMWorld ColumnId_Skill3 = 0x50002, ColumnId_Skill4 = 0x50003, ColumnId_Skill5 = 0x50004, - ColumnId_Skill6 = 0x50005 + ColumnId_Skill6 = 0x50005, + ColumnId_Skill7 = 0x50006 }; std::string getName (ColumnId column); diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index c387298d2..3352dd30e 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -108,6 +108,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mFactions.addColumn (new HiddenColumn); for (int i=0; i<7; ++i) mFactions.addColumn (new SkillsColumn (i)); + // Faction Reactions + NestedParentColumn *reactions = + new NestedParentColumn (Columns::ColumnId_FactionReactions); + mFactions.addColumn (reactions); + mFactions.addAdapter (std::make_pair(reactions, new FactionReactionsAdapter ())); + mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_Faction)); + mFactions.getNestableColumn(mFactions.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_FactionReaction)); mRaces.addColumn (new StringIdColumn); mRaces.addColumn (new RecordStateColumn); @@ -140,12 +149,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRegions.addColumn (new NameColumn); mRegions.addColumn (new MapColourColumn); mRegions.addColumn (new SleepListColumn); - // see idadapterimpl.hpp and columnimp.hpp - RegionSoundListColumn *soundList = new RegionSoundListColumn (); + // Region Sounds + NestedParentColumn *soundList = + new NestedParentColumn (Columns::ColumnId_RegionSounds); mRegions.addColumn (soundList); mRegions.addAdapter (std::make_pair(soundList, new RegionSoundListAdapter ())); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundNameColumn ()); - mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn(new RegionSoundChanceColumn ()); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( + new NestedStringColumn (Columns::ColumnId_SoundName)); + mRegions.getNestableColumn(mRegions.getColumns()-1)->addColumn( + new NestedIntegerColumn (Columns::ColumnId_SoundChance)); mBirthsigns.addColumn (new StringIdColumn); mBirthsigns.addColumn (new RecordStateColumn); @@ -341,7 +353,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mClasses), UniversalId::Type_Class); - addModel (new IdTable (&mFactions), UniversalId::Type_Faction); + addModel (new IdTree (&mFactions, &mFactions), UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Script); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 329aceaf7..858f82639 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -69,7 +69,7 @@ namespace CSMWorld IdCollection mGmsts; IdCollection mSkills; IdCollection mClasses; - IdCollection mFactions; + NestedIdCollection mFactions; IdCollection mRaces; IdCollection mSounds; IdCollection mScripts; diff --git a/apps/opencs/model/world/idadapterimp.hpp b/apps/opencs/model/world/idadapterimp.hpp index d5a44aea2..00f7b1831 100644 --- a/apps/opencs/model/world/idadapterimp.hpp +++ b/apps/opencs/model/world/idadapterimp.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "idadapter.hpp" #include "nestedtablewrapper.hpp" @@ -218,7 +219,12 @@ namespace CSMWorld virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const { - ESM::Pathgrid::Edge edge = record.get().mEdges[subRowIndex]; + ESXRecordT 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; @@ -233,6 +239,10 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { ESXRecordT 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) { @@ -258,6 +268,126 @@ namespace CSMWorld } }; + template + class FactionReactionsAdapter : public NestedIdAdapter + { + public: + FactionReactionsAdapter () {} + + virtual void addNestedRow(Record& record, int position) const + { + ESXRecordT faction = record.get(); + + std::map& reactions = faction.mReactions; + + // blank row + reactions.insert(std::make_pair("", 0)); + + record.setModified (faction); + } + + virtual void removeNestedRow(Record& record, int rowToRemove) const + { + ESXRecordT 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::const_iterator iter = reactions.begin(); + for(int i = 0; i < rowToRemove; ++i) + iter++; + reactions.erase(iter); + + record.setModified (faction); + } + + virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const + { + record.get().mReactions = + static_cast >&>(nestedTable).mNestedTable; + } + + virtual NestedTableWrapperBase* nestedTable(const Record& record) const + { + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(record.get().mReactions); + } + + virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const + { + ESXRecordT 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"); + } + } + + virtual void setNestedData(Record& record, const QVariant& value, + int subRowIndex, int subColIndex) const + { + ESXRecordT 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++; + + 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); + } + + virtual int getNestedColumnsCount(const Record& record) const + { + return 2; + } + + virtual int getNestedRowsCount(const Record& record) const + { + return static_cast(record.get().mReactions.size()); + } + }; + template class RegionSoundListAdapter : public NestedIdAdapter { @@ -268,10 +398,10 @@ namespace CSMWorld { ESXRecordT region = record.get(); - std::vector& soundList = region.mSoundList; + std::vector& soundList = region.mSoundList; // blank row - ESXRecordT::SoundRef soundRef; + typename ESXRecordT::SoundRef soundRef; soundRef.mSound.assign(""); soundRef.mChance = 0; @@ -284,7 +414,7 @@ namespace CSMWorld { ESXRecordT region = record.get(); - std::vector& soundList = region.mSoundList; + std::vector& soundList = region.mSoundList; if (rowToRemove < 0 || rowToRemove >= static_cast (soundList.size())) throw std::runtime_error ("index out of range"); @@ -297,18 +427,25 @@ namespace CSMWorld virtual void setNestedTable(Record& record, const NestedTableWrapperBase& nestedTable) const { record.get().mSoundList = - static_cast >&>(nestedTable).mNestedTable; + static_cast >&>(nestedTable).mNestedTable; } virtual NestedTableWrapperBase* nestedTable(const Record& record) const { // deleted by dtor of NestedTableStoring - return new NestedTableWrapper >(record.get().mSoundList); + return new NestedTableWrapper >(record.get().mSoundList); } virtual QVariant getNestedData(const Record& record, int subRowIndex, int subColIndex) const { - ESXRecordT::SoundRef soundRef = record.get().mSoundList[subRowIndex]; + ESXRecordT region = record.get(); + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: return QString(soundRef.mSound.toString().c_str()); @@ -321,7 +458,13 @@ namespace CSMWorld int subRowIndex, int subColIndex) const { ESXRecordT region = record.get(); - ESXRecordT::SoundRef soundRef = region.mSoundList[subRowIndex]; + + std::vector& soundList = region.mSoundList; + + if (subRowIndex < 0 || subRowIndex >= static_cast (soundList.size())) + throw std::runtime_error ("index out of range"); + + typename ESXRecordT::SoundRef soundRef = soundList[subRowIndex]; switch (subColIndex) { case 0: soundRef.mSound.assign(value.toString().toUtf8().constData()); break;