#ifndef CSM_WOLRD_IDCOLLECTION_H #define CSM_WOLRD_IDCOLLECTION_H #include #include #include #include #include #include #include #include #include "columnbase.hpp" namespace CSMWorld { class IdCollectionBase { // not implemented IdCollectionBase (const IdCollectionBase&); IdCollectionBase& operator= (const IdCollectionBase&); public: IdCollectionBase(); virtual ~IdCollectionBase(); virtual int getSize() const = 0; virtual std::string getId (int index) const = 0; virtual int getIndex (const std::string& id) const = 0; virtual int getColumns() const = 0; virtual const ColumnBase& getColumn (int column) const = 0; virtual QVariant getData (int index, int column) const = 0; virtual void setData (int index, int column, const QVariant& data) = 0; virtual void merge() = 0; ///< Merge modified into base. virtual void purge() = 0; ///< Remove records that are flagged as erased. virtual void removeRows (int index, int count) = 0; virtual void appendBlankRecord (const std::string& id) = 0; virtual int searchId (const std::string& id) const = 0; ////< Search record with \a id. /// \return index of record (if found) or -1 (not found) virtual void replace (int index, const RecordBase& record) = 0; ///< 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) = 0; ///< If the record type does not match, an exception is thrown. virtual std::string getId (const RecordBase& record) const = 0; ///< Return ID for \a record. /// /// \attention Throw san exception, if the type of \a record does not match. virtual const RecordBase& getRecord (const std::string& id) const = 0; }; ///< \brief Collection of ID-based records template class IdCollection : public IdCollectionBase { std::vector > mRecords; std::map mIndex; std::vector *> mColumns; // not implemented IdCollection (const IdCollection&); IdCollection& operator= (const IdCollection&); public: IdCollection(); virtual ~IdCollection(); 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); 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); ///< If the record type does not match, an exception is thrown. virtual std::string getId (const RecordBase& record) const; ///< Return ID for \a record. /// /// \attention Throw san exception, if the type of \a record does not match. virtual const RecordBase& getRecord (const std::string& id) const; void addColumn (Column *column); }; template IdCollection::IdCollection() {} template IdCollection::~IdCollection() { for (typename std::vector *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter) delete *iter; } template void IdCollection::add (const ESXRecordT& record) { std::string id; std::transform (record.mId.begin(), record.mId.end(), std::back_inserter (id), (int(*)(int)) std::tolower); 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 (id, mRecords.size()-1)); } else { mRecords[iter->second].setModified (record); } } template int IdCollection::getSize() const { return mRecords.size(); } template std::string IdCollection::getId (int index) const { return mRecords.at (index).get().mId; } template int IdCollection::getIndex (const std::string& id) const { int index = searchId (id); if (index==-1) throw std::runtime_error ("invalid ID: " + id); return index; } template int IdCollection::getColumns() const { return mColumns.size(); } template QVariant IdCollection::getData (int index, int column) const { return mColumns.at (column)->get (mRecords.at (index)); } template void IdCollection::setData (int index, int column, const QVariant& data) { return mColumns.at (column)->set (mRecords.at (index), data); } template const ColumnBase& IdCollection::getColumn (int column) const { return *mColumns.at (column); } template void IdCollection::addColumn (Column *column) { mColumns.push_back (column); } template void IdCollection::merge() { for (typename std::vector >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter) iter->merge(); purge(); } template void IdCollection::purge() { mRecords.erase (std::remove_if (mRecords.begin(), mRecords.end(), std::mem_fun_ref (&Record::isErased) // I want lambda :( ), mRecords.end()); } template void IdCollection::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 IdCollection::appendBlankRecord (const std::string& id) { ESXRecordT record; record.mId = id; record.blank(); add (record); } template int IdCollection::searchId (const std::string& id) const { std::string id2; std::transform (id.begin(), id.end(), std::back_inserter (id2), (int(*)(int)) std::tolower); std::map::const_iterator iter = mIndex.find (id2); if (iter==mIndex.end()) return -1; return iter->second; } template void IdCollection::replace (int index, const RecordBase& record) { mRecords.at (index) = dynamic_cast&> (record); } template void IdCollection::appendRecord (const RecordBase& record) { mRecords.push_back (dynamic_cast&> (record)); mIndex.insert (std::make_pair (getId (record), mRecords.size()-1)); } template std::string IdCollection::getId (const RecordBase& record) const { const Record& record2 = dynamic_cast&> (record); return (record2.isModified() ? record2.mModified : record2.mBase).mId; } template const RecordBase& IdCollection::getRecord (const std::string& id) const { int index = getIndex (id); return mRecords.at (index); } } #endif