From 7494340b66500c08aa6f6f7fe41c957d293cdcab Mon Sep 17 00:00:00 2001 From: cc9cii Date: Mon, 18 May 2015 22:08:36 +1000 Subject: [PATCH 1/8] Add the remaining NPC data for editing with dialogue subview. Should resolve Bug #2547. --- apps/opencs/model/world/columns.cpp | 15 + apps/opencs/model/world/columns.hpp | 15 + apps/opencs/model/world/refidadapterimp.cpp | 350 +++++++++++++++++++- apps/opencs/model/world/refidadapterimp.hpp | 95 ++++++ apps/opencs/model/world/refidcollection.cpp | 56 ++++ apps/opencs/view/world/dialoguesubview.cpp | 6 +- 6 files changed, 535 insertions(+), 2 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 89ee6258b..2bfe79464 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -281,6 +281,21 @@ namespace CSMWorld { ColumnId_InfoCondValue, "Value" }, { ColumnId_OriginalCell, "Original Cell" }, + { ColumnId_NpcAttributes, "Attributes" }, + { ColumnId_NpcSkills, "Skills" }, + { ColumnId_UChar, "Value [0..255]" }, + { ColumnId_NpcMisc, "Misc" }, + { ColumnId_NpcLevel, "Level" }, + { ColumnId_NpcFactionID, "Faction ID" }, + { ColumnId_NpcHealth, "Health" }, + { ColumnId_NpcMana, "Mana" }, + { ColumnId_NpcFatigue, "Fatigue" }, + { ColumnId_NpcDisposition, "Disposition" }, + { ColumnId_NpcReputation, "Reputation" }, + { ColumnId_NpcRank, "Rank" }, + { ColumnId_NpcGold, "Gold" }, + { ColumnId_NpcPersistence, "Persistent" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index f971f3fd8..b2234ad49 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -272,6 +272,21 @@ namespace CSMWorld ColumnId_OriginalCell = 247, + ColumnId_NpcAttributes = 248, + ColumnId_NpcSkills = 249, + ColumnId_UChar = 250, + ColumnId_NpcMisc = 251, + ColumnId_NpcLevel = 252, + ColumnId_NpcFactionID = 253, + ColumnId_NpcHealth = 254, + ColumnId_NpcMana = 255, + ColumnId_NpcFatigue = 256, + ColumnId_NpcDisposition = 257, + ColumnId_NpcReputation = 258, + ColumnId_NpcRank = 259, + ColumnId_NpcGold = 260, + ColumnId_NpcPersistence = 261, + // 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, diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index 98c1b6f0f..a5f0b2244 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -468,7 +468,10 @@ CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) mClass(NULL), mFaction(NULL), mHair(NULL), - mHead(NULL) + mHead(NULL), + mAttributes(NULL), + mSkills(NULL), + mMisc(NULL) {} CSMWorld::NpcRefIdAdapter::NpcRefIdAdapter (const NpcColumns& columns) @@ -496,6 +499,17 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mHead) return QString::fromUtf8 (record.get().mHead.c_str()); + if (column==mColumns.mAttributes || column==mColumns.mSkills) + { + if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) + return QVariant(); + else + return true; + } + + if (column==mColumns.mMisc) + return true; + std::map::const_iterator iter = mColumns.mFlags.find (column); @@ -538,6 +552,340 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d } } +CSMWorld::NpcAttributesRefIdAdapter::NpcAttributesRefIdAdapter () +{} + +void CSMWorld::NpcAttributesRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcAttributesRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + + // store the whole struct + npc.mNpdt52 = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (npc); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mNpdt52); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + + if (subColIndex == 0) + switch (subRowIndex) + { + case 0: return QString("Strength"); + case 1: return QString("Intelligence"); + case 2: return QString("Willpower"); + case 3: return QString("Agility"); + case 4: return QString("Speed"); + case 5: return QString("Endurance"); + case 6: return QString("Personality"); + case 7: return QString("Luck"); + default: return QVariant(); // throw an exception here? + } + else if (subColIndex == 1) + switch (subRowIndex) + { + case 0: return static_cast(npcStruct.mStrength); + case 1: return static_cast(npcStruct.mIntelligence); + case 2: return static_cast(npcStruct.mWillpower); + case 3: return static_cast(npcStruct.mAgility); + case 4: return static_cast(npcStruct.mSpeed); + case 5: return static_cast(npcStruct.mEndurance); + case 6: return static_cast(npcStruct.mPersonality); + case 7: return static_cast(npcStruct.mLuck); + default: return QVariant(); // throw an exception here? + } + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::NpcAttributesRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + + if (subColIndex == 1) + switch(subRowIndex) + { + case 0: npcStruct.mStrength = static_cast(value.toInt()); break; + case 1: npcStruct.mIntelligence = static_cast(value.toInt()); break; + case 2: npcStruct.mWillpower = static_cast(value.toInt()); break; + case 3: npcStruct.mAgility = static_cast(value.toInt()); break; + case 4: npcStruct.mSpeed = static_cast(value.toInt()); break; + case 5: npcStruct.mEndurance = static_cast(value.toInt()); break; + case 6: npcStruct.mPersonality = static_cast(value.toInt()); break; + case 7: npcStruct.mLuck = static_cast(value.toInt()); break; + default: return; // throw an exception here? + } + else + return; // throw an exception here? + + record.setModified (npc); +} + +int CSMWorld::NpcAttributesRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 2; +} + +int CSMWorld::NpcAttributesRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 8 attributes + return 8; +} + +CSMWorld::NpcSkillsRefIdAdapter::NpcSkillsRefIdAdapter () +{} + +void CSMWorld::NpcSkillsRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcSkillsRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + // Do nothing, this table cannot be changed by the user +} + +void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + + // store the whole struct + npc.mNpdt52 = + static_cast > &>(nestedTable).mNestedTable.at(0); + + record.setModified (npc); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + // return the whole struct + std::vector wrap; + wrap.push_back(record.get().mNpdt52); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); +} + +QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; + + if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) + std::cout << "getNestedDatat index" << std::endl; + //throw std::runtime_error ("index out of range"); + + if (subColIndex == 0) + return QString(ESM::Skill::sSkillNames[subRowIndex].c_str()); + else if (subColIndex == 1) + return static_cast(npcStruct.mSkills[subRowIndex]); + else + return QVariant(); // throw an exception here? +} + +void CSMWorld::NpcSkillsRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; + + if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) + std::cout << "setNestedDatat index" << std::endl; + //throw std::runtime_error ("index out of range"); + + if (subColIndex == 1) + npcStruct.mSkills[subRowIndex] = static_cast(value.toInt()); + else + return; // throw an exception here? + + record.setModified (npc); +} + +int CSMWorld::NpcSkillsRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 2; +} + +int CSMWorld::NpcSkillsRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + // There are 27 skills + return ESM::Skill::Length; +} + +CSMWorld::NpcMiscRefIdAdapter::NpcMiscRefIdAdapter () +{} + +CSMWorld::NpcMiscRefIdAdapter::~NpcMiscRefIdAdapter() +{} + +void CSMWorld::NpcMiscRefIdAdapter::addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const +{ + throw std::logic_error ("cannot add a row to a fixed table"); +} + +void CSMWorld::NpcMiscRefIdAdapter::removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const +{ + throw std::logic_error ("cannot remove a row to a fixed table"); +} + +void CSMWorld::NpcMiscRefIdAdapter::setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const +{ + throw std::logic_error ("table operation not supported"); +} + +CSMWorld::NestedTableWrapperBase* CSMWorld::NpcMiscRefIdAdapter::nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const +{ + throw std::logic_error ("table operation not supported"); +} + +QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const +{ + const Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); + + bool autoCalc = (record.get().mFlags & ESM::NPC::Autocalc) != 0; + + if (autoCalc) + switch (subColIndex) + { + case 0: return static_cast(record.get().mNpdt12.mLevel); + case 1: return QVariant(); + case 2: return QVariant(); + case 3: return QVariant(); + case 4: return QVariant(); + case 5: return static_cast(record.get().mNpdt12.mDisposition); + case 6: return static_cast(record.get().mNpdt12.mReputation); + case 7: return static_cast(record.get().mNpdt12.mRank); + case 8: return record.get().mNpdt12.mGold; + case 9: return record.get().mPersistent == true; + default: return QVariant(); // throw an exception here? + } + else + switch (subColIndex) + { + case 0: return static_cast(record.get().mNpdt52.mLevel); + case 1: return static_cast(record.get().mNpdt52.mFactionID); + case 2: return static_cast(record.get().mNpdt52.mHealth); + case 3: return static_cast(record.get().mNpdt52.mMana); + case 4: return static_cast(record.get().mNpdt52.mFatigue); + case 5: return static_cast(record.get().mNpdt52.mDisposition); + case 6: return static_cast(record.get().mNpdt52.mReputation); + case 7: return static_cast(record.get().mNpdt52.mRank); + case 8: return record.get().mNpdt52.mGold; + case 9: return record.get().mPersistent == true; + default: return QVariant(); // throw an exception here? + } +} + +void CSMWorld::NpcMiscRefIdAdapter::setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const +{ + Record& record = + static_cast&> (data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Npc))); + ESM::NPC npc = record.get(); + + bool autoCalc = (record.get().mFlags & ESM::NPC::Autocalc) != 0; + + if (autoCalc) + switch(subColIndex) + { + case 0: npc.mNpdt12.mLevel = static_cast(value.toInt()); break; + case 1: return; + case 2: return; + case 3: return; + case 4: return; + case 5: npc.mNpdt12.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt12.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt12.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt12.mGold = value.toInt(); break; + case 9: npc.mPersistent = value.toBool(); break; + default: return; // throw an exception here? + } + else + switch(subColIndex) + { + case 0: npc.mNpdt52.mLevel = static_cast(value.toInt()); break; + case 1: npc.mNpdt52.mFactionID = static_cast(value.toInt()); break; + case 2: npc.mNpdt52.mHealth = static_cast(value.toInt()); break; + case 3: npc.mNpdt52.mMana = static_cast(value.toInt()); break; + case 4: npc.mNpdt52.mFatigue = static_cast(value.toInt()); break; + case 5: npc.mNpdt52.mDisposition = static_cast(value.toInt()); break; + case 6: npc.mNpdt52.mReputation = static_cast(value.toInt()); break; + case 7: npc.mNpdt52.mRank = static_cast(value.toInt()); break; + case 8: npc.mNpdt52.mGold = value.toInt(); break; + case 9: npc.mPersistent = value.toBool(); break; + default: return; // throw an exception here? + } + + record.setModified (npc); +} + +int CSMWorld::NpcMiscRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const +{ + return 10; // Level, FactionID, Health, Mana, Fatigue, Disposition, Reputation, Rank, Gold, Persist +} + +int CSMWorld::NpcMiscRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const +{ + return 1; // fixed at size 1 +} + CSMWorld::WeaponColumns::WeaponColumns (const EnchantableColumns& columns) : EnchantableColumns (columns) {} diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 61e8115c0..143b46c44 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -792,6 +792,9 @@ namespace CSMWorld 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 NpcColumns (const ActorColumns& actorColumns); }; @@ -842,8 +845,100 @@ namespace CSMWorld ///< If the data type does not match an exception is thrown. }; + class NestedRefIdAdapterBase; + class NpcAttributesRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + NpcAttributesRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class NpcSkillsRefIdAdapter : public NestedRefIdAdapterBase + { + public: + + NpcSkillsRefIdAdapter (); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + + class NpcMiscRefIdAdapter : public NestedRefIdAdapterBase + { + NpcMiscRefIdAdapter (const NpcMiscRefIdAdapter&); + NpcMiscRefIdAdapter& operator= (const NpcMiscRefIdAdapter&); + + public: + + NpcMiscRefIdAdapter (); + virtual ~NpcMiscRefIdAdapter(); + + virtual void addNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int position) const; + + virtual void removeNestedRow (const RefIdColumn *column, + RefIdData& data, int index, int rowToRemove) const; + + virtual void setNestedTable (const RefIdColumn* column, + RefIdData& data, int index, const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* nestedTable (const RefIdColumn* column, + const RefIdData& data, int index) const; + + virtual QVariant getNestedData (const RefIdColumn *column, + const RefIdData& data, int index, int subRowIndex, int subColIndex) const; + + virtual void setNestedData (const RefIdColumn *column, + RefIdData& data, int row, const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; + + virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; + }; + template class EffectsListAdapter; diff --git a/apps/opencs/model/world/refidcollection.cpp b/apps/opencs/model/world/refidcollection.cpp index 1941c505a..9d9e9826a 100644 --- a/apps/opencs/model/world/refidcollection.cpp +++ b/apps/opencs/model/world/refidcollection.cpp @@ -427,6 +427,62 @@ CSMWorld::RefIdCollection::RefIdCollection() npcColumns.mFlags.insert (std::make_pair (metalBlood, ESM::NPC::Metal)); + // Need a way to add a table of stats and values (rather than adding a long list of + // entries in the dialogue subview) E.g. attributes+stats(health, mana, fatigue), skills + // These needs to be driven from the autocalculated setting. + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcAttributes, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + npcColumns.mAttributes = &mColumns.back(); + std::map attrMap; + attrMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcAttributesRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), attrMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcAttributes, CSMWorld::ColumnBase::Display_String, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); + + // Nested table + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcSkills, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue)); + npcColumns.mSkills = &mColumns.back(); + std::map skillsMap; + skillsMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcSkillsRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), skillsMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcSkills, CSMWorld::ColumnBase::Display_String, false, false)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_UChar, CSMWorld::ColumnBase::Display_Integer)); + + // Nested list + mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcMisc, + ColumnBase::Display_NestedHeader, ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + npcColumns.mMisc = &mColumns.back(); + std::map miscMap; + miscMap.insert(std::make_pair(UniversalId::Type_Npc, new NpcMiscRefIdAdapter())); + mNestedAdapters.push_back (std::make_pair(&mColumns.back(), miscMap)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcLevel, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcFactionID, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcHealth, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcMana, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcFatigue, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcDisposition, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcReputation, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcRank, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcGold, CSMWorld::ColumnBase::Display_Integer)); + mColumns.back().addColumn( + new RefIdColumn (Columns::ColumnId_NpcPersistence, CSMWorld::ColumnBase::Display_Boolean)); + WeaponColumns weaponColumns (enchantableColumns); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponType, ColumnBase::Display_WeaponType)); diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 0d0e82dbf..4b4afc666 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/columnbase.hpp" @@ -511,7 +512,7 @@ void CSVWorld::EditWidget::remake(int row) mNestedTableMapper->setModel(mNestedModels.back()); // FIXME: lack MIME support? mNestedTableDispatcher = - new DialogueDelegateDispatcher (this, mTable, mCommandDispatcher, mDocument, mNestedModels.back()); + new DialogueDelegateDispatcher (0/*this*/, mTable, mCommandDispatcher, mDocument, mNestedModels.back()); mNestedTableMapper->setItemDelegate(mNestedTableDispatcher); int columnCount = @@ -763,6 +764,9 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) CSMWorld::RecordBase::State state = static_cast(mTable->data (mTable->index (currentIndex.row(), 1)).toInt()); mEditWidget->setDisabled (state==CSMWorld::RecordBase::State_Deleted || mLocked); + int y = mEditWidget->verticalScrollBar()->value(); + mEditWidget->remake (index.row()); + mEditWidget->verticalScrollBar()->setValue(y); } } From 0ecfd9119f1c7ec5c2326c7d15a1b1a1813fa354 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 19 May 2015 06:56:38 +1000 Subject: [PATCH 2/8] Add the remaining Race data for editing with dialogue subview. Should resolve Bug #2546. --- apps/opencs/model/world/columnbase.cpp | 1 + apps/opencs/model/world/columnbase.hpp | 1 + apps/opencs/model/world/columns.cpp | 8 + apps/opencs/model/world/columns.hpp | 7 + apps/opencs/model/world/data.cpp | 18 +++ .../model/world/nestedcoladapterimp.cpp | 153 ++++++++++++++++++ .../model/world/nestedcoladapterimp.hpp | 51 ++++++ apps/opencs/view/doc/viewmanager.cpp | 3 +- 8 files changed, 241 insertions(+), 1 deletion(-) diff --git a/apps/opencs/model/world/columnbase.cpp b/apps/opencs/model/world/columnbase.cpp index cf125aa63..087a1df7b 100644 --- a/apps/opencs/model/world/columnbase.cpp +++ b/apps/opencs/model/world/columnbase.cpp @@ -84,6 +84,7 @@ bool CSMWorld::ColumnBase::isId (Display display) Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, + Display_RaceSkill, Display_None }; diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 2d2513774..d6dd4b291 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -119,6 +119,7 @@ namespace CSMWorld Display_InfoCondFunc, Display_InfoCondVar, Display_InfoCondComp, + Display_RaceSkill, //top level columns that nest other columns Display_NestedHeader diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 2bfe79464..daf537c0c 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -296,6 +296,13 @@ namespace CSMWorld { ColumnId_NpcGold, "Gold" }, { ColumnId_NpcPersistence, "Persistent" }, + { ColumnId_RaceAttributes, "Attributes" }, + { ColumnId_RaceMaleValue, "Male" }, + { ColumnId_RaceFemaleValue, "Female" }, + { ColumnId_RaceSkillBonus, "Skill Bonus" }, + { ColumnId_RaceSkill, "Skills" }, + { ColumnId_RaceBonus, "Bonus" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, @@ -566,6 +573,7 @@ namespace // FIXME: don't have dynamic value enum delegate, use Display_String for now //case CSMWorld::Columns::ColumnId_InfoCond: return sInfoCond; case CSMWorld::Columns::ColumnId_InfoCondComp: return sInfoCondComp; + case CSMWorld::Columns::ColumnId_RaceSkill: return sSkills; default: return 0; } diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index b2234ad49..85276a695 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -287,6 +287,13 @@ namespace CSMWorld ColumnId_NpcGold = 260, ColumnId_NpcPersistence = 261, + ColumnId_RaceAttributes = 262, + ColumnId_RaceMaleValue = 263, + ColumnId_RaceFemaleValue = 264, + ColumnId_RaceSkillBonus = 265, + ColumnId_RaceSkill = 266, + ColumnId_RaceBonus = 267, + // 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, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index e2fab0a25..fa7e48a0e 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -136,6 +136,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter ())); mRaces.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); + // Race attributes + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceAttributes)); + index = mRaces.getColumns()-1; + mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceAttributeAdapter())); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceAttributes, ColumnBase::Display_String, false)); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceMaleValue, ColumnBase::Display_Integer)); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceFemaleValue, ColumnBase::Display_Integer)); + // Race skill bonus + mRaces.addColumn (new NestedParentColumn (Columns::ColumnId_RaceSkillBonus)); + index = mRaces.getColumns()-1; + mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new RaceSkillsBonusAdapter())); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceSkill, ColumnBase::Display_RaceSkill)); + mRaces.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_RaceBonus, ColumnBase::Display_Integer)); mSounds.addColumn (new StringIdColumn); mSounds.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index a0d764576..7efe14dee 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -880,4 +880,157 @@ namespace CSMWorld { return static_cast(record.get().mSelects.size()); } + + RaceAttributeAdapter::RaceAttributeAdapter () {} + + void RaceAttributeAdapter::addRow(Record& record, int position) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceAttributeAdapter::removeRow(Record& record, int rowToRemove) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceAttributeAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + ESM::Race race = record.get(); + + race.mData = + static_cast >&>(nestedTable).mNestedTable.at(0); + + record.setModified (race); + } + + NestedTableWrapperBase* RaceAttributeAdapter::table(const Record& record) const + { + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); + } + + QVariant RaceAttributeAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return QString(ESM::Attribute::sAttributeNames[subRowIndex].c_str()); + case 1: return race.mData.mAttributeValues[subRowIndex].mMale; + case 2: return race.mData.mAttributeValues[subRowIndex].mFemale; + default: throw std::runtime_error("Race Attribute subcolumn index out of range"); + } + } + + void RaceAttributeAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= ESM::Attribute::Length) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return; // throw an exception here? + case 1: race.mData.mAttributeValues[subRowIndex].mMale = value.toInt(); break; + case 2: race.mData.mAttributeValues[subRowIndex].mFemale = value.toInt(); break; + default: throw std::runtime_error("Race Attribute subcolumn index out of range"); + } + + record.setModified (race); + } + + int RaceAttributeAdapter::getColumnsCount(const Record& record) const + { + return 3; // attrib, male, female + } + + int RaceAttributeAdapter::getRowsCount(const Record& record) const + { + return ESM::Attribute::Length; // there are 8 attributes + } + + RaceSkillsBonusAdapter::RaceSkillsBonusAdapter () {} + + void RaceSkillsBonusAdapter::addRow(Record& record, int position) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceSkillsBonusAdapter::removeRow(Record& record, int rowToRemove) const + { + // Do nothing, this table cannot be changed by the user + } + + void RaceSkillsBonusAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + ESM::Race race = record.get(); + + race.mData = + static_cast >&>(nestedTable).mNestedTable.at(0); + + record.setModified (race); + } + + NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record& record) const + { + std::vector wrap; + wrap.push_back(record.get().mData); + // deleted by dtor of NestedTableStoring + return new NestedTableWrapper >(wrap); + } + + QVariant RaceSkillsBonusAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast(sizeof(race.mData.mBonus)/sizeof(race.mData.mBonus[0]))) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: return race.mData.mBonus[subRowIndex].mSkill; // can be -1 + case 1: return race.mData.mBonus[subRowIndex].mBonus; + default: throw std::runtime_error("Race skill bonus subcolumn index out of range"); + } + } + + void RaceSkillsBonusAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + ESM::Race race = record.get(); + + if (subRowIndex < 0 || subRowIndex >= static_cast(sizeof(race.mData.mBonus)/sizeof(race.mData.mBonus[0]))) + throw std::runtime_error ("index out of range"); + + switch (subColIndex) + { + case 0: race.mData.mBonus[subRowIndex].mSkill = value.toInt(); break; // can be -1 + case 1: race.mData.mBonus[subRowIndex].mBonus = value.toInt(); break; + default: throw std::runtime_error("Race skill bonus subcolumn index out of range"); + } + + record.setModified (race); + } + + int RaceSkillsBonusAdapter::getColumnsCount(const Record& record) const + { + return 2; // skill, bonus + } + + int RaceSkillsBonusAdapter::getRowsCount(const Record& record) const + { + // there are 7 skill bonuses + return static_cast(sizeof(record.get().mData.mBonus)/sizeof(record.get().mData.mBonus[0])); + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 776a908ba..4b1e2cd09 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -8,6 +8,7 @@ #include // for converting magic effect id to string & back #include // for converting skill names #include // for converting attributes +#include #include "nestedcolumnadapter.hpp" #include "nestedtablewrapper.hpp" @@ -437,6 +438,56 @@ namespace CSMWorld virtual int getRowsCount(const Record& record) const; }; + + class RaceAttributeAdapter : public NestedColumnAdapter + { + public: + RaceAttributeAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; + + class RaceSkillsBonusAdapter : public NestedColumnAdapter + { + public: + RaceSkillsBonusAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; } #endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H diff --git a/apps/opencs/view/doc/viewmanager.cpp b/apps/opencs/view/doc/viewmanager.cpp index 6362f9659..97b7aac19 100644 --- a/apps/opencs/view/doc/viewmanager.cpp +++ b/apps/opencs/view/doc/viewmanager.cpp @@ -92,7 +92,8 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager) { CSMWorld::ColumnBase::Display_AiPackageType, CSMWorld::Columns::ColumnId_AiPackageType, false }, { CSMWorld::ColumnBase::Display_YesNo, CSMWorld::Columns::ColumnId_AiWanderRepeat, false }, { CSMWorld::ColumnBase::Display_InfoCondFunc, CSMWorld::Columns::ColumnId_InfoCondFunc, false }, - { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false } + { CSMWorld::ColumnBase::Display_InfoCondComp, CSMWorld::Columns::ColumnId_InfoCondComp, false }, + { CSMWorld::ColumnBase::Display_RaceSkill, CSMWorld::Columns::ColumnId_RaceSkill, true }, }; for (std::size_t i=0; i Date: Tue, 19 May 2015 19:19:52 +1000 Subject: [PATCH 3/8] Fix occasional crash with DialogueSubView, e.g. when deleting a row of a subtable. --- apps/opencs/view/world/dialoguesubview.cpp | 57 ++++++++++++---------- apps/opencs/view/world/dialoguesubview.hpp | 2 +- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index 4b4afc666..fee302e2c 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -348,16 +348,19 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() CSVWorld::EditWidget::~EditWidget() { for (unsigned i = 0; i < mNestedModels.size(); ++i) - { delete mNestedModels[i]; - } - delete mNestedTableDispatcher; + + if (mDispatcher) + delete mDispatcher; + + if (mNestedTableDispatcher) + delete mNestedTableDispatcher; } CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher, CSMDoc::Document& document, bool createAndDelete) : -mDispatcher(this, table, commandDispatcher, document), +mDispatcher(0), mNestedTableDispatcher(NULL), QScrollArea(parent), mWidgetMapper(NULL), @@ -369,41 +372,41 @@ mTable(table) { remake (row); - connect(&mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), + connect(mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); } void CSVWorld::EditWidget::remake(int row) { for (unsigned i = 0; i < mNestedModels.size(); ++i) - { delete mNestedModels[i]; - } - mNestedModels.clear(); - delete mNestedTableDispatcher; - if (mMainWidget) - { - delete mMainWidget; - mMainWidget = 0; - } - mMainWidget = new QWidget (this); + mNestedModels.clear(); + + if (mDispatcher) + delete mDispatcher; + mDispatcher = new DialogueDelegateDispatcher(0/*this*/, mTable, mCommandDispatcher, mDocument); + + if (mNestedTableDispatcher) + delete mNestedTableDispatcher; //not sure if widget mapper can handle deleting the widgets that were mapped if (mWidgetMapper) - { delete mWidgetMapper; - mWidgetMapper = 0; - } - if (mNestedTableMapper) - { - delete mNestedTableMapper; - mNestedTableMapper = 0; - } - mWidgetMapper = new QDataWidgetMapper (this); + mWidgetMapper = new QDataWidgetMapper (this); mWidgetMapper->setModel(mTable); - mWidgetMapper->setItemDelegate(&mDispatcher); + mWidgetMapper->setItemDelegate(mDispatcher); + + if (mNestedTableMapper) + delete mNestedTableMapper; + + if (mMainWidget) + { + QWidget *del = this->takeWidget(); + del->deleteLater(); + } + mMainWidget = new QWidget (this); QFrame* line = new QFrame(mMainWidget); line->setObjectName(QString::fromUtf8("line")); @@ -476,8 +479,8 @@ void CSVWorld::EditWidget::remake(int row) } else if (!(flags & CSMWorld::ColumnBase::Flag_Dialogue_List)) { - mDispatcher.makeDelegate (display); - QWidget* editor = mDispatcher.makeEditor (display, (mTable->index (row, i))); + mDispatcher->makeDelegate (display); + QWidget* editor = mDispatcher->makeEditor (display, (mTable->index (row, i))); if (editor) { diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index b5a44d266..8783d935f 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -165,7 +165,7 @@ namespace CSVWorld Q_OBJECT QDataWidgetMapper *mWidgetMapper; QDataWidgetMapper *mNestedTableMapper; - DialogueDelegateDispatcher mDispatcher; + DialogueDelegateDispatcher *mDispatcher; DialogueDelegateDispatcher *mNestedTableDispatcher; QWidget* mMainWidget; CSMWorld::IdTable* mTable; From b27a879352b155205a9809f567007e97bf7dd1a6 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Tue, 19 May 2015 22:01:40 +1000 Subject: [PATCH 4/8] Add the remaining Cell data for editing with dialogue subview. Should resolve Bug #2551. - NOTE: the interior water flag and water level logic needs reviewing - does not automatically disable region names for interiors without mQuasiEx flag - Colour values can't be entered as RGB - Region names are not drop down menus --- apps/opencs/model/world/columns.cpp | 11 +- apps/opencs/model/world/columns.hpp | 11 +- apps/opencs/model/world/data.cpp | 25 ++- apps/opencs/model/world/data.hpp | 2 +- .../model/world/nestedcoladapterimp.cpp | 161 +++++++++++++++++- .../model/world/nestedcoladapterimp.hpp | 26 +++ 6 files changed, 230 insertions(+), 6 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index daf537c0c..ee7a00ca0 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -62,7 +62,7 @@ namespace CSMWorld { ColumnId_StarterSpell, "Starter Spell" }, { ColumnId_AlwaysSucceeds, "Always Succeeds" }, { ColumnId_SleepForbidden, "Sleep Forbidden" }, - { ColumnId_InteriorWater, "Interior Water" }, + { ColumnId_Water, "Has Water" }, { ColumnId_InteriorSky, "Interior Sky" }, { ColumnId_Model, "Model" }, { ColumnId_Script, "Script" }, @@ -303,6 +303,15 @@ namespace CSMWorld { ColumnId_RaceSkill, "Skills" }, { ColumnId_RaceBonus, "Bonus" }, + { ColumnId_Interior, "Interior" }, + { ColumnId_Ambient, "Ambient" }, + { ColumnId_Sunlight, "Sunlight" }, + { ColumnId_Fog, "Fog" }, + { ColumnId_FogDensity, "Fog Density" }, + { ColumnId_WaterLevel, "Water Level" }, + { ColumnId_InteriorWater, "Interior Water" }, + { ColumnId_MapColor, "Map Color" }, + { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue3, "Use value 3" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 85276a695..3a345b3ec 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -57,7 +57,7 @@ namespace CSMWorld ColumnId_StarterSpell = 42, ColumnId_AlwaysSucceeds = 43, ColumnId_SleepForbidden = 44, - ColumnId_InteriorWater = 45, + ColumnId_Water = 45, ColumnId_InteriorSky = 46, ColumnId_Model = 47, ColumnId_Script = 48, @@ -294,6 +294,15 @@ namespace CSMWorld ColumnId_RaceSkill = 266, ColumnId_RaceBonus = 267, + ColumnId_Interior = 268, + ColumnId_Ambient = 269, + ColumnId_Sunlight = 270, + ColumnId_Fog = 271, + ColumnId_FogDensity = 272, + ColumnId_WaterLevel = 273, + ColumnId_InteriorWater = 274, + ColumnId_MapColor = 275, + // 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, diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index fa7e48a0e..00349d476 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -287,10 +287,31 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); mCells.addColumn (new FlagColumn (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep)); - mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); + mCells.addColumn (new FlagColumn (Columns::ColumnId_Water, ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new RegionColumn); mCells.addColumn (new RefNumCounterColumn); + // Misc Cell data + mCells.addColumn (new NestedParentColumn (Columns::ColumnId_Cell, + ColumnBase::Flag_Dialogue | ColumnBase::Flag_Dialogue_List)); + index = mCells.getColumns()-1; + mCells.addAdapter (std::make_pair(&mCells.getColumn(index), new CellListAdapter ())); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Interior, ColumnBase::Display_Boolean)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Ambient, ColumnBase::Display_Integer)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Sunlight, ColumnBase::Display_Integer)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_Fog, ColumnBase::Display_Integer)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_FogDensity, ColumnBase::Display_Float)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_InteriorWater, ColumnBase::Display_Boolean)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_WaterLevel, ColumnBase::Display_Float)); + mCells.getNestableColumn(index)->addColumn( + new NestedChildColumn (Columns::ColumnId_MapColor, ColumnBase::Display_Integer)); mEnchantments.addColumn (new StringIdColumn); mEnchantments.addColumn (new RecordStateColumn); @@ -465,7 +486,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc addModel (new IdTree (&mTopicInfos, &mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); - addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); + addModel (new IdTree (&mCells, &mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); addModel (new IdTree (&mEnchantments, &mEnchantments), UniversalId::Type_Enchantment); addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart); addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen); diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index 8689b98c0..060e47bd9 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -88,7 +88,7 @@ namespace CSMWorld IdCollection mStartScripts; NestedInfoCollection mTopicInfos; InfoCollection mJournalInfos; - IdCollection mCells; + NestedIdCollection mCells; IdCollection mLandTextures; IdCollection mLand; RefIdCollection mReferenceables; diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 7efe14dee..a63ebe672 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -481,7 +481,7 @@ namespace CSMWorld void InfoListAdapter::removeRow(Record& record, int rowToRemove) const { - throw std::logic_error ("cannot add a row to a fixed table"); + throw std::logic_error ("cannot remove a row to a fixed table"); } void InfoListAdapter::setTable(Record& record, @@ -1033,4 +1033,163 @@ namespace CSMWorld // there are 7 skill bonuses return static_cast(sizeof(record.get().mData.mBonus)/sizeof(record.get().mData.mBonus[0])); } + + CellListAdapter::CellListAdapter () {} + + void CellListAdapter::addRow(Record& record, int position) const + { + throw std::logic_error ("cannot add a row to a fixed table"); + } + + void CellListAdapter::removeRow(Record& record, int rowToRemove) const + { + throw std::logic_error ("cannot remove a row to a fixed table"); + } + + void CellListAdapter::setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const + { + throw std::logic_error ("table operation not supported"); + } + + NestedTableWrapperBase* CellListAdapter::table(const Record& record) const + { + throw std::logic_error ("table operation not supported"); + } + + QVariant CellListAdapter::getData(const Record& record, + int subRowIndex, int subColIndex) const + { + CSMWorld::Cell cell = record.get(); + + bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; + bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + + switch (subColIndex) + { + case 0: return isInterior; + case 1: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mAmbient : QVariant(); + case 2: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mSunlight : QVariant(); + case 3: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFog : QVariant(); + case 4: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFogDensity : QVariant(); + case 5: return (isInterior && !behaveLikeExterior) ? cell.mWaterInt==true : QVariant(); + case 6: + { + if (isInterior && !behaveLikeExterior && cell.mWaterInt) + return cell.mWater; + else + return QVariant(); + } + case 7: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? + //case 8: return isInterior ? behaveLikeExterior : QVariant(); + default: throw std::runtime_error("Cell subcolumn index out of range"); + } + } + + void CellListAdapter::setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const + { + CSMWorld::Cell cell = record.get(); + + bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; + bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + + switch (subColIndex) + { + case 0: + { + if (value.toBool()) + cell.mData.mFlags |= ESM::Cell::Interior; + else + cell.mData.mFlags &= ~ESM::Cell::Interior; + break; + } + case 1: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mAmbient = static_cast(value.toInt()); + else + return; // return without saving + break; + } + case 2: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mSunlight = static_cast(value.toInt()); + else + return; // return without saving + break; + } + case 3: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mFog = static_cast(value.toInt()); + else + return; // return without saving + break; + } + case 4: + { + if (isInterior && !behaveLikeExterior) + cell.mAmbi.mFogDensity = value.toFloat(); + else + return; // return without saving + break; + } + case 5: + { + if (isInterior && !behaveLikeExterior) + cell.mWaterInt = value.toBool(); + else + return; // return without saving + break; + } + case 6: + { + if (isInterior && !behaveLikeExterior && cell.mWaterInt) + cell.mWater = value.toFloat(); + else + return; // return without saving + break; + } + case 7: + { + if (!isInterior) + cell.mMapColor = value.toInt(); + else + return; // return without saving + break; + } +#if 0 + // redundant since this flag is shown in the main table as "Interior Sky" + // keep here for documenting the logic based on vanilla + case 8: + { + if (isInterior) + { + if (value.toBool()) + cell.mData.mFlags |= ESM::Cell::QuasiEx; + else + cell.mData.mFlags &= ~ESM::Cell::QuasiEx; + } + else + return; // return without saving + break; + } +#endif + default: throw std::runtime_error("Cell subcolumn index out of range"); + } + + record.setModified (cell); + } + + int CellListAdapter::getColumnsCount(const Record& record) const + { + return 8; + } + + int CellListAdapter::getRowsCount(const Record& record) const + { + return 1; // fixed at size 1 + } } diff --git a/apps/opencs/model/world/nestedcoladapterimp.hpp b/apps/opencs/model/world/nestedcoladapterimp.hpp index 4b1e2cd09..81c52588b 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.hpp +++ b/apps/opencs/model/world/nestedcoladapterimp.hpp @@ -12,6 +12,7 @@ #include "nestedcolumnadapter.hpp" #include "nestedtablewrapper.hpp" +#include "cell.hpp" namespace ESM { @@ -488,6 +489,31 @@ namespace CSMWorld virtual int getRowsCount(const Record& record) const; }; + + class CellListAdapter : public NestedColumnAdapter + { + public: + CellListAdapter (); + + virtual void addRow(Record& record, int position) const; + + virtual void removeRow(Record& record, int rowToRemove) const; + + virtual void setTable(Record& record, + const NestedTableWrapperBase& nestedTable) const; + + virtual NestedTableWrapperBase* table(const Record& record) const; + + virtual QVariant getData(const Record& record, + int subRowIndex, int subColIndex) const; + + virtual void setData(Record& record, + const QVariant& value, int subRowIndex, int subColIndex) const; + + virtual int getColumnsCount(const Record& record) const; + + virtual int getRowsCount(const Record& record) const; + }; } #endif // CSM_WOLRD_NESTEDCOLADAPTERIMP_H From 1d0b8587a1682dd1116b0a254f4b0ea4416fefd9 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Wed, 20 May 2015 21:14:17 +1000 Subject: [PATCH 5/8] Use HasWater bit flag rather than mWaterInt bool. --- apps/opencs/model/world/columns.cpp | 3 +-- apps/opencs/model/world/columns.hpp | 5 ++-- apps/opencs/model/world/data.cpp | 4 +-- .../model/world/nestedcoladapterimp.cpp | 27 +++++++------------ 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index ee7a00ca0..c937997a9 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -62,7 +62,7 @@ namespace CSMWorld { ColumnId_StarterSpell, "Starter Spell" }, { ColumnId_AlwaysSucceeds, "Always Succeeds" }, { ColumnId_SleepForbidden, "Sleep Forbidden" }, - { ColumnId_Water, "Has Water" }, + { ColumnId_InteriorWater, "Interior Water" }, { ColumnId_InteriorSky, "Interior Sky" }, { ColumnId_Model, "Model" }, { ColumnId_Script, "Script" }, @@ -309,7 +309,6 @@ namespace CSMWorld { ColumnId_Fog, "Fog" }, { ColumnId_FogDensity, "Fog Density" }, { ColumnId_WaterLevel, "Water Level" }, - { ColumnId_InteriorWater, "Interior Water" }, { ColumnId_MapColor, "Map Color" }, { ColumnId_UseValue1, "Use value 1" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 3a345b3ec..191bbdea8 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -57,7 +57,7 @@ namespace CSMWorld ColumnId_StarterSpell = 42, ColumnId_AlwaysSucceeds = 43, ColumnId_SleepForbidden = 44, - ColumnId_Water = 45, + ColumnId_InteriorWater = 45, ColumnId_InteriorSky = 46, ColumnId_Model = 47, ColumnId_Script = 48, @@ -300,8 +300,7 @@ namespace CSMWorld ColumnId_Fog = 271, ColumnId_FogDensity = 272, ColumnId_WaterLevel = 273, - ColumnId_InteriorWater = 274, - ColumnId_MapColor = 275, + ColumnId_MapColor = 274, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 00349d476..920c7db71 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -287,7 +287,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mCells.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn); mCells.addColumn (new FlagColumn (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep)); - mCells.addColumn (new FlagColumn (Columns::ColumnId_Water, ESM::Cell::HasWater)); + mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new RegionColumn); mCells.addColumn (new RefNumCounterColumn); @@ -306,8 +306,6 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc new NestedChildColumn (Columns::ColumnId_Fog, ColumnBase::Display_Integer)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_FogDensity, ColumnBase::Display_Float)); - mCells.getNestableColumn(index)->addColumn( - new NestedChildColumn (Columns::ColumnId_InteriorWater, ColumnBase::Display_Boolean)); mCells.getNestableColumn(index)->addColumn( new NestedChildColumn (Columns::ColumnId_WaterLevel, ColumnBase::Display_Float)); mCells.getNestableColumn(index)->addColumn( diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index a63ebe672..8c897f71c 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -1064,6 +1064,7 @@ namespace CSMWorld bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + bool interiorWater = (cell.mData.mFlags & ESM::Cell::HasWater) != 0; switch (subColIndex) { @@ -1072,16 +1073,15 @@ namespace CSMWorld case 2: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mSunlight : QVariant(); case 3: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFog : QVariant(); case 4: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFogDensity : QVariant(); - case 5: return (isInterior && !behaveLikeExterior) ? cell.mWaterInt==true : QVariant(); - case 6: + case 5: { - if (isInterior && !behaveLikeExterior && cell.mWaterInt) + if (isInterior && !behaveLikeExterior && interiorWater) return cell.mWater; else return QVariant(); } - case 7: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? - //case 8: return isInterior ? behaveLikeExterior : QVariant(); + case 6: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? + //case 7: return isInterior ? behaveLikeExterior : QVariant(); default: throw std::runtime_error("Cell subcolumn index out of range"); } } @@ -1093,6 +1093,7 @@ namespace CSMWorld bool isInterior = (cell.mData.mFlags & ESM::Cell::Interior) != 0; bool behaveLikeExterior = (cell.mData.mFlags & ESM::Cell::QuasiEx) != 0; + bool interiorWater = (cell.mData.mFlags & ESM::Cell::HasWater) != 0; switch (subColIndex) { @@ -1138,21 +1139,13 @@ namespace CSMWorld } case 5: { - if (isInterior && !behaveLikeExterior) - cell.mWaterInt = value.toBool(); - else - return; // return without saving - break; - } - case 6: - { - if (isInterior && !behaveLikeExterior && cell.mWaterInt) + if (isInterior && !behaveLikeExterior && interiorWater) cell.mWater = value.toFloat(); else return; // return without saving break; } - case 7: + case 6: { if (!isInterior) cell.mMapColor = value.toInt(); @@ -1163,7 +1156,7 @@ namespace CSMWorld #if 0 // redundant since this flag is shown in the main table as "Interior Sky" // keep here for documenting the logic based on vanilla - case 8: + case 7: { if (isInterior) { @@ -1185,7 +1178,7 @@ namespace CSMWorld int CellListAdapter::getColumnsCount(const Record& record) const { - return 8; + return 7; } int CellListAdapter::getRowsCount(const Record& record) const From 2fc964ca7372b7f67055706c661f79202ddbe539 Mon Sep 17 00:00:00 2001 From: cc9cii Date: Thu, 21 May 2015 13:11:07 +1000 Subject: [PATCH 6/8] Grey out disabled entries rather than hiding them. --- .../model/world/nestedcoladapterimp.cpp | 20 ++++++++++------ apps/opencs/model/world/refidadapterimp.cpp | 10 ++++---- apps/opencs/model/world/refidadapterimp.hpp | 2 +- apps/opencs/view/world/dialoguesubview.cpp | 23 ++++++++++++++++++- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/apps/opencs/model/world/nestedcoladapterimp.cpp b/apps/opencs/model/world/nestedcoladapterimp.cpp index 8c897f71c..b7d09777d 100644 --- a/apps/opencs/model/world/nestedcoladapterimp.cpp +++ b/apps/opencs/model/world/nestedcoladapterimp.cpp @@ -1069,19 +1069,25 @@ namespace CSMWorld switch (subColIndex) { case 0: return isInterior; - case 1: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mAmbient : QVariant(); - case 2: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mSunlight : QVariant(); - case 3: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFog : QVariant(); - case 4: return (isInterior && !behaveLikeExterior) ? cell.mAmbi.mFogDensity : QVariant(); + case 1: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mAmbient : QVariant(QVariant::UserType); + case 2: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mSunlight : QVariant(QVariant::UserType); + case 3: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mFog : QVariant(QVariant::UserType); + case 4: return (isInterior && !behaveLikeExterior) ? + cell.mAmbi.mFogDensity : QVariant(QVariant::UserType); case 5: { if (isInterior && !behaveLikeExterior && interiorWater) return cell.mWater; else - return QVariant(); + return QVariant(QVariant::UserType); } - case 6: return isInterior ? QVariant() : cell.mMapColor; // TODO: how to select? - //case 7: return isInterior ? behaveLikeExterior : QVariant(); + case 6: return isInterior ? + QVariant(QVariant::UserType) : cell.mMapColor; // TODO: how to select? + //case 7: return isInterior ? + //behaveLikeExterior : QVariant(QVariant::UserType); default: throw std::runtime_error("Cell subcolumn index out of range"); } } diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index a5f0b2244..ee045afd0 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -502,7 +502,7 @@ QVariant CSMWorld::NpcRefIdAdapter::getData (const RefIdColumn *column, const Re if (column==mColumns.mAttributes || column==mColumns.mSkills) { if ((record.get().mFlags & ESM::NPC::Autocalc) != 0) - return QVariant(); + return QVariant(QVariant::UserType); else return true; } @@ -805,10 +805,10 @@ QVariant CSMWorld::NpcMiscRefIdAdapter::getNestedData (const RefIdColumn *column switch (subColIndex) { case 0: return static_cast(record.get().mNpdt12.mLevel); - case 1: return QVariant(); - case 2: return QVariant(); - case 3: return QVariant(); - case 4: return QVariant(); + case 1: return QVariant(QVariant::UserType); + case 2: return QVariant(QVariant::UserType); + case 3: return QVariant(QVariant::UserType); + case 4: return QVariant(QVariant::UserType); case 5: return static_cast(record.get().mNpdt12.mDisposition); case 6: return static_cast(record.get().mNpdt12.mReputation); case 7: return static_cast(record.get().mNpdt12.mRank); diff --git a/apps/opencs/model/world/refidadapterimp.hpp b/apps/opencs/model/world/refidadapterimp.hpp index 143b46c44..3411429d0 100644 --- a/apps/opencs/model/world/refidadapterimp.hpp +++ b/apps/opencs/model/world/refidadapterimp.hpp @@ -1976,7 +1976,7 @@ namespace CSMWorld { switch (subColIndex) { - case 0: return QVariant(); // don't allow checkbox editor to be created + case 0: return QVariant(QVariant::UserType); // disable the checkbox editor case 1: return record.get().mFlags & ESM::CreatureLevList::AllLevels; case 2: return static_cast (record.get().mChanceNone); default: diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index fee302e2c..0a5eb5202 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -461,7 +461,14 @@ void CSVWorld::EditWidget::remake(int row) NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this); // FIXME: does not work well when enum delegates are used //table->resizeColumnsToContents(); - table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); + + if(mTable->index(row, i).data().type() == QVariant::UserType) + { + table->setEditTriggers(QAbstractItemView::NoEditTriggers); + table->setEnabled(false); + } + else + table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); int rows = mTable->rowCount(mTable->index(row, i)); int rowHeight = (rows == 0) ? table->horizontalHeader()->height() : table->rowHeight(0); @@ -473,6 +480,8 @@ void CSVWorld::EditWidget::remake(int row) new QLabel (mTable->headerData (i, Qt::Horizontal, Qt::DisplayRole).toString(), mMainWidget); label->setSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed); + if(mTable->index(row, i).data().type() == QVariant::UserType) + label->setEnabled(false); tablesLayout->addWidget(label); tablesLayout->addWidget(table); @@ -503,6 +512,12 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; } + + if(mTable->index(row, i).data().type() == QVariant::UserType) + { + editor->setEnabled(false); + label->setEnabled(false); + } } } else @@ -550,6 +565,12 @@ void CSVWorld::EditWidget::remake(int row) unlockedLayout->addWidget (label, unlocked, 0); unlockedLayout->addWidget (editor, unlocked, 1); ++unlocked; + + if(mNestedModels.back()->index(0, col).data().type() == QVariant::UserType) + { + editor->setEnabled(false); + label->setEnabled(false); + } } } mNestedTableMapper->setCurrentModelIndex(mNestedModels.back()->index(0, 0)); From aecd9a275e34d5e539e90713ca0e4158220f526d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Fri, 22 May 2015 06:09:55 +1000 Subject: [PATCH 7/8] Remove debugging comments. --- apps/opencs/model/world/refidadapterimp.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/apps/opencs/model/world/refidadapterimp.cpp b/apps/opencs/model/world/refidadapterimp.cpp index ee045afd0..0bb565e51 100644 --- a/apps/opencs/model/world/refidadapterimp.cpp +++ b/apps/opencs/model/world/refidadapterimp.cpp @@ -721,8 +721,7 @@ QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *colu const ESM::NPC::NPDTstruct52& npcStruct = record.get().mNpdt52; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) - std::cout << "getNestedDatat index" << std::endl; - //throw std::runtime_error ("index out of range"); + throw std::runtime_error ("index out of range"); if (subColIndex == 0) return QString(ESM::Skill::sSkillNames[subRowIndex].c_str()); @@ -741,8 +740,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedData (const RefIdColumn *column, ESM::NPC::NPDTstruct52& npcStruct = npc.mNpdt52; if (subRowIndex < 0 || subRowIndex >= ESM::Skill::Length) - std::cout << "setNestedDatat index" << std::endl; - //throw std::runtime_error ("index out of range"); + throw std::runtime_error ("index out of range"); if (subColIndex == 1) npcStruct.mSkills[subRowIndex] = static_cast(value.toInt()); From 21af1913e1d1e30dc3fc91e503ff862dba0fae1d Mon Sep 17 00:00:00 2001 From: cc9cii Date: Sun, 24 May 2015 19:18:54 +1000 Subject: [PATCH 8/8] Ensure ColumnId names are unique. --- apps/opencs/model/world/columns.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index c937997a9..9491c3246 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -176,7 +176,7 @@ namespace CSMWorld { ColumnId_ContainerContent, "Content" }, { ColumnId_ItemCount, "Count" }, - { ColumnId_InventoryItemId, "ID"}, + { ColumnId_InventoryItemId, "Item ID"}, { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, @@ -188,10 +188,10 @@ namespace CSMWorld { ColumnId_ActorInventory, "Inventory" }, { ColumnId_SpellList, "Spells" }, - { ColumnId_SpellId, "ID"}, + { ColumnId_SpellId, "Spell ID"}, { ColumnId_NpcDestinations, "Destinations" }, - { ColumnId_DestinationCell, "Cell"}, + { ColumnId_DestinationCell, "Dest Cell"}, { ColumnId_PosX, "Dest X"}, { ColumnId_PosY, "Dest Y"}, { ColumnId_PosZ, "Dest Z"}, @@ -224,17 +224,17 @@ namespace CSMWorld { ColumnId_BoltSound, "Bolt Sound" }, { ColumnId_PathgridPoints, "Points" }, - { ColumnId_PathgridIndex, "Index" }, + { ColumnId_PathgridIndex, "pIndex" }, { ColumnId_PathgridPosX, "X" }, { ColumnId_PathgridPosY, "Y" }, { ColumnId_PathgridPosZ, "Z" }, { ColumnId_PathgridEdges, "Edges" }, - { ColumnId_PathgridEdgeIndex, "Index" }, + { ColumnId_PathgridEdgeIndex, "eIndex" }, { ColumnId_PathgridEdge0, "Point 0" }, { ColumnId_PathgridEdge1, "Point 1" }, { ColumnId_RegionSounds, "Sounds" }, - { ColumnId_SoundName, "Name" }, + { ColumnId_SoundName, "Sound Name" }, { ColumnId_SoundChance, "Chance" }, { ColumnId_FactionReactions, "Reactions" }, @@ -250,7 +250,7 @@ namespace CSMWorld { ColumnId_AiPackageList, "Ai Packages" }, { ColumnId_AiPackageType, "Package" }, { ColumnId_AiWanderDist, "Wander Dist" }, - { ColumnId_AiDuration, "Duration" }, + { ColumnId_AiDuration, "Ai Duration" }, { ColumnId_AiWanderToD, "Wander ToD" }, { ColumnId_AiWanderIdle, "Wander Idle" }, { ColumnId_AiWanderRepeat, "Wander Repeat" }, @@ -260,11 +260,11 @@ namespace CSMWorld { ColumnId_PartRefList, "Part Reference" }, { ColumnId_PartRefType, "Type" }, - { ColumnId_PartRefMale, "Male" }, - { ColumnId_PartRefFemale, "Female" }, + { ColumnId_PartRefMale, "Male Part" }, + { ColumnId_PartRefFemale, "Female Part" }, { ColumnId_LevelledList,"Levelled List" }, - { ColumnId_LevelledItemId,"Item ID" }, + { ColumnId_LevelledItemId,"Levelled Item" }, { ColumnId_LevelledItemLevel,"Level" }, { ColumnId_LevelledItemType, "Calculate all levels <= player" }, { ColumnId_LevelledItemTypeEach, "Select a new item each instance" }, @@ -278,7 +278,7 @@ namespace CSMWorld { ColumnId_InfoCondFunc, "Function" }, { ColumnId_InfoCondVar, "Func/Variable" }, { ColumnId_InfoCondComp, "Comp" }, - { ColumnId_InfoCondValue, "Value" }, + { ColumnId_InfoCondValue, "Values" }, { ColumnId_OriginalCell, "Original Cell" }, { ColumnId_NpcAttributes, "Attributes" },