forked from mirror/openmw-tes3mp
Merge branch 'master' of https://github.com/zinnschlag/openmw into magic
Conflicts: apps/openmw/mwgui/inventoryitemmodel.cpp
This commit is contained in:
commit
956d8adb99
50 changed files with 1461 additions and 97 deletions
|
@ -339,6 +339,8 @@ int load(Arguments& info)
|
|||
}
|
||||
|
||||
std::string id = esm.getHNOString("NAME");
|
||||
if (id.empty())
|
||||
id = esm.getHNOString("INAM");
|
||||
|
||||
if(!quiet && interested)
|
||||
std::cout << "\nRecord: " << n.toString()
|
||||
|
|
|
@ -740,8 +740,8 @@ void Record<ESM::DialInfo>::print()
|
|||
if (mData.mClass != "")
|
||||
std::cout << " Class: " << mData.mClass << std::endl;
|
||||
std::cout << " Factionless: " << mData.mFactionLess << std::endl;
|
||||
if (mData.mNpcFaction != "")
|
||||
std::cout << " NPC Faction: " << mData.mNpcFaction << std::endl;
|
||||
if (mData.mFaction != "")
|
||||
std::cout << " NPC Faction: " << mData.mFaction << std::endl;
|
||||
if (mData.mData.mRank != -1)
|
||||
std::cout << " NPC Rank: " << (int)mData.mData.mRank << std::endl;
|
||||
if (mData.mPcFaction != "")
|
||||
|
|
|
@ -24,11 +24,11 @@ opencs_units (model/world
|
|||
|
||||
opencs_units_noqt (model/world
|
||||
universalid record commands columnbase scriptcontext cell refidcollection
|
||||
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns
|
||||
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection
|
||||
)
|
||||
|
||||
opencs_hdrs_noqt (model/world
|
||||
columnimp idcollection collection
|
||||
columnimp idcollection collection info
|
||||
)
|
||||
|
||||
|
||||
|
@ -60,7 +60,7 @@ opencs_hdrs_noqt (view/doc
|
|||
opencs_units (view/world
|
||||
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
|
||||
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
|
||||
scenetoolmode
|
||||
scenetoolmode infocreator
|
||||
)
|
||||
|
||||
opencs_units (view/render
|
||||
|
|
|
@ -58,12 +58,9 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
|
|||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Spell> >
|
||||
(mDocument.getData().getSpells(), mState));
|
||||
|
||||
/// \todo deal with info records for topcis and journals
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Dialogue> >
|
||||
(mDocument.getData().getTopics(), mState));
|
||||
appendStage (new WriteDialogueCollectionStage (mDocument, mState, false));
|
||||
|
||||
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Dialogue> >
|
||||
(mDocument.getData().getJournals(), mState));
|
||||
appendStage (new WriteDialogueCollectionStage (mDocument, mState, true));
|
||||
|
||||
appendStage (new WriteRefIdCollectionStage (mDocument, mState));
|
||||
|
||||
|
|
|
@ -7,6 +7,10 @@
|
|||
|
||||
#include <QUndoStack>
|
||||
|
||||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include "../world/infocollection.hpp"
|
||||
|
||||
#include "document.hpp"
|
||||
#include "savingstate.hpp"
|
||||
|
||||
|
@ -80,6 +84,115 @@ void CSMDoc::WriteHeaderStage::perform (int stage, std::vector<std::string>& mes
|
|||
}
|
||||
|
||||
|
||||
CSMDoc::WriteDialogueCollectionStage::WriteDialogueCollectionStage (Document& document,
|
||||
SavingState& state, bool journal)
|
||||
: mDocument (document), mState (state),
|
||||
mTopics (journal ? document.getData().getJournals() : document.getData().getTopics()),
|
||||
mInfos (journal ? document.getData().getJournalInfos() : document.getData().getTopicInfos())
|
||||
{}
|
||||
|
||||
int CSMDoc::WriteDialogueCollectionStage::setup()
|
||||
{
|
||||
return mTopics.getSize();
|
||||
}
|
||||
|
||||
void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::string>& messages)
|
||||
{
|
||||
const CSMWorld::Record<ESM::Dialogue>& topic = mTopics.getRecord (stage);
|
||||
|
||||
CSMWorld::RecordBase::State state = topic.mState;
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
// if the topic is deleted, we do not need to bother with INFO records.
|
||||
|
||||
/// \todo wrote record with delete flag
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Test, if we need to save anything associated info records.
|
||||
bool infoModified = false;
|
||||
|
||||
CSMWorld::InfoCollection::Range range = mInfos.getTopicRange (topic.get().mId);
|
||||
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second; ++iter)
|
||||
{
|
||||
CSMWorld::RecordBase::State state = iter->mState;
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||
state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
infoModified = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly ||
|
||||
infoModified)
|
||||
{
|
||||
// always write the topic record
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&topic.mModified.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().writeHNCString ("NAME", topic.mModified.mId);
|
||||
topic.mModified.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
|
||||
// write modified selected info records
|
||||
for (CSMWorld::InfoCollection::RecordConstIterator iter (range.first); iter!=range.second;
|
||||
++iter)
|
||||
{
|
||||
CSMWorld::RecordBase::State state = iter->mState;
|
||||
|
||||
if (state==CSMWorld::RecordBase::State_Deleted)
|
||||
{
|
||||
/// \todo wrote record with delete flag
|
||||
}
|
||||
else if (state==CSMWorld::RecordBase::State_Modified ||
|
||||
state==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
ESM::DialInfo info = iter->get();
|
||||
info.mId = info.mId.substr (info.mId.find_last_of ('#')+1);
|
||||
|
||||
if (iter!=range.first)
|
||||
{
|
||||
CSMWorld::InfoCollection::RecordConstIterator prev = iter;
|
||||
--prev;
|
||||
|
||||
info.mPrev =
|
||||
prev->mModified.mId.substr (prev->mModified.mId.find_last_of ('#')+1);
|
||||
}
|
||||
|
||||
CSMWorld::InfoCollection::RecordConstIterator next = iter;
|
||||
++next;
|
||||
|
||||
if (next!=range.second)
|
||||
{
|
||||
info.mNext =
|
||||
next->mModified.mId.substr (next->mModified.mId.find_last_of ('#')+1);
|
||||
}
|
||||
|
||||
std::string type;
|
||||
for (int i=0; i<4; ++i)
|
||||
/// \todo make endianess agnostic (change ESMWriter interface?)
|
||||
type += reinterpret_cast<const char *> (&info.sRecordId)[i];
|
||||
|
||||
mState.getWriter().startRecord (type);
|
||||
mState.getWriter().writeHNCString ("INAM", info.mId);
|
||||
info.save (mState.getWriter());
|
||||
mState.getWriter().endRecord (type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CSMDoc::WriteRefIdCollectionStage::WriteRefIdCollectionStage (Document& document, SavingState& state)
|
||||
: mDocument (document), mState (state)
|
||||
{}
|
||||
|
|
|
@ -3,13 +3,23 @@
|
|||
|
||||
#include "stage.hpp"
|
||||
|
||||
#include "savingstate.hpp"
|
||||
|
||||
#include "../world/record.hpp"
|
||||
#include "../world/idcollection.hpp"
|
||||
|
||||
#include "../filter/filter.hpp"
|
||||
|
||||
#include "savingstate.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
struct Dialogue;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class InfoCollection;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
|
@ -106,6 +116,25 @@ namespace CSMDoc
|
|||
}
|
||||
|
||||
|
||||
class WriteDialogueCollectionStage : public Stage
|
||||
{
|
||||
Document& mDocument;
|
||||
SavingState& mState;
|
||||
const CSMWorld::IdCollection<ESM::Dialogue>& mTopics;
|
||||
CSMWorld::InfoCollection& mInfos;
|
||||
|
||||
public:
|
||||
|
||||
WriteDialogueCollectionStage (Document& document, SavingState& state, bool journal);
|
||||
|
||||
virtual int setup();
|
||||
///< \return number of steps
|
||||
|
||||
virtual void perform (int stage, std::vector<std::string>& messages);
|
||||
///< Messages resulting from this stage will be appended to \a messages.
|
||||
};
|
||||
|
||||
|
||||
class WriteRefIdCollectionStage : public Stage
|
||||
{
|
||||
Document& mDocument;
|
||||
|
|
|
@ -51,6 +51,18 @@ namespace CSMWorld
|
|||
Collection (const Collection&);
|
||||
Collection& operator= (const Collection&);
|
||||
|
||||
protected:
|
||||
|
||||
const std::map<std::string, int>& getIdMap() const;
|
||||
|
||||
const std::vector<Record<ESXRecordT> >& getRecords() const;
|
||||
|
||||
bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
|
||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
///
|
||||
/// \return Success?
|
||||
|
||||
public:
|
||||
|
||||
Collection();
|
||||
|
@ -104,7 +116,8 @@ namespace CSMWorld
|
|||
|
||||
virtual const Record<ESXRecordT>& getRecord (int index) const;
|
||||
|
||||
virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const;
|
||||
virtual int getAppendIndex (const std::string& id,
|
||||
UniversalId::Type type = UniversalId::Type_None) const;
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual std::vector<std::string> getIds (bool listDeleted = true) const;
|
||||
|
@ -112,12 +125,74 @@ namespace CSMWorld
|
|||
///
|
||||
/// \param listDeleted include deleted record in the list
|
||||
|
||||
virtual void insertRecord (const RecordBase& record, int index,
|
||||
UniversalId::Type type = UniversalId::Type_None);
|
||||
///< Insert record before index.
|
||||
///
|
||||
/// If the record type does not match, an exception is thrown.
|
||||
///
|
||||
/// If the index is invalid either generally (by being out of range) or for the particular
|
||||
/// record, an exception is thrown.
|
||||
|
||||
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
|
||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
///
|
||||
/// \return Success?
|
||||
|
||||
void addColumn (Column<ESXRecordT> *column);
|
||||
|
||||
void setRecord (int index, const Record<ESXRecordT>& record);
|
||||
///< \attention This function must not change the ID.
|
||||
};
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
const std::map<std::string, int>& Collection<ESXRecordT, IdAccessorT>::getIdMap() const
|
||||
{
|
||||
return mIndex;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
const std::vector<Record<ESXRecordT> >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
|
||||
{
|
||||
return mRecords;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
bool Collection<ESXRecordT, IdAccessorT>::reorderRowsImp (int baseIndex,
|
||||
const std::vector<int>& newOrder)
|
||||
{
|
||||
if (!newOrder.empty())
|
||||
{
|
||||
int size = static_cast<int> (newOrder.size());
|
||||
|
||||
// check that all indices are present
|
||||
std::vector<int> test (newOrder);
|
||||
std::sort (test.begin(), test.end());
|
||||
if (*test.begin()!=0 || *--test.end()!=size-1)
|
||||
return false;
|
||||
|
||||
// reorder records
|
||||
std::vector<Record<ESXRecordT> > buffer (size);
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
{
|
||||
buffer[newOrder[i]] = mRecords [baseIndex+i];
|
||||
buffer[newOrder[i]].setModified (buffer[newOrder[i]].get());
|
||||
}
|
||||
|
||||
std::copy (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
|
||||
|
||||
// adjust index
|
||||
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
|
||||
++iter)
|
||||
if (iter->second>=baseIndex && iter->second<baseIndex+size)
|
||||
iter->second = newOrder.at (iter->second-baseIndex)+baseIndex;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
Collection<ESXRecordT, IdAccessorT>::Collection()
|
||||
{}
|
||||
|
@ -142,8 +217,7 @@ namespace CSMWorld
|
|||
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
|
||||
record2.mModified = record;
|
||||
|
||||
mRecords.push_back (record2);
|
||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mRecords.size()-1));
|
||||
insertRecord (record2, getAppendIndex (id));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -260,7 +334,12 @@ namespace CSMWorld
|
|||
ESXRecordT record;
|
||||
IdAccessorT().getId (record) = id;
|
||||
record.blank();
|
||||
add (record);
|
||||
|
||||
Record<ESXRecordT> record2;
|
||||
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
|
||||
record2.mModified = record;
|
||||
|
||||
insertRecord (record2, getAppendIndex (id, type), type);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
|
@ -286,14 +365,14 @@ namespace CSMWorld
|
|||
void Collection<ESXRecordT, IdAccessorT>::appendRecord (const RecordBase& record,
|
||||
UniversalId::Type type)
|
||||
{
|
||||
mRecords.push_back (dynamic_cast<const Record<ESXRecordT>&> (record));
|
||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
|
||||
dynamic_cast<const Record<ESXRecordT>&> (record).get())),
|
||||
mRecords.size()-1));
|
||||
insertRecord (record,
|
||||
getAppendIndex (IdAccessorT().getId (
|
||||
dynamic_cast<const Record<ESXRecordT>&> (record).get()), type), type);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
int Collection<ESXRecordT, IdAccessorT>::getAppendIndex (UniversalId::Type type) const
|
||||
int Collection<ESXRecordT, IdAccessorT>::getAppendIndex (const std::string& id,
|
||||
UniversalId::Type type) const
|
||||
{
|
||||
return static_cast<int> (mRecords.size());
|
||||
}
|
||||
|
@ -326,6 +405,29 @@ namespace CSMWorld
|
|||
return mRecords.at (index);
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void Collection<ESXRecordT, IdAccessorT>::insertRecord (const RecordBase& record, int index,
|
||||
UniversalId::Type type)
|
||||
{
|
||||
if (index<0 || index>static_cast<int> (mRecords.size()))
|
||||
throw std::runtime_error ("index out of range");
|
||||
|
||||
const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
|
||||
|
||||
mRecords.insert (mRecords.begin()+index, record2);
|
||||
|
||||
if (index<static_cast<int> (mRecords.size())-1)
|
||||
{
|
||||
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
|
||||
++iter)
|
||||
if (iter->second>=index)
|
||||
++(iter->second);
|
||||
}
|
||||
|
||||
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
|
||||
record2.get())), index));
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
void Collection<ESXRecordT, IdAccessorT>::setRecord (int index, const Record<ESXRecordT>& record)
|
||||
{
|
||||
|
@ -334,6 +436,12 @@ namespace CSMWorld
|
|||
|
||||
mRecords.at (index) = record;
|
||||
}
|
||||
|
||||
template<typename ESXRecordT, typename IdAccessorT>
|
||||
bool Collection<ESXRecordT, IdAccessorT>::reorderRows (int baseIndex, const std::vector<int>& newOrder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CSM_WOLRD_COLLECTIONBASE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "universalid.hpp"
|
||||
#include "columns.hpp"
|
||||
|
@ -77,7 +78,8 @@ namespace CSMWorld
|
|||
|
||||
virtual const RecordBase& getRecord (int index) const = 0;
|
||||
|
||||
virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const = 0;
|
||||
virtual int getAppendIndex (const std::string& id,
|
||||
UniversalId::Type type = UniversalId::Type_None) const = 0;
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual std::vector<std::string> getIds (bool listDeleted = true) const = 0;
|
||||
|
@ -85,6 +87,12 @@ namespace CSMWorld
|
|||
///
|
||||
/// \param listDeleted include deleted record in the list
|
||||
|
||||
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder) = 0;
|
||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
///
|
||||
/// \return Success?
|
||||
|
||||
int searchColumnIndex (Columns::ColumnId id) const;
|
||||
///< Return index of column with the given \a id. If no such column exists, -1 is returned.
|
||||
|
||||
|
|
|
@ -44,7 +44,9 @@ namespace CSMWorld
|
|||
Display_WeaponType,
|
||||
Display_RecordState,
|
||||
Display_RefRecordType,
|
||||
Display_DialogueType
|
||||
Display_DialogueType,
|
||||
Display_QuestStatusType,
|
||||
Display_Gender
|
||||
};
|
||||
|
||||
int mColumnId;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "columnbase.hpp"
|
||||
#include "columns.hpp"
|
||||
#include "info.hpp"
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
|
@ -814,14 +815,14 @@ namespace CSMWorld
|
|||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mCellId.c_str());
|
||||
return QString::fromUtf8 (record.get().mCell.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mCellId = data.toString().toUtf8().constData();
|
||||
record2.mCell = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
@ -1348,6 +1349,340 @@ namespace CSMWorld
|
|||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct QuestStatusTypeColumn : public Column<ESXRecordT>
|
||||
{
|
||||
QuestStatusTypeColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_QuestStatusType, ColumnBase::Display_QuestStatusType)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return static_cast<int> (record.get().mQuestStatus);
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mQuestStatus = static_cast<Info::QuestStatus> (data.toInt());
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct QuestDescriptionColumn : public Column<ESXRecordT>
|
||||
{
|
||||
QuestDescriptionColumn() : Column<ESXRecordT> (Columns::ColumnId_QuestDescription, ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mResponse.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mResponse = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct QuestIndexColumn : public Column<ESXRecordT>
|
||||
{
|
||||
QuestIndexColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_QuestIndex, ColumnBase::Display_Integer)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return record.get().mData.mDisposition;
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mData.mDisposition = data.toInt();
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct TopicColumn : public Column<ESXRecordT>
|
||||
{
|
||||
TopicColumn (bool journal) : Column<ESXRecordT> (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mTopicId.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mTopicId = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool isUserEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct ActorColumn : public Column<ESXRecordT>
|
||||
{
|
||||
ActorColumn() : Column<ESXRecordT> (Columns::ColumnId_Actor, ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mActor.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mActor = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct RaceColumn : public Column<ESXRecordT>
|
||||
{
|
||||
RaceColumn() : Column<ESXRecordT> (Columns::ColumnId_Race, ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mRace.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mRace = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct ClassColumn : public Column<ESXRecordT>
|
||||
{
|
||||
ClassColumn() : Column<ESXRecordT> (Columns::ColumnId_Class, ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mClass.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mClass = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct PcFactionColumn : public Column<ESXRecordT>
|
||||
{
|
||||
PcFactionColumn() : Column<ESXRecordT> (Columns::ColumnId_PcFaction, ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mPcFaction.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mPcFaction = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct ResponseColumn : public Column<ESXRecordT>
|
||||
{
|
||||
ResponseColumn() : Column<ESXRecordT> (Columns::ColumnId_Response, ColumnBase::Display_String) {}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mResponse.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mResponse = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct DispositionColumn : public Column<ESXRecordT>
|
||||
{
|
||||
DispositionColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_Disposition, ColumnBase::Display_Integer)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return record.get().mData.mDisposition;
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mData.mDisposition = data.toInt();
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct RankColumn : public Column<ESXRecordT>
|
||||
{
|
||||
RankColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_Rank, ColumnBase::Display_Integer)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return static_cast<int> (record.get().mData.mRank);
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mData.mRank = static_cast<signed char> (data.toInt());
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct PcRankColumn : public Column<ESXRecordT>
|
||||
{
|
||||
PcRankColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_PcRank, ColumnBase::Display_Integer)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return static_cast<int> (record.get().mData.mPCrank);
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
record2.mData.mPCrank = static_cast<signed char> (data.toInt());
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct GenderColumn : public Column<ESXRecordT>
|
||||
{
|
||||
GenderColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_Gender, ColumnBase::Display_Gender)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return static_cast<int> (record.get().mData.mGender);
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mData.mGender = data.toInt();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -160,6 +160,18 @@ namespace CSMWorld
|
|||
{ ColumnId_DoorPositionYRot, "Teleport Rot Y" },
|
||||
{ ColumnId_DoorPositionZRot, "Teleport Rot Z" },
|
||||
{ ColumnId_DialogueType, "Dialogue Type" },
|
||||
{ ColumnId_QuestIndex, "Quest Index" },
|
||||
{ ColumnId_QuestStatusType, "Quest Status" },
|
||||
{ ColumnId_QuestDescription, "Quest Description" },
|
||||
{ ColumnId_Topic, "Topic" },
|
||||
{ ColumnId_Journal, "Journal" },
|
||||
{ ColumnId_Actor, "Actor" },
|
||||
{ ColumnId_PcFaction, "PC Faction" },
|
||||
{ ColumnId_Response, "Response" },
|
||||
{ ColumnId_Disposition, "Disposition" },
|
||||
{ ColumnId_Rank, "Rank" },
|
||||
{ ColumnId_Gender, "Gender" },
|
||||
{ ColumnId_PcRank, "PC Rank" },
|
||||
{ ColumnId_Scope, "Scope", },
|
||||
|
||||
{ ColumnId_UseValue1, "Use value 1" },
|
||||
|
@ -276,6 +288,16 @@ namespace
|
|||
"Topic", "Voice", "Greeting", "Persuasion", 0
|
||||
};
|
||||
|
||||
static const char *sQuestStatusTypes[] =
|
||||
{
|
||||
"None", "Name", "Finished", "Restart", 0
|
||||
};
|
||||
|
||||
static const char *sGenderEnums[] =
|
||||
{
|
||||
"Male", "Female", 0
|
||||
};
|
||||
|
||||
const char **getEnumNames (CSMWorld::Columns::ColumnId column)
|
||||
{
|
||||
switch (column)
|
||||
|
@ -291,6 +313,8 @@ namespace
|
|||
case CSMWorld::Columns::ColumnId_Modification: return sModificationEnums;
|
||||
case CSMWorld::Columns::ColumnId_ValueType: return sVarTypeEnums;
|
||||
case CSMWorld::Columns::ColumnId_DialogueType: return sDialogueTypeEnums;
|
||||
case CSMWorld::Columns::ColumnId_QuestStatusType: return sQuestStatusTypes;
|
||||
case CSMWorld::Columns::ColumnId_Gender: return sGenderEnums;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
|
|
|
@ -153,7 +153,19 @@ namespace CSMWorld
|
|||
ColumnId_DoorPositionYRot = 140,
|
||||
ColumnId_DoorPositionZRot = 141,
|
||||
ColumnId_DialogueType = 142,
|
||||
ColumnId_Scope = 143,
|
||||
ColumnId_QuestIndex = 143,
|
||||
ColumnId_QuestStatusType = 144,
|
||||
ColumnId_QuestDescription = 145,
|
||||
ColumnId_Topic = 146,
|
||||
ColumnId_Journal = 147,
|
||||
ColumnId_Actor = 148,
|
||||
ColumnId_PcFaction = 149,
|
||||
ColumnId_Response = 150,
|
||||
ColumnId_Disposition = 151,
|
||||
ColumnId_Rank = 152,
|
||||
ColumnId_Gender = 153,
|
||||
ColumnId_PcRank = 154,
|
||||
ColumnId_Scope = 155,
|
||||
|
||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||
// to extend the number of use values.
|
||||
|
|
|
@ -123,3 +123,25 @@ void CSMWorld::DeleteCommand::undo()
|
|||
{
|
||||
mModel.setRecord (mId, *mOld);
|
||||
}
|
||||
|
||||
|
||||
CSMWorld::ReorderRowsCommand::ReorderRowsCommand (IdTable& model, int baseIndex,
|
||||
const std::vector<int>& newOrder)
|
||||
: mModel (model), mBaseIndex (baseIndex), mNewOrder (newOrder)
|
||||
{}
|
||||
|
||||
void CSMWorld::ReorderRowsCommand::redo()
|
||||
{
|
||||
mModel.reorderRows (mBaseIndex, mNewOrder);
|
||||
}
|
||||
|
||||
void CSMWorld::ReorderRowsCommand::undo()
|
||||
{
|
||||
int size = static_cast<int> (mNewOrder.size());
|
||||
std::vector<int> reverse (size);
|
||||
|
||||
for (int i=0; i<size; ++i)
|
||||
reverse.at (mNewOrder[i]) = i;
|
||||
|
||||
mModel.reorderRows (mBaseIndex, reverse);
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <QVariant>
|
||||
#include <QUndoCommand>
|
||||
|
@ -99,6 +100,21 @@ namespace CSMWorld
|
|||
|
||||
virtual void undo();
|
||||
};
|
||||
|
||||
class ReorderRowsCommand : public QUndoCommand
|
||||
{
|
||||
IdTable& mModel;
|
||||
int mBaseIndex;
|
||||
std::vector<int> mNewOrder;
|
||||
|
||||
public:
|
||||
|
||||
ReorderRowsCommand (IdTable& model, int baseIndex, const std::vector<int>& newOrder);
|
||||
|
||||
virtual void redo();
|
||||
|
||||
virtual void undo();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -160,6 +160,29 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
mJournals.addColumn (new RecordStateColumn<ESM::Dialogue>);
|
||||
mJournals.addColumn (new DialogueTypeColumn<ESM::Dialogue> (true));
|
||||
|
||||
mTopicInfos.addColumn (new StringIdColumn<Info> (true));
|
||||
mTopicInfos.addColumn (new RecordStateColumn<Info>);
|
||||
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 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));
|
||||
|
@ -218,6 +241,8 @@ CSMWorld::Data::Data() : mRefs (mCells)
|
|||
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);
|
||||
|
@ -362,6 +387,25 @@ 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
|
||||
{
|
||||
|
@ -441,6 +485,8 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, b
|
|||
|
||||
reader.open (path.string());
|
||||
|
||||
const ESM::Dialogue *dialogue = 0;
|
||||
|
||||
mAuthor = reader.getAuthor();
|
||||
mDescription = reader.getDesc();
|
||||
|
||||
|
@ -505,9 +551,13 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, b
|
|||
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
|
||||
|
@ -524,11 +574,29 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, b
|
|||
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)
|
||||
|
@ -545,6 +613,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, b
|
|||
default:
|
||||
|
||||
/// \todo throw an exception instead, once all records are implemented
|
||||
/// or maybe report error and continue?
|
||||
reader.skipRecord();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "cell.hpp"
|
||||
#include "refidcollection.hpp"
|
||||
#include "refcollection.hpp"
|
||||
#include "infocollection.hpp"
|
||||
|
||||
class QAbstractItemModel;
|
||||
|
||||
|
@ -51,6 +52,8 @@ namespace CSMWorld
|
|||
IdCollection<ESM::Spell> mSpells;
|
||||
IdCollection<ESM::Dialogue> mTopics;
|
||||
IdCollection<ESM::Dialogue> mJournals;
|
||||
InfoCollection mTopicInfos;
|
||||
InfoCollection mJournalInfos;
|
||||
IdCollection<Cell> mCells;
|
||||
RefIdCollection mReferenceables;
|
||||
RefCollection mRefs;
|
||||
|
@ -131,6 +134,14 @@ namespace CSMWorld
|
|||
|
||||
IdCollection<ESM::Dialogue>& getJournals();
|
||||
|
||||
const InfoCollection& getTopicInfos() const;
|
||||
|
||||
InfoCollection& getTopicInfos();
|
||||
|
||||
const InfoCollection& getJournalInfos() const;
|
||||
|
||||
InfoCollection& getJournalInfos();
|
||||
|
||||
const IdCollection<Cell>& getCells() const;
|
||||
|
||||
IdCollection<Cell>& getCells();
|
||||
|
|
|
@ -4,15 +4,12 @@
|
|||
#include "collectionbase.hpp"
|
||||
#include "columnbase.hpp"
|
||||
|
||||
CSMWorld::IdTable::IdTable (CollectionBase *idCollection) : mIdCollection (idCollection)
|
||||
{
|
||||
|
||||
}
|
||||
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering)
|
||||
: mIdCollection (idCollection), mReordering (reordering)
|
||||
{}
|
||||
|
||||
CSMWorld::IdTable::~IdTable()
|
||||
{
|
||||
|
||||
}
|
||||
{}
|
||||
|
||||
int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const
|
||||
{
|
||||
|
@ -118,7 +115,7 @@ QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const
|
|||
|
||||
void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type)
|
||||
{
|
||||
int index = mIdCollection->getAppendIndex();
|
||||
int index = mIdCollection->getAppendIndex (id, type);
|
||||
|
||||
beginInsertRows (QModelIndex(), index, index);
|
||||
|
||||
|
@ -138,7 +135,7 @@ void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& reco
|
|||
|
||||
if (index==-1)
|
||||
{
|
||||
int index = mIdCollection->getAppendIndex();
|
||||
int index = mIdCollection->getAppendIndex (id);
|
||||
|
||||
beginInsertRows (QModelIndex(), index, index);
|
||||
|
||||
|
@ -168,3 +165,16 @@ int CSMWorld::IdTable::findColumnIndex (Columns::ColumnId id) const
|
|||
{
|
||||
return mIdCollection->findColumnIndex (id);
|
||||
}
|
||||
|
||||
void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newOrder)
|
||||
{
|
||||
if (!newOrder.empty())
|
||||
if (mIdCollection->reorderRows (baseIndex, newOrder))
|
||||
emit dataChanged (index (baseIndex, 0),
|
||||
index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1));
|
||||
}
|
||||
|
||||
CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const
|
||||
{
|
||||
return mReordering;
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef CSM_WOLRD_IDTABLE_H
|
||||
#define CSM_WOLRD_IDTABLE_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
#include "universalid.hpp"
|
||||
|
@ -15,7 +17,18 @@ namespace CSMWorld
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
enum Reordering
|
||||
{
|
||||
Reordering_None,
|
||||
Reordering_WithinTopic
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
CollectionBase *mIdCollection;
|
||||
Reordering mReordering;
|
||||
|
||||
// not implemented
|
||||
IdTable (const IdTable&);
|
||||
|
@ -23,7 +36,7 @@ namespace CSMWorld
|
|||
|
||||
public:
|
||||
|
||||
IdTable (CollectionBase *idCollection);
|
||||
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_WithinTopic);
|
||||
///< The ownership of \a idCollection is not transferred.
|
||||
|
||||
virtual ~IdTable();
|
||||
|
@ -63,6 +76,12 @@ namespace CSMWorld
|
|||
int findColumnIndex (Columns::ColumnId id) const;
|
||||
///< Return index of column with the given \a id. If no such column exists, an exception is
|
||||
/// thrown.
|
||||
|
||||
void reorderRows (int baseIndex, const std::vector<int>& newOrder);
|
||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
|
||||
Reordering getReordering() const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
14
apps/opencs/model/world/info.hpp
Normal file
14
apps/opencs/model/world/info.hpp
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef CSM_WOLRD_INFO_H
|
||||
#define CSM_WOLRD_INFO_H
|
||||
|
||||
#include <components/esm/loadinfo.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
struct Info : public ESM::DialInfo
|
||||
{
|
||||
std::string mTopicId;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
184
apps/opencs/model/world/infocollection.cpp
Normal file
184
apps/opencs/model/world/infocollection.cpp
Normal file
|
@ -0,0 +1,184 @@
|
|||
|
||||
#include "infocollection.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <iterator>
|
||||
|
||||
#include <components/esm/esmreader.hpp>
|
||||
#include <components/esm/loaddial.hpp>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
void CSMWorld::InfoCollection::load (const Info& record, bool base)
|
||||
{
|
||||
int index = searchId (record.mId);
|
||||
|
||||
if (index==-1)
|
||||
{
|
||||
// new record
|
||||
Record<Info> record2;
|
||||
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
|
||||
(base ? record2.mBase : record2.mModified) = record;
|
||||
|
||||
int index = -1;
|
||||
|
||||
std::string topic = Misc::StringUtils::lowerCase (record2.get().mTopicId);
|
||||
|
||||
if (!record2.get().mPrev.empty())
|
||||
{
|
||||
index = getIndex (record2.get().mPrev, topic);
|
||||
|
||||
if (index!=-1)
|
||||
++index;
|
||||
}
|
||||
|
||||
if (index==-1 && !record2.get().mNext.empty())
|
||||
{
|
||||
index = getIndex (record2.get().mNext, topic);
|
||||
}
|
||||
|
||||
if (index==-1)
|
||||
{
|
||||
Range range = getTopicRange (topic);
|
||||
|
||||
index = std::distance (getRecords().begin(), range.second);
|
||||
}
|
||||
|
||||
insertRecord (record2, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
// old record
|
||||
Record<Info> record2 = getRecord (index);
|
||||
|
||||
if (base)
|
||||
record2.mBase = record;
|
||||
else
|
||||
record2.setModified (record);
|
||||
|
||||
setRecord (index, record2);
|
||||
}
|
||||
}
|
||||
|
||||
int CSMWorld::InfoCollection::getIndex (const std::string& id, const std::string& topic) const
|
||||
{
|
||||
std::string fullId = Misc::StringUtils::lowerCase (topic) + "#" + id;
|
||||
|
||||
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (topic);
|
||||
|
||||
for (; range.first!=range.second; ++range.first)
|
||||
if (Misc::StringUtils::lowerCase (range.first->get().mId)==fullId)
|
||||
return std::distance (getRecords().begin(), range.first);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CSMWorld::InfoCollection::getAppendIndex (const std::string& id, UniversalId::Type type) const
|
||||
{
|
||||
std::string::size_type separator = id.find_last_of ('#');
|
||||
|
||||
if (separator==std::string::npos)
|
||||
throw std::runtime_error ("invalid info ID: " + id);
|
||||
|
||||
std::pair<RecordConstIterator, RecordConstIterator> range = getTopicRange (id.substr (0, separator));
|
||||
|
||||
if (range.first==range.second)
|
||||
return Collection<Info, IdAccessor<Info> >::getAppendIndex (id, type);
|
||||
|
||||
return std::distance (getRecords().begin(), range.second);
|
||||
}
|
||||
|
||||
bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int>& newOrder)
|
||||
{
|
||||
// check if the range is valid
|
||||
int lastIndex = baseIndex + newOrder.size() -1;
|
||||
|
||||
if (lastIndex>=getSize())
|
||||
return false;
|
||||
|
||||
// Check that topics match
|
||||
if (getRecord (baseIndex).get().mTopicId!=getRecord (lastIndex).get().mTopicId)
|
||||
return false;
|
||||
|
||||
// reorder
|
||||
return reorderRowsImp (baseIndex, newOrder);
|
||||
}
|
||||
|
||||
void CSMWorld::InfoCollection::load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue)
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase (dialogue.mId) + "#" +
|
||||
reader.getHNOString ("INAM");
|
||||
|
||||
if (reader.isNextSub ("DELE"))
|
||||
{
|
||||
int index = searchId (id);
|
||||
|
||||
reader.skipRecord();
|
||||
|
||||
if (index==-1)
|
||||
{
|
||||
// deleting a record that does not exist
|
||||
|
||||
// ignore it for now
|
||||
|
||||
/// \todo report the problem to the user
|
||||
}
|
||||
else if (base)
|
||||
{
|
||||
removeRows (index, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Record<Info> record = getRecord (index);
|
||||
record.mState = RecordBase::State_Deleted;
|
||||
setRecord (index, record);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Info record;
|
||||
record.mTopicId = dialogue.mId;
|
||||
record.mId = id;
|
||||
record.load (reader);
|
||||
|
||||
load (record, base);
|
||||
}
|
||||
}
|
||||
|
||||
CSMWorld::InfoCollection::Range CSMWorld::InfoCollection::getTopicRange (const std::string& topic)
|
||||
const
|
||||
{
|
||||
std::string topic2 = Misc::StringUtils::lowerCase (topic);
|
||||
|
||||
std::map<std::string, int>::const_iterator iter = getIdMap().lower_bound (topic2);
|
||||
|
||||
// Skip invalid records: The beginning of a topic string could be identical to another topic
|
||||
// string.
|
||||
for (; iter!=getIdMap().end(); ++iter)
|
||||
{
|
||||
std::string testTopicId =
|
||||
Misc::StringUtils::lowerCase (getRecord (iter->second).get().mTopicId);
|
||||
|
||||
if (testTopicId==topic2)
|
||||
break;
|
||||
|
||||
std::size_t size = topic2.size();
|
||||
|
||||
if (testTopicId.size()<size || testTopicId.substr (0, size)!=topic2)
|
||||
return Range (getRecords().end(), getRecords().end());
|
||||
}
|
||||
|
||||
if (iter==getIdMap().end())
|
||||
return Range (getRecords().end(), getRecords().end());
|
||||
|
||||
RecordConstIterator begin = getRecords().begin()+iter->second;
|
||||
|
||||
// Find end
|
||||
RecordConstIterator end = begin;
|
||||
|
||||
for (; end!=getRecords().end(); ++end)
|
||||
if (Misc::StringUtils::lowerCase (end->get().mTopicId)!=topic2)
|
||||
break;
|
||||
|
||||
return Range (begin, end);
|
||||
}
|
50
apps/opencs/model/world/infocollection.hpp
Normal file
50
apps/opencs/model/world/infocollection.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#ifndef CSM_WOLRD_INFOCOLLECTION_H
|
||||
#define CSM_WOLRD_INFOCOLLECTION_H
|
||||
|
||||
#include "collection.hpp"
|
||||
#include "info.hpp"
|
||||
|
||||
namespace ESM
|
||||
{
|
||||
class Dialogue;
|
||||
}
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class InfoCollection : public Collection<Info, IdAccessor<Info> >
|
||||
{
|
||||
public:
|
||||
|
||||
typedef std::vector<Record<Info> >::const_iterator RecordConstIterator;
|
||||
typedef std::pair<RecordConstIterator, RecordConstIterator> Range;
|
||||
|
||||
private:
|
||||
|
||||
void load (const Info& record, bool base);
|
||||
|
||||
int getIndex (const std::string& id, const std::string& topic) const;
|
||||
///< Return index for record \a id or -1 (if not present; deleted records are considered)
|
||||
///
|
||||
/// \param id info ID without topic prefix
|
||||
|
||||
public:
|
||||
|
||||
virtual int getAppendIndex (const std::string& id,
|
||||
UniversalId::Type type = UniversalId::Type_None) const;
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
|
||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
///
|
||||
/// \return Success?
|
||||
|
||||
void load (ESM::ESMReader& reader, bool base, const ESM::Dialogue& dialogue);
|
||||
|
||||
Range getTopicRange (const std::string& topic) const;
|
||||
///< Return iterators that point to the beginning and past the end of the range for
|
||||
/// the given topic.
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -6,7 +6,7 @@
|
|||
void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string& id)
|
||||
{
|
||||
mId = id;
|
||||
mCellId = cell.mId;
|
||||
mCell = cell.mId;
|
||||
|
||||
if (!mDeleted)
|
||||
cell.addRef (mId);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace CSMWorld
|
|||
struct CellRef : public ESM::CellRef
|
||||
{
|
||||
std::string mId;
|
||||
std::string mCellId;
|
||||
std::string mCell;
|
||||
|
||||
void load (ESM::ESMReader &esm, Cell& cell, const std::string& id);
|
||||
///< Load cell ref and register it with \a cell.
|
||||
|
|
|
@ -530,7 +530,7 @@ void CSMWorld::RefIdCollection::load (ESM::ESMReader& reader, bool base, Univers
|
|||
}
|
||||
}
|
||||
|
||||
int CSMWorld::RefIdCollection::getAppendIndex (UniversalId::Type type) const
|
||||
int CSMWorld::RefIdCollection::getAppendIndex (const std::string& id, UniversalId::Type type) const
|
||||
{
|
||||
return mData.getAppendIndex (type);
|
||||
}
|
||||
|
@ -540,6 +540,11 @@ std::vector<std::string> CSMWorld::RefIdCollection::getIds (bool listDeleted) co
|
|||
return mData.getIds (listDeleted);
|
||||
}
|
||||
|
||||
bool CSMWorld::RefIdCollection::reorderRows (int baseIndex, const std::vector<int>& newOrder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSMWorld::RefIdCollection::save (int index, ESM::ESMWriter& writer) const
|
||||
{
|
||||
mData.save (index, writer);
|
||||
|
|
|
@ -92,7 +92,7 @@ namespace CSMWorld
|
|||
|
||||
void load (ESM::ESMReader& reader, bool base, UniversalId::Type type);
|
||||
|
||||
virtual int getAppendIndex (UniversalId::Type type) const;
|
||||
virtual int getAppendIndex (const std::string& id, UniversalId::Type type) const;
|
||||
///< \param type Will be ignored, unless the collection supports multiple record types
|
||||
|
||||
virtual std::vector<std::string> getIds (bool listDeleted) const;
|
||||
|
@ -100,6 +100,12 @@ namespace CSMWorld
|
|||
///
|
||||
/// \param listDeleted include deleted record in the list
|
||||
|
||||
virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
|
||||
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
||||
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
|
||||
///
|
||||
/// \return Success?
|
||||
|
||||
void save (int index, ESM::ESMWriter& writer) const;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ namespace
|
|||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells", 0 },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Topics, "Topics", 0 },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Journals, "Journals", 0 },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_TopicInfos, "Topic Infos", 0 },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_JournalInfos, "Journal Infos", 0 },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Cells, "Cells", 0 },
|
||||
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Referenceables,
|
||||
"Referenceables", 0 },
|
||||
|
@ -58,6 +60,8 @@ namespace
|
|||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", 0 },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" },
|
||||
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 },
|
||||
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" },
|
||||
|
|
|
@ -91,6 +91,10 @@ namespace CSMWorld
|
|||
Type_Topic,
|
||||
Type_Journals,
|
||||
Type_Journal,
|
||||
Type_TopicInfos,
|
||||
Type_TopicInfo,
|
||||
Type_JournalInfos,
|
||||
Type_JournalInfo,
|
||||
Type_Scene
|
||||
};
|
||||
|
||||
|
|
|
@ -26,16 +26,25 @@ namespace CSVDoc
|
|||
template<class SubViewT, class CreatorFactoryT>
|
||||
class SubViewFactoryWithCreator : public SubViewFactoryBase
|
||||
{
|
||||
bool mSorting;
|
||||
|
||||
public:
|
||||
|
||||
SubViewFactoryWithCreator (bool sorting = true);
|
||||
|
||||
virtual CSVDoc::SubView *makeSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
|
||||
};
|
||||
|
||||
template<class SubViewT, class CreatorFactoryT>
|
||||
SubViewFactoryWithCreator<SubViewT, CreatorFactoryT>::SubViewFactoryWithCreator (bool sorting)
|
||||
: mSorting (sorting)
|
||||
{}
|
||||
|
||||
template<class SubViewT, class CreatorFactoryT>
|
||||
CSVDoc::SubView *SubViewFactoryWithCreator<SubViewT, CreatorFactoryT>::makeSubView (
|
||||
const CSMWorld::UniversalId& id, CSMDoc::Document& document)
|
||||
{
|
||||
return new SubViewT (id, document, CreatorFactoryT());
|
||||
return new SubViewT (id, document, CreatorFactoryT(), mSorting);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,41 +136,54 @@ void CSVDoc::View::setupMechanicsMenu()
|
|||
connect (gmsts, SIGNAL (triggered()), this, SLOT (addGmstsSubView()));
|
||||
mechanics->addAction (gmsts);
|
||||
|
||||
QAction *skills = new QAction (tr ("Skills"), this);
|
||||
connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView()));
|
||||
mechanics->addAction (skills);
|
||||
|
||||
QAction *classes = new QAction (tr ("Classes"), this);
|
||||
connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView()));
|
||||
mechanics->addAction (classes);
|
||||
|
||||
QAction *factions = new QAction (tr ("Factions"), this);
|
||||
connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView()));
|
||||
mechanics->addAction (factions);
|
||||
|
||||
QAction *races = new QAction (tr ("Races"), this);
|
||||
connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView()));
|
||||
mechanics->addAction (races);
|
||||
|
||||
QAction *scripts = new QAction (tr ("Scripts"), this);
|
||||
connect (scripts, SIGNAL (triggered()), this, SLOT (addScriptsSubView()));
|
||||
mechanics->addAction (scripts);
|
||||
|
||||
QAction *birthsigns = new QAction (tr ("Birthsigns"), this);
|
||||
connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView()));
|
||||
mechanics->addAction (birthsigns);
|
||||
|
||||
QAction *spells = new QAction (tr ("Spells"), this);
|
||||
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
|
||||
mechanics->addAction (spells);
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupCharacterMenu()
|
||||
{
|
||||
QMenu *characters = menuBar()->addMenu (tr ("Characters"));
|
||||
|
||||
QAction *skills = new QAction (tr ("Skills"), this);
|
||||
connect (skills, SIGNAL (triggered()), this, SLOT (addSkillsSubView()));
|
||||
characters->addAction (skills);
|
||||
|
||||
QAction *classes = new QAction (tr ("Classes"), this);
|
||||
connect (classes, SIGNAL (triggered()), this, SLOT (addClassesSubView()));
|
||||
characters->addAction (classes);
|
||||
|
||||
QAction *factions = new QAction (tr ("Factions"), this);
|
||||
connect (factions, SIGNAL (triggered()), this, SLOT (addFactionsSubView()));
|
||||
characters->addAction (factions);
|
||||
|
||||
QAction *races = new QAction (tr ("Races"), this);
|
||||
connect (races, SIGNAL (triggered()), this, SLOT (addRacesSubView()));
|
||||
characters->addAction (races);
|
||||
|
||||
QAction *birthsigns = new QAction (tr ("Birthsigns"), this);
|
||||
connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView()));
|
||||
characters->addAction (birthsigns);
|
||||
|
||||
QAction *topics = new QAction (tr ("Topics"), this);
|
||||
connect (topics, SIGNAL (triggered()), this, SLOT (addTopicsSubView()));
|
||||
mechanics->addAction (topics);
|
||||
characters->addAction (topics);
|
||||
|
||||
QAction *journals = new QAction (tr ("Journals"), this);
|
||||
connect (journals, SIGNAL (triggered()), this, SLOT (addJournalsSubView()));
|
||||
mechanics->addAction (journals);
|
||||
characters->addAction (journals);
|
||||
|
||||
QAction *topicInfos = new QAction (tr ("Topic Infos"), this);
|
||||
connect (topicInfos, SIGNAL (triggered()), this, SLOT (addTopicInfosSubView()));
|
||||
characters->addAction (topicInfos);
|
||||
|
||||
QAction *journalInfos = new QAction (tr ("Journal Infos"), this);
|
||||
connect (journalInfos, SIGNAL (triggered()), this, SLOT (addJournalInfosSubView()));
|
||||
characters->addAction (journalInfos);
|
||||
}
|
||||
|
||||
void CSVDoc::View::setupAssetsMenu()
|
||||
|
@ -189,6 +202,7 @@ void CSVDoc::View::setupUi()
|
|||
setupViewMenu();
|
||||
setupWorldMenu();
|
||||
setupMechanicsMenu();
|
||||
setupCharacterMenu();
|
||||
setupAssetsMenu();
|
||||
}
|
||||
|
||||
|
@ -430,6 +444,16 @@ void CSVDoc::View::addJournalsSubView()
|
|||
addSubView (CSMWorld::UniversalId::Type_Journals);
|
||||
}
|
||||
|
||||
void CSVDoc::View::addTopicInfosSubView()
|
||||
{
|
||||
addSubView (CSMWorld::UniversalId::Type_TopicInfos);
|
||||
}
|
||||
|
||||
void CSVDoc::View::addJournalInfosSubView()
|
||||
{
|
||||
addSubView (CSMWorld::UniversalId::Type_JournalInfos);
|
||||
}
|
||||
|
||||
void CSVDoc::View::abortOperation (int type)
|
||||
{
|
||||
mDocument->abortOperation (type);
|
||||
|
|
|
@ -63,6 +63,8 @@ namespace CSVDoc
|
|||
|
||||
void setupMechanicsMenu();
|
||||
|
||||
void setupCharacterMenu();
|
||||
|
||||
void setupAssetsMenu();
|
||||
|
||||
void setupUi();
|
||||
|
@ -170,6 +172,10 @@ namespace CSVDoc
|
|||
|
||||
void addJournalsSubView();
|
||||
|
||||
void addTopicInfosSubView();
|
||||
|
||||
void addJournalInfosSubView();
|
||||
|
||||
void toggleShowStatusBar (bool show);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -75,7 +75,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
|
|||
{ CSMWorld::ColumnBase::Display_ClothingType, CSMWorld::Columns::ColumnId_ClothingType, false },
|
||||
{ CSMWorld::ColumnBase::Display_CreatureType, CSMWorld::Columns::ColumnId_CreatureType, false },
|
||||
{ CSMWorld::ColumnBase::Display_WeaponType, CSMWorld::Columns::ColumnId_WeaponType, false },
|
||||
{ CSMWorld::ColumnBase::Display_DialogueType, CSMWorld::Columns::ColumnId_DialogueType, false }
|
||||
{ CSMWorld::ColumnBase::Display_DialogueType, CSMWorld::Columns::ColumnId_DialogueType, false },
|
||||
{ CSMWorld::ColumnBase::Display_QuestStatusType, CSMWorld::Columns::ColumnId_QuestStatusType, false },
|
||||
{ CSMWorld::ColumnBase::Display_Gender, CSMWorld::Columns::ColumnId_Gender, true }
|
||||
};
|
||||
|
||||
for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
|
||||
|
|
|
@ -19,7 +19,7 @@ void CSVWorld::DialogueCreator::configureCreateCommand (CSMWorld::CreateCommand&
|
|||
|
||||
CSVWorld::DialogueCreator::DialogueCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id, int type)
|
||||
: GenericCreator (data, undoStack, id), mType (type)
|
||||
: GenericCreator (data, undoStack, id, true), mType (type)
|
||||
{}
|
||||
|
||||
CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMWorld::Data& data,
|
||||
|
|
|
@ -57,14 +57,14 @@ const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
|
|||
}
|
||||
|
||||
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id)
|
||||
const CSMWorld::UniversalId& id, bool relaxedIdRules)
|
||||
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false)
|
||||
{
|
||||
mLayout = new QHBoxLayout;
|
||||
mLayout->setContentsMargins (0, 0, 0, 0);
|
||||
|
||||
mId = new QLineEdit;
|
||||
mId->setValidator (new IdValidator (this));
|
||||
mId->setValidator (new IdValidator (relaxedIdRules, this));
|
||||
mLayout->addWidget (mId, 1);
|
||||
|
||||
mCreate = new QPushButton ("Create");
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace CSVWorld
|
|||
public:
|
||||
|
||||
GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id);
|
||||
const CSMWorld::UniversalId& id, bool relaxedIdRules = false);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
|
||||
|
|
|
@ -12,15 +12,25 @@ bool CSVWorld::IdValidator::isValid (const QChar& c, bool first) const
|
|||
return false;
|
||||
}
|
||||
|
||||
CSVWorld::IdValidator::IdValidator (QObject *parent) : QValidator (parent) {}
|
||||
CSVWorld::IdValidator::IdValidator (bool relaxed, QObject *parent)
|
||||
: QValidator (parent), mRelaxed (relaxed)
|
||||
{}
|
||||
|
||||
QValidator::State CSVWorld::IdValidator::validate (QString& input, int& pos) const
|
||||
{
|
||||
if (mRelaxed)
|
||||
{
|
||||
if (input.indexOf ('"')!=-1 || input.indexOf ("::")!=-1 || input.indexOf ("#")!=-1)
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool first = true;
|
||||
|
||||
for (QString::const_iterator iter (input.begin()); iter!=input.end(); ++iter, first = false)
|
||||
if (!isValid (*iter, first))
|
||||
return QValidator::Invalid;
|
||||
}
|
||||
|
||||
return QValidator::Acceptable;
|
||||
}
|
|
@ -7,13 +7,16 @@ namespace CSVWorld
|
|||
{
|
||||
class IdValidator : public QValidator
|
||||
{
|
||||
bool mRelaxed;
|
||||
|
||||
private:
|
||||
|
||||
bool isValid (const QChar& c, bool first) const;
|
||||
|
||||
public:
|
||||
|
||||
IdValidator (QObject *parent = 0);
|
||||
IdValidator (bool relaxed = false, QObject *parent = 0);
|
||||
///< \param relaxed Relaxed rules for IDs that also functino as user visible text
|
||||
|
||||
virtual State validate (QString& input, int& pos) const;
|
||||
|
||||
|
|
81
apps/opencs/view/world/infocreator.cpp
Normal file
81
apps/opencs/view/world/infocreator.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
|
||||
#include "infocreator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QUuid>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include "../../model/world/data.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/columns.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
|
||||
std::string CSVWorld::InfoCreator::getId() const
|
||||
{
|
||||
std::string id = Misc::StringUtils::lowerCase (mTopic->text().toUtf8().constData());
|
||||
|
||||
std::string unique = QUuid::createUuid().toByteArray().data();
|
||||
|
||||
unique.erase (std::remove (unique.begin(), unique.end(), '-'), unique.end());
|
||||
|
||||
unique = unique.substr (1, unique.size()-2);
|
||||
|
||||
return id + '#' + unique;
|
||||
}
|
||||
|
||||
void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
|
||||
{
|
||||
int index =
|
||||
dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())).
|
||||
findColumnIndex (
|
||||
getCollectionId().getType()==CSMWorld::UniversalId::Type_TopicInfos ?
|
||||
CSMWorld::Columns::ColumnId_Topic : CSMWorld::Columns::ColumnId_Journal);
|
||||
|
||||
command.addValue (index, mTopic->text());
|
||||
}
|
||||
|
||||
CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id)
|
||||
: GenericCreator (data, undoStack, id)
|
||||
{
|
||||
QLabel *label = new QLabel ("Topic", this);
|
||||
insertBeforeButtons (label, false);
|
||||
|
||||
mTopic = new QLineEdit (this);
|
||||
insertBeforeButtons (mTopic, true);
|
||||
|
||||
setManualEditing (false);
|
||||
|
||||
connect (mTopic, SIGNAL (textChanged (const QString&)), this, SLOT (topicChanged()));
|
||||
}
|
||||
|
||||
void CSVWorld::InfoCreator::reset()
|
||||
{
|
||||
mTopic->setText ("");
|
||||
GenericCreator::reset();
|
||||
}
|
||||
|
||||
std::string CSVWorld::InfoCreator::getErrors() const
|
||||
{
|
||||
// We ignore errors from GenericCreator here, because they can never happen in an InfoCreator.
|
||||
std::string errors;
|
||||
|
||||
std::string topic = mTopic->text().toUtf8().constData();
|
||||
|
||||
if ((getCollectionId().getType()==CSMWorld::UniversalId::Type_TopicInfos ?
|
||||
getData().getTopics() : getData().getJournals()).searchId (topic)==-1)
|
||||
{
|
||||
errors += "Invalid Topic ID";
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
void CSVWorld::InfoCreator::topicChanged()
|
||||
{
|
||||
update();
|
||||
}
|
42
apps/opencs/view/world/infocreator.hpp
Normal file
42
apps/opencs/view/world/infocreator.hpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef CSV_WORLD_INFOCREATOR_H
|
||||
#define CSV_WORLD_INFOCREATOR_H
|
||||
|
||||
#include "genericcreator.hpp"
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
namespace CSMWorld
|
||||
{
|
||||
class InfoCollection;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
{
|
||||
class InfoCreator : public GenericCreator
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QLineEdit *mTopic;
|
||||
|
||||
virtual std::string getId() const;
|
||||
|
||||
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
|
||||
|
||||
public:
|
||||
|
||||
InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
const CSMWorld::UniversalId& id);
|
||||
|
||||
virtual void reset();
|
||||
|
||||
virtual std::string getErrors() const;
|
||||
///< Return formatted error descriptions for the current state of the creator. if an empty
|
||||
/// string is returned, there is no error.
|
||||
|
||||
private slots:
|
||||
|
||||
void topicChanged();
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,6 +15,7 @@
|
|||
#include "referencecreator.hpp"
|
||||
#include "scenesubview.hpp"
|
||||
#include "dialoguecreator.hpp"
|
||||
#include "infocreator.hpp"
|
||||
|
||||
void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
||||
{
|
||||
|
@ -60,6 +61,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
|
|||
manager.add (CSMWorld::UniversalId::Type_Journal,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>);
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_TopicInfos,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> > (false));
|
||||
|
||||
manager.add (CSMWorld::UniversalId::Type_JournalInfos,
|
||||
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> > (false));
|
||||
|
||||
// Subviews for editing/viewing individual records
|
||||
manager.add (CSMWorld::UniversalId::Type_Script, new CSVDoc::SubViewFactory<ScriptSubView>);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../../model/world/idtableproxymodel.hpp"
|
||||
#include "../../model/world/idtable.hpp"
|
||||
#include "../../model/world/record.hpp"
|
||||
#include "../../model/world/columns.hpp"
|
||||
|
||||
#include "recordstatusdelegate.hpp"
|
||||
#include "util.hpp"
|
||||
|
@ -32,11 +33,43 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
|
|||
if (mCreateAction)
|
||||
menu.addAction (mCreateAction);
|
||||
|
||||
/// \todo Reverting temporarily disabled on tables that support reordering, because
|
||||
/// revert logic currently can not handle reordering.
|
||||
if (mModel->getReordering()==CSMWorld::IdTable::Reordering_None)
|
||||
if (listRevertableSelectedIds().size()>0)
|
||||
menu.addAction (mRevertAction);
|
||||
|
||||
if (listDeletableSelectedIds().size()>0)
|
||||
menu.addAction (mDeleteAction);
|
||||
|
||||
if (mModel->getReordering()==CSMWorld::IdTable::Reordering_WithinTopic)
|
||||
{
|
||||
/// \todo allow reordering of multiple rows
|
||||
if (selectedRows.size()==1)
|
||||
{
|
||||
int row =selectedRows.begin()->row();
|
||||
|
||||
int column = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Topic);
|
||||
|
||||
if (column==-1)
|
||||
column = mModel->findColumnIndex (CSMWorld::Columns::ColumnId_Journal);
|
||||
|
||||
if (column!=-1)
|
||||
{
|
||||
if (row>0 && mProxyModel->data (mProxyModel->index (row, column))==
|
||||
mProxyModel->data (mProxyModel->index (row-1, column)))
|
||||
{
|
||||
menu.addAction (mMoveUpAction);
|
||||
}
|
||||
|
||||
if (row<mProxyModel->rowCount()-1 && mProxyModel->data (mProxyModel->index (row, column))==
|
||||
mProxyModel->data (mProxyModel->index (row+1, column)))
|
||||
{
|
||||
menu.addAction (mMoveDownAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu.exec (event->globalPos());
|
||||
|
@ -121,7 +154,7 @@ std::vector<std::string> CSVWorld::Table::listDeletableSelectedIds() const
|
|||
}
|
||||
|
||||
CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack,
|
||||
bool createAndDelete)
|
||||
bool createAndDelete, bool sorting)
|
||||
: mUndoStack (undoStack), mCreateAction (0), mEditLock (false), mRecordStatusDisplay (0)
|
||||
{
|
||||
mModel = &dynamic_cast<CSMWorld::IdTable&> (*data.getTableModel (id));
|
||||
|
@ -132,7 +165,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
|||
setModel (mProxyModel);
|
||||
horizontalHeader()->setResizeMode (QHeaderView::Interactive);
|
||||
verticalHeader()->hide();
|
||||
setSortingEnabled (true);
|
||||
setSortingEnabled (sorting);
|
||||
setSelectionBehavior (QAbstractItemView::SelectRows);
|
||||
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||
|
||||
|
@ -176,6 +209,14 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, Q
|
|||
connect (mDeleteAction, SIGNAL (triggered()), this, SLOT (deleteRecord()));
|
||||
addAction (mDeleteAction);
|
||||
|
||||
mMoveUpAction = new QAction (tr ("Move Up"), this);
|
||||
connect (mMoveUpAction, SIGNAL (triggered()), this, SLOT (moveUpRecord()));
|
||||
addAction (mMoveUpAction);
|
||||
|
||||
mMoveDownAction = new QAction (tr ("Move Down"), this);
|
||||
connect (mMoveDownAction, SIGNAL (triggered()), this, SLOT (moveDownRecord()));
|
||||
addAction (mMoveDownAction);
|
||||
|
||||
connect (mProxyModel, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
|
||||
this, SLOT (tableSizeUpdate()));
|
||||
|
||||
|
@ -254,6 +295,64 @@ void CSVWorld::Table::editRecord()
|
|||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::moveUpRecord()
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
if (selectedRows.size()==1)
|
||||
{
|
||||
int row2 =selectedRows.begin()->row();
|
||||
|
||||
if (row2>0)
|
||||
{
|
||||
int row = row2-1;
|
||||
|
||||
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
|
||||
row2 = mProxyModel->mapToSource (mProxyModel->index (row2, 0)).row();
|
||||
|
||||
if (row2<=row)
|
||||
throw std::runtime_error ("Inconsistent row order");
|
||||
|
||||
std::vector<int> newOrder (row2-row+1);
|
||||
newOrder[0] = row2-row;
|
||||
newOrder[row2-row] = 0;
|
||||
for (int i=1; i<row2-row; ++i)
|
||||
newOrder[i] = i;
|
||||
|
||||
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::moveDownRecord()
|
||||
{
|
||||
QModelIndexList selectedRows = selectionModel()->selectedRows();
|
||||
|
||||
if (selectedRows.size()==1)
|
||||
{
|
||||
int row =selectedRows.begin()->row();
|
||||
|
||||
if (row<mProxyModel->rowCount()-1)
|
||||
{
|
||||
int row2 = row+1;
|
||||
|
||||
row = mProxyModel->mapToSource (mProxyModel->index (row, 0)).row();
|
||||
row2 = mProxyModel->mapToSource (mProxyModel->index (row2, 0)).row();
|
||||
|
||||
if (row2<=row)
|
||||
throw std::runtime_error ("Inconsistent row order");
|
||||
|
||||
std::vector<int> newOrder (row2-row+1);
|
||||
newOrder[0] = row2-row;
|
||||
newOrder[row2-row] = 0;
|
||||
for (int i=1; i<row2-row; ++i)
|
||||
newOrder[i] = i;
|
||||
|
||||
mUndoStack.push (new CSMWorld::ReorderRowsCommand (*mModel, row, newOrder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSVWorld::Table::updateEditorSetting (const QString &settingName, const QString &settingValue)
|
||||
{
|
||||
int columns = mModel->columnCount();
|
||||
|
|
|
@ -34,6 +34,8 @@ namespace CSVWorld
|
|||
QAction *mCreateAction;
|
||||
QAction *mRevertAction;
|
||||
QAction *mDeleteAction;
|
||||
QAction *mMoveUpAction;
|
||||
QAction *mMoveDownAction;
|
||||
CSMWorld::IdTableProxyModel *mProxyModel;
|
||||
CSMWorld::IdTable *mModel;
|
||||
bool mEditLock;
|
||||
|
@ -49,8 +51,9 @@ namespace CSVWorld
|
|||
|
||||
public:
|
||||
|
||||
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete);
|
||||
Table (const CSMWorld::UniversalId& id, CSMWorld::Data& data, QUndoStack& undoStack, bool createAndDelete, bool sorting);
|
||||
///< \param createAndDelete Allow creation and deletion of records.
|
||||
/// \param sorting Allow changing order of rows in the view via column headers.
|
||||
|
||||
void setEditLock (bool locked);
|
||||
|
||||
|
@ -79,6 +82,10 @@ namespace CSVWorld
|
|||
|
||||
void editRecord();
|
||||
|
||||
void moveUpRecord();
|
||||
|
||||
void moveDownRecord();
|
||||
|
||||
public slots:
|
||||
|
||||
void tableSizeUpdate();
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "creator.hpp"
|
||||
|
||||
CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
||||
const CreatorFactoryBase& creatorFactory)
|
||||
const CreatorFactoryBase& creatorFactory, bool sorting)
|
||||
: SubView (id)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
|
@ -23,7 +23,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
|
|||
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
|
||||
|
||||
layout->insertWidget (0, mTable =
|
||||
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete()), 2);
|
||||
new Table (id, document.getData(), document.getUndoStack(), mBottom->canCreateAndDelete(), sorting), 2);
|
||||
|
||||
CSVFilter::FilterBox *filterBox = new CSVFilter::FilterBox (document.getData(), this);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace CSVWorld
|
|||
public:
|
||||
|
||||
TableSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
|
||||
const CreatorFactoryBase& creatorFactory);
|
||||
const CreatorFactoryBase& creatorFactory, bool sorting);
|
||||
|
||||
virtual void setEditLock (bool locked);
|
||||
|
||||
|
|
|
@ -58,13 +58,13 @@ bool MWDialogue::Filter::testActor (const ESM::DialInfo& info) const
|
|||
}
|
||||
|
||||
// NPC faction
|
||||
if (!info.mNpcFaction.empty())
|
||||
if (!info.mFaction.empty())
|
||||
{
|
||||
if (isCreature)
|
||||
return false;
|
||||
|
||||
MWMechanics::NpcStats& stats = MWWorld::Class::get (mActor).getNpcStats (mActor);
|
||||
std::map<std::string, int>::iterator iter = stats.getFactionRanks().find ( Misc::StringUtils::lowerCase (info.mNpcFaction));
|
||||
std::map<std::string, int>::iterator iter = stats.getFactionRanks().find ( Misc::StringUtils::lowerCase (info.mFaction));
|
||||
|
||||
if (iter==stats.getFactionRanks().end())
|
||||
return false;
|
||||
|
|
|
@ -253,6 +253,8 @@ namespace MWGui
|
|||
|
||||
void InventoryWindow::open()
|
||||
{
|
||||
mPtr = MWBase::Environment::get().getWorld()->getPlayer().getPlayer();
|
||||
|
||||
updateEncumbranceBar();
|
||||
|
||||
mItemView->update();
|
||||
|
|
|
@ -70,8 +70,10 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
|
|||
|
||||
if (it == mStores.end()) {
|
||||
if (n.val == ESM::REC_INFO) {
|
||||
std::string id = esm.getHNOString("INAM");
|
||||
if (dialogue) {
|
||||
dialogue->mInfo.push_back(ESM::DialInfo());
|
||||
dialogue->mInfo.back().mId = id;
|
||||
dialogue->mInfo.back().load(esm);
|
||||
} else {
|
||||
std::cerr << "error: info record without dialog" << std::endl;
|
||||
|
|
|
@ -2239,6 +2239,7 @@ namespace MWWorld
|
|||
|
||||
void World::updateAnimParts(const Ptr& actor)
|
||||
{
|
||||
if (actor.mCell && actor.mCell == mWorldScene->getCurrentCell())
|
||||
mRendering->updateAnimParts(actor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ namespace ESM
|
|||
|
||||
void DialInfo::load(ESMReader &esm)
|
||||
{
|
||||
mId = esm.getHNString("INAM");
|
||||
mPrev = esm.getHNString("PNAM");
|
||||
mNext = esm.getHNString("NNAM");
|
||||
|
||||
|
@ -50,8 +49,8 @@ void DialInfo::load(ESMReader &esm)
|
|||
mFactionLess = false;
|
||||
if (subName.val == REC_FNAM)
|
||||
{
|
||||
mNpcFaction = esm.getHString();
|
||||
if (mNpcFaction == "FFFF")
|
||||
mFaction = esm.getHString();
|
||||
if (mFaction == "FFFF")
|
||||
mFactionLess = true;
|
||||
if (esm.isEmptyOrGetName())
|
||||
return;
|
||||
|
@ -124,14 +123,13 @@ void DialInfo::load(ESMReader &esm)
|
|||
|
||||
void DialInfo::save(ESMWriter &esm) const
|
||||
{
|
||||
esm.writeHNCString("INAM", mId);
|
||||
esm.writeHNCString("PNAM", mPrev);
|
||||
esm.writeHNCString("NNAM", mNext);
|
||||
esm.writeHNT("DATA", mData, 12);
|
||||
esm.writeHNOCString("ONAM", mActor);
|
||||
esm.writeHNOCString("RNAM", mRace);
|
||||
esm.writeHNOCString("CNAM", mClass);
|
||||
esm.writeHNOCString("FNAM", mNpcFaction);
|
||||
esm.writeHNOCString("FNAM", mFaction);
|
||||
esm.writeHNOCString("ANAM", mCell);
|
||||
esm.writeHNOCString("DNAM", mPcFaction);
|
||||
esm.writeHNOCString("SNAM", mSound);
|
||||
|
@ -155,4 +153,28 @@ void DialInfo::save(ESMWriter &esm) const
|
|||
}
|
||||
}
|
||||
|
||||
void DialInfo::blank()
|
||||
{
|
||||
mData.mUnknown1 = 0;
|
||||
mData.mDisposition = 0;
|
||||
mData.mRank = 0;
|
||||
mData.mGender = 0;
|
||||
mData.mPCrank = 0;
|
||||
mData.mUnknown2 = 0;
|
||||
|
||||
mSelects.clear();
|
||||
mPrev.clear();
|
||||
mNext.clear();
|
||||
mActor.clear();
|
||||
mRace.clear();
|
||||
mClass.clear();
|
||||
mFaction.clear();
|
||||
mPcFaction.clear();
|
||||
mCell.clear();
|
||||
mSound.clear();
|
||||
mResponse.clear();
|
||||
mResultScript.clear();
|
||||
mFactionLess = false;
|
||||
mQuestStatus = QS_None;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,10 +50,10 @@ struct DialInfo
|
|||
// Journal quest indices (introduced with the quest system in Tribunal)
|
||||
enum QuestStatus
|
||||
{
|
||||
QS_None,
|
||||
QS_Name,
|
||||
QS_Finished,
|
||||
QS_Restart,
|
||||
QS_None = 0,
|
||||
QS_Name = 1,
|
||||
QS_Finished = 2,
|
||||
QS_Restart = 3,
|
||||
QS_Deleted
|
||||
};
|
||||
|
||||
|
@ -65,7 +65,7 @@ struct DialInfo
|
|||
std::string mId, mPrev, mNext;
|
||||
|
||||
// Various references used in determining when to select this item.
|
||||
std::string mActor, mRace, mClass, mNpcFaction, mPcFaction, mCell;
|
||||
std::string mActor, mRace, mClass, mFaction, mPcFaction, mCell;
|
||||
|
||||
// Sound and text associated with this item
|
||||
std::string mSound, mResponse;
|
||||
|
@ -102,6 +102,9 @@ struct DialInfo
|
|||
|
||||
void load(ESMReader &esm);
|
||||
void save(ESMWriter &esm) const;
|
||||
|
||||
void blank();
|
||||
///< Set record to default state (does not touch the ID).
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue