diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 3181eaa47..3d9f1084e 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -23,12 +23,12 @@ opencs_units (model/world opencs_units_noqt (model/world - universalid data record idcollection commands columnbase scriptcontext cell refidcollection + universalid data record commands columnbase scriptcontext cell refidcollection refidadapter refiddata refidadapterimp ref collectionbase ) opencs_hdrs_noqt (model/world - columns + columns idcollection collection ) diff --git a/apps/opencs/model/world/collection.hpp b/apps/opencs/model/world/collection.hpp new file mode 100644 index 000000000..526c07815 --- /dev/null +++ b/apps/opencs/model/world/collection.hpp @@ -0,0 +1,318 @@ +#ifndef CSM_WOLRD_COLLECTION_H +#define CSM_WOLRD_COLLECTION_H + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "columnbase.hpp" + +#include "collectionbase.hpp" + +namespace CSMWorld +{ + /// \brief Access to ID field in records + template + struct IdAccessor + { + std::string& getId (ESXRecordT& record); + + const std::string getId (const ESXRecordT& record) const; + }; + + template + std::string& IdAccessor::getId (ESXRecordT& record) + { + return record.mId; + } + + template + const std::string IdAccessor::getId (const ESXRecordT& record) const + { + return record.mId; + } + + /// \brief Single-type record collection + template > + class Collection : public CollectionBase + { + std::vector > mRecords; + std::map mIndex; + std::vector *> mColumns; + + // not implemented + Collection (const Collection&); + Collection& operator= (const Collection&); + + public: + + Collection(); + + virtual ~Collection(); + + void add (const ESXRecordT& record); + ///< Add a new record (modified) + + virtual int getSize() const; + + virtual std::string getId (int index) const; + + virtual int getIndex (const std::string& id) const; + + virtual int getColumns() const; + + virtual QVariant getData (int index, int column) const; + + virtual void setData (int index, int column, const QVariant& data); + + virtual const ColumnBase& getColumn (int column) const; + + virtual void merge(); + ///< Merge modified into base. + + virtual void purge(); + ///< Remove records that are flagged as erased. + + virtual void removeRows (int index, int count) ; + + virtual void appendBlankRecord (const std::string& id, + UniversalId::Type type = UniversalId::Type_None); + ///< \param type Will be ignored, unless the collection supports multiple record types + + virtual int searchId (const std::string& id) const; + ////< Search record with \a id. + /// \return index of record (if found) or -1 (not found) + + virtual void replace (int index, const RecordBase& record); + ///< If the record type does not match, an exception is thrown. + /// + /// \attention \a record must not change the ID. + + virtual void appendRecord (const RecordBase& record, + UniversalId::Type type = UniversalId::Type_None); + ///< If the record type does not match, an exception is thrown. + ///< \param type Will be ignored, unless the collection supports multiple record types + + virtual const Record& getRecord (const std::string& id) const; + + virtual const Record& getRecord (int index) const; + + virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const; + ///< \param type Will be ignored, unless the collection supports multiple record types + + void addColumn (Column *column); + + void setRecord (int index, const Record& record); + ///< \attention This function must not change the ID. + }; + + template + Collection::Collection() + {} + + template + Collection::~Collection() + { + for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) + delete *iter; + } + + template + void Collection::add (const ESXRecordT& record) + { + std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record)); + + std::map::iterator iter = mIndex.find (id); + + if (iter==mIndex.end()) + { + Record record2; + record2.mState = Record::State_ModifiedOnly; + record2.mModified = record; + + mRecords.push_back (record2); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mRecords.size()-1)); + } + else + { + mRecords[iter->second].setModified (record); + } + } + + template + int Collection::getSize() const + { + return mRecords.size(); + } + + template + std::string Collection::getId (int index) const + { + return IdAccessorT().getId (mRecords.at (index).get()); + } + + template + int Collection::getIndex (const std::string& id) const + { + int index = searchId (id); + + if (index==-1) + throw std::runtime_error ("invalid ID: " + id); + + return index; + } + + template + int Collection::getColumns() const + { + return mColumns.size(); + } + + template + QVariant Collection::getData (int index, int column) const + { + return mColumns.at (column)->get (mRecords.at (index)); + } + + template + void Collection::setData (int index, int column, const QVariant& data) + { + return mColumns.at (column)->set (mRecords.at (index), data); + } + + template + const ColumnBase& Collection::getColumn (int column) const + { + return *mColumns.at (column); + } + + template + void Collection::addColumn (Column *column) + { + mColumns.push_back (column); + } + + template + void Collection::merge() + { + for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) + iter->merge(); + + purge(); + } + + template + void Collection::purge() + { + int i = 0; + + while (i (mRecords.size())) + { + if (mRecords[i].isErased()) + removeRows (i, 1); + else + ++i; + } + } + + template + void Collection::removeRows (int index, int count) + { + mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); + + typename std::map::iterator iter = mIndex.begin(); + + while (iter!=mIndex.end()) + { + if (iter->second>=index) + { + if (iter->second>=index+count) + { + iter->second -= count; + } + else + { + mIndex.erase (iter++); + } + } + + ++iter; + } + } + + template + void Collection::appendBlankRecord (const std::string& id, + UniversalId::Type type) + { + ESXRecordT record; + IdAccessorT().getId (record) = id; + record.blank(); + add (record); + } + + template + int Collection::searchId (const std::string& id) const + { + std::string id2 = Misc::StringUtils::lowerCase(id); + + std::map::const_iterator iter = mIndex.find (id2); + + if (iter==mIndex.end()) + return -1; + + return iter->second; + } + + template + void Collection::replace (int index, const RecordBase& record) + { + mRecords.at (index) = dynamic_cast&> (record); + } + + template + void Collection::appendRecord (const RecordBase& record, + UniversalId::Type type) + { + mRecords.push_back (dynamic_cast&> (record)); + mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId ( + dynamic_cast&> (record).get())), + mRecords.size()-1)); + } + + template + int Collection::getAppendIndex (UniversalId::Type type) const + { + return static_cast (mRecords.size()); + } + + template + const Record& Collection::getRecord (const std::string& id) const + { + int index = getIndex (id); + return mRecords.at (index); + } + + template + const Record& Collection::getRecord (int index) const + { + return mRecords.at (index); + } + + template + void Collection::setRecord (int index, const Record& record) + { + if (IdAccessorT().getId (mRecords.at (index).get())!=IdAccessorT().getId (record.get())) + throw std::runtime_error ("attempt to change the ID of a record"); + + mRecords.at (index) = record; + } +} + +#endif diff --git a/apps/opencs/model/world/idcollection.cpp b/apps/opencs/model/world/idcollection.cpp deleted file mode 100644 index e8a5195fe..000000000 --- a/apps/opencs/model/world/idcollection.cpp +++ /dev/null @@ -1,3 +0,0 @@ - -#include "idcollection.hpp" - diff --git a/apps/opencs/model/world/idcollection.hpp b/apps/opencs/model/world/idcollection.hpp index 3ba26193a..e0097747c 100644 --- a/apps/opencs/model/world/idcollection.hpp +++ b/apps/opencs/model/world/idcollection.hpp @@ -1,320 +1,12 @@ #ifndef CSM_WOLRD_IDCOLLECTION_H #define CSM_WOLRD_IDCOLLECTION_H -#include -#include -#include -#include -#include -#include - -#include - #include -#include - -#include "columnbase.hpp" - -#include "collectionbase.hpp" +#include "collection.hpp" namespace CSMWorld { - /// \brief Access to ID field in records - template - struct IdAccessor - { - std::string& getId (ESXRecordT& record); - - const std::string getId (const ESXRecordT& record) const; - }; - - template - std::string& IdAccessor::getId (ESXRecordT& record) - { - return record.mId; - } - - template - const std::string IdAccessor::getId (const ESXRecordT& record) const - { - return record.mId; - } - - /// \brief Single-type record collection - template > - class Collection : public CollectionBase - { - std::vector > mRecords; - std::map mIndex; - std::vector *> mColumns; - - // not implemented - Collection (const Collection&); - Collection& operator= (const Collection&); - - public: - - Collection(); - - virtual ~Collection(); - - void add (const ESXRecordT& record); - ///< Add a new record (modified) - - virtual int getSize() const; - - virtual std::string getId (int index) const; - - virtual int getIndex (const std::string& id) const; - - virtual int getColumns() const; - - virtual QVariant getData (int index, int column) const; - - virtual void setData (int index, int column, const QVariant& data); - - virtual const ColumnBase& getColumn (int column) const; - - virtual void merge(); - ///< Merge modified into base. - - virtual void purge(); - ///< Remove records that are flagged as erased. - - virtual void removeRows (int index, int count) ; - - virtual void appendBlankRecord (const std::string& id, - UniversalId::Type type = UniversalId::Type_None); - ///< \param type Will be ignored, unless the collection supports multiple record types - - virtual int searchId (const std::string& id) const; - ////< Search record with \a id. - /// \return index of record (if found) or -1 (not found) - - virtual void replace (int index, const RecordBase& record); - ///< If the record type does not match, an exception is thrown. - /// - /// \attention \a record must not change the ID. - - virtual void appendRecord (const RecordBase& record, - UniversalId::Type type = UniversalId::Type_None); - ///< If the record type does not match, an exception is thrown. - ///< \param type Will be ignored, unless the collection supports multiple record types - - virtual const Record& getRecord (const std::string& id) const; - - virtual const Record& getRecord (int index) const; - - virtual int getAppendIndex (UniversalId::Type type = UniversalId::Type_None) const; - ///< \param type Will be ignored, unless the collection supports multiple record types - - void addColumn (Column *column); - - void setRecord (int index, const Record& record); - ///< \attention This function must not change the ID. - }; - - template - Collection::Collection() - {} - - template - Collection::~Collection() - { - for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) - delete *iter; - } - - template - void Collection::add (const ESXRecordT& record) - { - std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record)); - - std::map::iterator iter = mIndex.find (id); - - if (iter==mIndex.end()) - { - Record record2; - record2.mState = Record::State_ModifiedOnly; - record2.mModified = record; - - mRecords.push_back (record2); - mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (id), mRecords.size()-1)); - } - else - { - mRecords[iter->second].setModified (record); - } - } - - template - int Collection::getSize() const - { - return mRecords.size(); - } - - template - std::string Collection::getId (int index) const - { - return IdAccessorT().getId (mRecords.at (index).get()); - } - - template - int Collection::getIndex (const std::string& id) const - { - int index = searchId (id); - - if (index==-1) - throw std::runtime_error ("invalid ID: " + id); - - return index; - } - - template - int Collection::getColumns() const - { - return mColumns.size(); - } - - template - QVariant Collection::getData (int index, int column) const - { - return mColumns.at (column)->get (mRecords.at (index)); - } - - template - void Collection::setData (int index, int column, const QVariant& data) - { - return mColumns.at (column)->set (mRecords.at (index), data); - } - - template - const ColumnBase& Collection::getColumn (int column) const - { - return *mColumns.at (column); - } - - template - void Collection::addColumn (Column *column) - { - mColumns.push_back (column); - } - - template - void Collection::merge() - { - for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) - iter->merge(); - - purge(); - } - - template - void Collection::purge() - { - int i = 0; - - while (i (mRecords.size())) - { - if (mRecords[i].isErased()) - removeRows (i, 1); - else - ++i; - } - } - - template - void Collection::removeRows (int index, int count) - { - mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count); - - typename std::map::iterator iter = mIndex.begin(); - - while (iter!=mIndex.end()) - { - if (iter->second>=index) - { - if (iter->second>=index+count) - { - iter->second -= count; - } - else - { - mIndex.erase (iter++); - } - } - - ++iter; - } - } - - template - void Collection::appendBlankRecord (const std::string& id, - UniversalId::Type type) - { - ESXRecordT record; - IdAccessorT().getId (record) = id; - record.blank(); - add (record); - } - - template - int Collection::searchId (const std::string& id) const - { - std::string id2 = Misc::StringUtils::lowerCase(id); - - std::map::const_iterator iter = mIndex.find (id2); - - if (iter==mIndex.end()) - return -1; - - return iter->second; - } - - template - void Collection::replace (int index, const RecordBase& record) - { - mRecords.at (index) = dynamic_cast&> (record); - } - - template - void Collection::appendRecord (const RecordBase& record, - UniversalId::Type type) - { - mRecords.push_back (dynamic_cast&> (record)); - mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId ( - dynamic_cast&> (record).get())), - mRecords.size()-1)); - } - - template - int Collection::getAppendIndex (UniversalId::Type type) const - { - return static_cast (mRecords.size()); - } - - template - const Record& Collection::getRecord (const std::string& id) const - { - int index = getIndex (id); - return mRecords.at (index); - } - - template - const Record& Collection::getRecord (int index) const - { - return mRecords.at (index); - } - - template - void Collection::setRecord (int index, const Record& record) - { - if (IdAccessorT().getId (mRecords.at (index).get())!=IdAccessorT().getId (record.get())) - throw std::runtime_error ("attempt to change the ID of a record"); - - mRecords.at (index) = record; - } /// \brief Single type collection of top level records template >