#include "data.hpp" #include <stdexcept> #include <algorithm> #include <QAbstractItemModel> #include <components/esm/esmreader.hpp> #include <components/esm/defs.hpp> #include <components/esm/loadglob.hpp> #include <components/esm/cellref.hpp> #include "idtable.hpp" #include "columnimp.hpp" #include "regionmap.hpp" #include "columns.hpp" void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, UniversalId::Type type2, bool update) { mModels.push_back (model); mModelIndex.insert (std::make_pair (type1, model)); if (type2!=UniversalId::Type_None) mModelIndex.insert (std::make_pair (type2, model)); if (update) { connect (model, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)), this, SLOT (dataChanged (const QModelIndex&, const QModelIndex&))); connect (model, SIGNAL (rowsInserted (const QModelIndex&, int, int)), this, SLOT (rowsChanged (const QModelIndex&, int, int))); connect (model, SIGNAL (rowsRemoved (const QModelIndex&, int, int)), this, SLOT (rowsChanged (const QModelIndex&, int, int))); } } void CSMWorld::Data::appendIds (std::vector<std::string>& ids, const CollectionBase& collection, bool listDeleted) { std::vector<std::string> ids2 = collection.getIds (listDeleted); ids.insert (ids.end(), ids2.begin(), ids2.end()); } int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collection) { int number = 0; for (int i=0; i<collection.getSize(); ++i) if (collection.getRecord (i).mState==state) ++number; return number; } CSMWorld::Data::Data() : mRefs (mCells) { mGlobals.addColumn (new StringIdColumn<ESM::Global>); mGlobals.addColumn (new RecordStateColumn<ESM::Global>); mGlobals.addColumn (new FixedRecordTypeColumn<ESM::Global> (UniversalId::Type_Global)); mGlobals.addColumn (new VarTypeColumn<ESM::Global> (ColumnBase::Display_GlobalVarType)); mGlobals.addColumn (new VarValueColumn<ESM::Global>); mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>); mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>); mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst)); mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst)); mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting> (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>); mSkills.addColumn (new StringIdColumn<ESM::Skill>); mSkills.addColumn (new RecordStateColumn<ESM::Skill>); mSkills.addColumn (new FixedRecordTypeColumn<ESM::Skill> (UniversalId::Type_Skill)); mSkills.addColumn (new AttributeColumn<ESM::Skill>); mSkills.addColumn (new SpecialisationColumn<ESM::Skill>); for (int i=0; i<4; ++i) mSkills.addColumn (new UseValueColumn<ESM::Skill> (i)); mSkills.addColumn (new DescriptionColumn<ESM::Skill>); mClasses.addColumn (new StringIdColumn<ESM::Class>); mClasses.addColumn (new RecordStateColumn<ESM::Class>); mClasses.addColumn (new FixedRecordTypeColumn<ESM::Class> (UniversalId::Type_Class)); mClasses.addColumn (new NameColumn<ESM::Class>); mClasses.addColumn (new AttributesColumn<ESM::Class> (0)); mClasses.addColumn (new AttributesColumn<ESM::Class> (1)); mClasses.addColumn (new SpecialisationColumn<ESM::Class>); for (int i=0; i<5; ++i) mClasses.addColumn (new SkillsColumn<ESM::Class> (i, true, true)); for (int i=0; i<5; ++i) mClasses.addColumn (new SkillsColumn<ESM::Class> (i, true, false)); mClasses.addColumn (new PlayableColumn<ESM::Class>); mClasses.addColumn (new DescriptionColumn<ESM::Class>); mFactions.addColumn (new StringIdColumn<ESM::Faction>); mFactions.addColumn (new RecordStateColumn<ESM::Faction>); mFactions.addColumn (new FixedRecordTypeColumn<ESM::Faction> (UniversalId::Type_Faction)); mFactions.addColumn (new NameColumn<ESM::Faction>); mFactions.addColumn (new AttributesColumn<ESM::Faction> (0)); mFactions.addColumn (new AttributesColumn<ESM::Faction> (1)); mFactions.addColumn (new HiddenColumn<ESM::Faction>); for (int i=0; i<6; ++i) mFactions.addColumn (new SkillsColumn<ESM::Faction> (i)); mRaces.addColumn (new StringIdColumn<ESM::Race>); mRaces.addColumn (new RecordStateColumn<ESM::Race>); mRaces.addColumn (new FixedRecordTypeColumn<ESM::Race> (UniversalId::Type_Race)); mRaces.addColumn (new NameColumn<ESM::Race>); mRaces.addColumn (new DescriptionColumn<ESM::Race>); mRaces.addColumn (new FlagColumn<ESM::Race> (Columns::ColumnId_Playable, 0x1)); mRaces.addColumn (new FlagColumn<ESM::Race> (Columns::ColumnId_BeastRace, 0x2)); mRaces.addColumn (new WeightHeightColumn<ESM::Race> (true, true)); mRaces.addColumn (new WeightHeightColumn<ESM::Race> (true, false)); mRaces.addColumn (new WeightHeightColumn<ESM::Race> (false, true)); mRaces.addColumn (new WeightHeightColumn<ESM::Race> (false, false)); mSounds.addColumn (new StringIdColumn<ESM::Sound>); mSounds.addColumn (new RecordStateColumn<ESM::Sound>); mSounds.addColumn (new FixedRecordTypeColumn<ESM::Sound> (UniversalId::Type_Sound)); mSounds.addColumn (new SoundParamColumn<ESM::Sound> (SoundParamColumn<ESM::Sound>::Type_Volume)); mSounds.addColumn (new SoundParamColumn<ESM::Sound> (SoundParamColumn<ESM::Sound>::Type_MinRange)); mSounds.addColumn (new SoundParamColumn<ESM::Sound> (SoundParamColumn<ESM::Sound>::Type_MaxRange)); mSounds.addColumn (new SoundFileColumn<ESM::Sound>); mScripts.addColumn (new StringIdColumn<ESM::Script>); mScripts.addColumn (new RecordStateColumn<ESM::Script>); mScripts.addColumn (new FixedRecordTypeColumn<ESM::Script> (UniversalId::Type_Script)); mScripts.addColumn (new ScriptColumn<ESM::Script>); mRegions.addColumn (new StringIdColumn<ESM::Region>); mRegions.addColumn (new RecordStateColumn<ESM::Region>); mRegions.addColumn (new FixedRecordTypeColumn<ESM::Region> (UniversalId::Type_Region)); mRegions.addColumn (new NameColumn<ESM::Region>); mRegions.addColumn (new MapColourColumn<ESM::Region>); mRegions.addColumn (new SleepListColumn<ESM::Region>); mBirthsigns.addColumn (new StringIdColumn<ESM::BirthSign>); mBirthsigns.addColumn (new RecordStateColumn<ESM::BirthSign>); mBirthsigns.addColumn (new FixedRecordTypeColumn<ESM::BirthSign> (UniversalId::Type_Birthsign)); mBirthsigns.addColumn (new NameColumn<ESM::BirthSign>); mBirthsigns.addColumn (new TextureColumn<ESM::BirthSign>); mBirthsigns.addColumn (new DescriptionColumn<ESM::BirthSign>); mSpells.addColumn (new StringIdColumn<ESM::Spell>); mSpells.addColumn (new RecordStateColumn<ESM::Spell>); mSpells.addColumn (new FixedRecordTypeColumn<ESM::Spell> (UniversalId::Type_Spell)); mSpells.addColumn (new NameColumn<ESM::Spell>); mSpells.addColumn (new SpellTypeColumn<ESM::Spell>); mSpells.addColumn (new CostColumn<ESM::Spell>); mSpells.addColumn (new FlagColumn<ESM::Spell> (Columns::ColumnId_AutoCalc, 0x1)); mSpells.addColumn (new FlagColumn<ESM::Spell> (Columns::ColumnId_StarterSpell, 0x2)); mSpells.addColumn (new FlagColumn<ESM::Spell> (Columns::ColumnId_AlwaysSucceeds, 0x4)); mTopics.addColumn (new StringIdColumn<ESM::Dialogue>); mTopics.addColumn (new RecordStateColumn<ESM::Dialogue>); mTopics.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Topic)); mTopics.addColumn (new DialogueTypeColumn<ESM::Dialogue>); mJournals.addColumn (new StringIdColumn<ESM::Dialogue>); mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>); mJournals.addColumn (new FixedRecordTypeColumn<ESM::Dialogue> (UniversalId::Type_Journal)); mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true)); mTopicInfos.addColumn (new StringIdColumn<Info> (true)); mTopicInfos.addColumn (new RecordStateColumn<Info>); mTopicInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_TopicInfo)); mTopicInfos.addColumn (new TopicColumn<Info> (false)); mTopicInfos.addColumn (new ActorColumn<Info>); mTopicInfos.addColumn (new RaceColumn<Info>); mTopicInfos.addColumn (new ClassColumn<Info>); mTopicInfos.addColumn (new FactionColumn<Info>); mTopicInfos.addColumn (new CellColumn<Info>); mTopicInfos.addColumn (new DispositionColumn<Info>); mTopicInfos.addColumn (new RankColumn<Info>); mTopicInfos.addColumn (new GenderColumn<Info>); mTopicInfos.addColumn (new PcFactionColumn<Info>); mTopicInfos.addColumn (new PcRankColumn<Info>); mTopicInfos.addColumn (new SoundFileColumn<Info>); mTopicInfos.addColumn (new ResponseColumn<Info>); mJournalInfos.addColumn (new StringIdColumn<Info> (true)); mJournalInfos.addColumn (new RecordStateColumn<Info>); mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_Journal)); mJournalInfos.addColumn (new TopicColumn<Info> (true)); mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>); mJournalInfos.addColumn (new QuestIndexColumn<Info>); mJournalInfos.addColumn (new QuestDescriptionColumn<Info>); mCells.addColumn (new StringIdColumn<Cell>); mCells.addColumn (new RecordStateColumn<Cell>); mCells.addColumn (new FixedRecordTypeColumn<Cell> (UniversalId::Type_Cell)); mCells.addColumn (new NameColumn<Cell>); mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_SleepForbidden, ESM::Cell::NoSleep)); mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new RegionColumn<Cell>); mRefs.addColumn (new StringIdColumn<CellRef> (true)); mRefs.addColumn (new RecordStateColumn<CellRef>); mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference)); mRefs.addColumn (new CellColumn<CellRef>); mRefs.addColumn (new IdColumn<CellRef>); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false)); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 1, false)); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 2, false)); mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mPos, 0, false)); mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mPos, 1, false)); mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mPos, 2, false)); mRefs.addColumn (new ScaleColumn<CellRef>); mRefs.addColumn (new OwnerColumn<CellRef>); mRefs.addColumn (new SoulColumn<CellRef>); mRefs.addColumn (new FactionColumn<CellRef>); mRefs.addColumn (new FactionIndexColumn<CellRef>); mRefs.addColumn (new ChargesColumn<CellRef>); mRefs.addColumn (new EnchantmentChargesColumn<CellRef>); mRefs.addColumn (new GoldValueColumn<CellRef>); mRefs.addColumn (new TeleportColumn<CellRef>); mRefs.addColumn (new TeleportCellColumn<CellRef>); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mDoorDest, 0, true)); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mDoorDest, 1, true)); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mDoorDest, 2, true)); mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mDoorDest, 0, true)); mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mDoorDest, 1, true)); mRefs.addColumn (new RotColumn<CellRef> (&CellRef::mDoorDest, 2, true)); mRefs.addColumn (new LockLevelColumn<CellRef>); mRefs.addColumn (new KeyColumn<CellRef>); mRefs.addColumn (new TrapColumn<CellRef>); mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>); mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>); mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter)); mFilters.addColumn (new FilterColumn<CSMFilter::Filter>); mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>); mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>); addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill, false); addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic); addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal); addModel (new IdTable (&mTopicInfos), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo); addModel (new IdTable (&mJournalInfos), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo); addModel (new IdTable (&mCells), UniversalId::Type_Cells, UniversalId::Type_Cell); addModel (new IdTable (&mReferenceables), UniversalId::Type_Referenceables, UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs), UniversalId::Type_References, UniversalId::Type_Reference, false); addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false); } CSMWorld::Data::~Data() { for (std::vector<QAbstractItemModel *>::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) delete *iter; } const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const { return mGlobals; } CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() { return mGlobals; } const CSMWorld::IdCollection<ESM::GameSetting>& CSMWorld::Data::getGmsts() const { return mGmsts; } CSMWorld::IdCollection<ESM::GameSetting>& CSMWorld::Data::getGmsts() { return mGmsts; } const CSMWorld::IdCollection<ESM::Skill>& CSMWorld::Data::getSkills() const { return mSkills; } CSMWorld::IdCollection<ESM::Skill>& CSMWorld::Data::getSkills() { return mSkills; } const CSMWorld::IdCollection<ESM::Class>& CSMWorld::Data::getClasses() const { return mClasses; } CSMWorld::IdCollection<ESM::Class>& CSMWorld::Data::getClasses() { return mClasses; } const CSMWorld::IdCollection<ESM::Faction>& CSMWorld::Data::getFactions() const { return mFactions; } CSMWorld::IdCollection<ESM::Faction>& CSMWorld::Data::getFactions() { return mFactions; } const CSMWorld::IdCollection<ESM::Race>& CSMWorld::Data::getRaces() const { return mRaces; } CSMWorld::IdCollection<ESM::Race>& CSMWorld::Data::getRaces() { return mRaces; } const CSMWorld::IdCollection<ESM::Sound>& CSMWorld::Data::getSounds() const { return mSounds; } CSMWorld::IdCollection<ESM::Sound>& CSMWorld::Data::getSounds() { return mSounds; } const CSMWorld::IdCollection<ESM::Script>& CSMWorld::Data::getScripts() const { return mScripts; } CSMWorld::IdCollection<ESM::Script>& CSMWorld::Data::getScripts() { return mScripts; } const CSMWorld::IdCollection<ESM::Region>& CSMWorld::Data::getRegions() const { return mRegions; } CSMWorld::IdCollection<ESM::Region>& CSMWorld::Data::getRegions() { return mRegions; } const CSMWorld::IdCollection<ESM::BirthSign>& CSMWorld::Data::getBirthsigns() const { return mBirthsigns; } CSMWorld::IdCollection<ESM::BirthSign>& CSMWorld::Data::getBirthsigns() { return mBirthsigns; } const CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells() const { return mSpells; } CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells() { return mSpells; } const CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getTopics() const { return mTopics; } CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getTopics() { return mTopics; } const CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getJournals() const { return mJournals; } CSMWorld::IdCollection<ESM::Dialogue>& CSMWorld::Data::getJournals() { return mJournals; } const CSMWorld::InfoCollection& CSMWorld::Data::getTopicInfos() const { return mTopicInfos; } CSMWorld::InfoCollection& CSMWorld::Data::getTopicInfos() { return mTopicInfos; } const CSMWorld::InfoCollection& CSMWorld::Data::getJournalInfos() const { return mJournalInfos; } CSMWorld::InfoCollection& CSMWorld::Data::getJournalInfos() { return mJournalInfos; } const CSMWorld::IdCollection<CSMWorld::Cell>& CSMWorld::Data::getCells() const { return mCells; } CSMWorld::IdCollection<CSMWorld::Cell>& CSMWorld::Data::getCells() { return mCells; } const CSMWorld::RefIdCollection& CSMWorld::Data::getReferenceables() const { return mReferenceables; } CSMWorld::RefIdCollection& CSMWorld::Data::getReferenceables() { return mReferenceables; } const CSMWorld::RefCollection& CSMWorld::Data::getReferences() const { return mRefs; } CSMWorld::RefCollection& CSMWorld::Data::getReferences() { return mRefs; } const CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() const { return mFilters; } CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() { return mFilters; } QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) { std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType()); if (iter==mModelIndex.end()) { // try creating missing (secondary) tables on the fly // // Note: We create these tables here so we don't have to deal with them during load/initial // construction of the ESX data where no update signals are available. if (id.getType()==UniversalId::Type_RegionMap) { RegionMap *table = 0; addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, UniversalId::Type_None, false); return table; } throw std::logic_error ("No table model available for " + id.toString()); } return iter->second; } void CSMWorld::Data::merge() { mGlobals.merge(); } void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, bool project) { ESM::ESMReader reader; /// \todo set encoding properly, once config implementation has been fixed. ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252")); reader.setEncoder (&encoder); reader.open (path.string()); const ESM::Dialogue *dialogue = 0; mAuthor = reader.getAuthor(); mDescription = reader.getDesc(); // Note: We do not need to send update signals here, because at this point the model is not connected // to any view. while (reader.hasMoreRecs()) { ESM::NAME n = reader.getRecName(); reader.getRecHeader(); switch (n.val) { case ESM::REC_GLOB: mGlobals.load (reader, base); break; case ESM::REC_GMST: mGmsts.load (reader, base); break; case ESM::REC_SKIL: mSkills.load (reader, base); break; case ESM::REC_CLAS: mClasses.load (reader, base); break; case ESM::REC_FACT: mFactions.load (reader, base); break; case ESM::REC_RACE: mRaces.load (reader, base); break; case ESM::REC_SOUN: mSounds.load (reader, base); break; case ESM::REC_SCPT: mScripts.load (reader, base); break; case ESM::REC_REGN: mRegions.load (reader, base); break; case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; case ESM::REC_SPEL: mSpells.load (reader, base); break; case ESM::REC_CELL: mCells.load (reader, base); mRefs.load (reader, mCells.getSize()-1, base); break; case ESM::REC_ACTI: mReferenceables.load (reader, base, UniversalId::Type_Activator); break; case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break; case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break; case ESM::REC_ARMO: mReferenceables.load (reader, base, UniversalId::Type_Armor); break; case ESM::REC_BOOK: mReferenceables.load (reader, base, UniversalId::Type_Book); break; case ESM::REC_CLOT: mReferenceables.load (reader, base, UniversalId::Type_Clothing); break; case ESM::REC_CONT: mReferenceables.load (reader, base, UniversalId::Type_Container); break; case ESM::REC_CREA: mReferenceables.load (reader, base, UniversalId::Type_Creature); break; case ESM::REC_DOOR: mReferenceables.load (reader, base, UniversalId::Type_Door); break; case ESM::REC_INGR: mReferenceables.load (reader, base, UniversalId::Type_Ingredient); break; case ESM::REC_LEVC: mReferenceables.load (reader, base, UniversalId::Type_CreatureLevelledList); break; case ESM::REC_LEVI: mReferenceables.load (reader, base, UniversalId::Type_ItemLevelledList); break; case ESM::REC_LIGH: mReferenceables.load (reader, base, UniversalId::Type_Light); break; case ESM::REC_LOCK: mReferenceables.load (reader, base, UniversalId::Type_Lockpick); break; case ESM::REC_MISC: mReferenceables.load (reader, base, UniversalId::Type_Miscellaneous); break; case ESM::REC_NPC_: mReferenceables.load (reader, base, UniversalId::Type_Npc); break; case ESM::REC_PROB: mReferenceables.load (reader, base, UniversalId::Type_Probe); break; case ESM::REC_REPA: mReferenceables.load (reader, base, UniversalId::Type_Repair); break; case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break; case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break; case ESM::REC_DIAL: { std::string id = reader.getHNOString ("NAME"); ESM::Dialogue record; record.mId = id; record.load (reader); if (record.mType==ESM::Dialogue::Journal) { mJournals.load (record, base); dialogue = &mJournals.getRecord (id).get(); } else if (record.mType==ESM::Dialogue::Deleted) { dialogue = 0; // record vector can be shuffled around which would make pointer // to record invalid if (mJournals.tryDelete (id)) { /// \todo handle info records } else if (mTopics.tryDelete (id)) { /// \todo handle info records } else { /// \todo report deletion of non-existing record } } else { mTopics.load (record, base); dialogue = &mTopics.getRecord (id).get(); } break; } case ESM::REC_INFO: { if (!dialogue) { /// \todo INFO record without matching DIAL record -> report to user reader.skipRecord(); break; } if (dialogue->mType==ESM::Dialogue::Journal) mJournalInfos.load (reader, base, *dialogue); else mTopicInfos.load (reader, base, *dialogue); break; } case ESM::REC_FILT: if (project) { mFilters.load (reader, base); mFilters.setData (mFilters.getSize()-1, mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope), static_cast<int> (CSMFilter::Filter::Scope_Project)); break; } // fall through (filter record in a content file is an error with format 0) default: /// \todo throw an exception instead, once all records are implemented /// or maybe report error and continue? reader.skipRecord(); } } } bool CSMWorld::Data::hasId (const std::string& id) const { return getGlobals().searchId (id)!=-1 || getGmsts().searchId (id)!=-1 || getSkills().searchId (id)!=-1 || getClasses().searchId (id)!=-1 || getFactions().searchId (id)!=-1 || getRaces().searchId (id)!=-1 || getSounds().searchId (id)!=-1 || getScripts().searchId (id)!=-1 || getRegions().searchId (id)!=-1 || getBirthsigns().searchId (id)!=-1 || getSpells().searchId (id)!=-1 || getTopics().searchId (id)!=-1 || getJournals().searchId (id)!=-1 || getCells().searchId (id)!=-1 || getReferenceables().searchId (id)!=-1; } int CSMWorld::Data::count (RecordBase::State state) const { return count (state, mGlobals) + count (state, mGmsts) + count (state, mSkills) + count (state, mClasses) + count (state, mFactions) + count (state, mRaces) + count (state, mSounds) + count (state, mScripts) + count (state, mRegions) + count (state, mBirthsigns) + count (state, mSpells) + count (state, mCells) + count (state, mReferenceables); } void CSMWorld::Data::setDescription (const std::string& description) { mDescription = description; } std::string CSMWorld::Data::getDescription() const { return mDescription; } void CSMWorld::Data::setAuthor (const std::string& author) { mAuthor = author; } std::string CSMWorld::Data::getAuthor() const { return mAuthor; } std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const { std::vector<std::string> ids; appendIds (ids, mGlobals, listDeleted); appendIds (ids, mGmsts, listDeleted); appendIds (ids, mClasses, listDeleted); appendIds (ids, mFactions, listDeleted); appendIds (ids, mRaces, listDeleted); appendIds (ids, mSounds, listDeleted); appendIds (ids, mScripts, listDeleted); appendIds (ids, mRegions, listDeleted); appendIds (ids, mBirthsigns, listDeleted); appendIds (ids, mSpells, listDeleted); appendIds (ids, mTopics, listDeleted); appendIds (ids, mJournals, listDeleted); appendIds (ids, mCells, listDeleted); appendIds (ids, mReferenceables, listDeleted); std::sort (ids.begin(), ids.end()); return ids; } void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) { if (topLeft.column()<=0) emit idListChanged(); } void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) { emit idListChanged(); }