OpenMW
apps/opencs/model/world/collection.hpp
Go to the documentation of this file.
00001 #ifndef CSM_WOLRD_COLLECTION_H
00002 #define CSM_WOLRD_COLLECTION_H
00003 
00004 #include <vector>
00005 #include <map>
00006 #include <algorithm>
00007 #include <cctype>
00008 #include <stdexcept>
00009 #include <functional>
00010 
00011 #include <QVariant>
00012 
00013 #include <components/misc/stringops.hpp>
00014 
00015 #include "columnbase.hpp"
00016 
00017 #include "collectionbase.hpp"
00018 
00019 namespace CSMWorld
00020 {
00022     template<typename ESXRecordT>
00023     struct IdAccessor
00024     {
00025         std::string& getId (ESXRecordT& record);
00026 
00027         const std::string getId (const ESXRecordT& record) const;
00028     };
00029 
00030     template<typename ESXRecordT>
00031     std::string& IdAccessor<ESXRecordT>::getId (ESXRecordT& record)
00032     {
00033         return record.mId;
00034     }
00035 
00036     template<typename ESXRecordT>
00037     const std::string IdAccessor<ESXRecordT>::getId (const ESXRecordT& record) const
00038     {
00039         return record.mId;
00040     }
00041 
00043     template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
00044     class Collection : public CollectionBase
00045     {
00046             std::vector<Record<ESXRecordT> > mRecords;
00047             std::map<std::string, int> mIndex;
00048             std::vector<Column<ESXRecordT> *> mColumns;
00049 
00050             // not implemented
00051             Collection (const Collection&);
00052             Collection& operator= (const Collection&);
00053 
00054         protected:
00055 
00056             const std::map<std::string, int>& getIdMap() const;
00057 
00058             const std::vector<Record<ESXRecordT> >& getRecords() const;
00059 
00060             bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
00065 
00066         public:
00067 
00068             Collection();
00069 
00070             virtual ~Collection();
00071 
00072             void add (const ESXRecordT& record);
00074 
00075             virtual int getSize() const;
00076 
00077             virtual std::string getId (int index) const;
00078 
00079             virtual int getIndex (const std::string& id) const;
00080 
00081             virtual int getColumns() const;
00082 
00083             virtual QVariant getData (int index, int column) const;
00084 
00085             virtual void setData (int index, int column, const QVariant& data);
00086 
00087             virtual const ColumnBase& getColumn (int column) const;
00088 
00089             virtual void merge();
00091 
00092             virtual void purge();
00094 
00095             virtual void removeRows (int index, int count) ;
00096 
00097             virtual void appendBlankRecord (const std::string& id,
00098                 UniversalId::Type type = UniversalId::Type_None);
00100 
00101             virtual int searchId (const std::string& id) const;
00104 
00105             virtual void replace (int index, const RecordBase& record);
00109 
00110             virtual void appendRecord (const RecordBase& record,
00111                 UniversalId::Type type = UniversalId::Type_None);
00114 
00115             virtual const Record<ESXRecordT>& getRecord (const std::string& id) const;
00116 
00117             virtual const Record<ESXRecordT>& getRecord (int index) const;
00118 
00119             virtual int getAppendIndex (const std::string& id,
00120                 UniversalId::Type type = UniversalId::Type_None) const;
00122 
00123             virtual std::vector<std::string> getIds (bool listDeleted = true) const;
00127 
00128             virtual void insertRecord (const RecordBase& record, int index,
00129                 UniversalId::Type type = UniversalId::Type_None);
00136 
00137             virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
00142 
00143             void addColumn (Column<ESXRecordT> *column);
00144 
00145             void setRecord (int index, const Record<ESXRecordT>& record);
00147     };
00148 
00149     template<typename ESXRecordT, typename IdAccessorT>
00150     const std::map<std::string, int>& Collection<ESXRecordT, IdAccessorT>::getIdMap() const
00151     {
00152         return mIndex;
00153     }
00154 
00155     template<typename ESXRecordT, typename IdAccessorT>
00156     const std::vector<Record<ESXRecordT> >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
00157     {
00158         return mRecords;
00159     }
00160 
00161     template<typename ESXRecordT, typename IdAccessorT>
00162     bool Collection<ESXRecordT, IdAccessorT>::reorderRowsImp (int baseIndex,
00163         const std::vector<int>& newOrder)
00164     {
00165         if (!newOrder.empty())
00166         {
00167             int size = static_cast<int> (newOrder.size());
00168 
00169             // check that all indices are present
00170             std::vector<int> test (newOrder);
00171             std::sort (test.begin(), test.end());
00172             if (*test.begin()!=0 || *--test.end()!=size-1)
00173                 return false;
00174 
00175             // reorder records
00176             std::vector<Record<ESXRecordT> > buffer (size);
00177 
00178             for (int i=0; i<size; ++i)
00179             {
00180                 buffer[newOrder[i]] = mRecords [baseIndex+i];
00181                 buffer[newOrder[i]].setModified (buffer[newOrder[i]].get());
00182             }
00183 
00184             std::copy (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
00185 
00186             // adjust index
00187             for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
00188                  ++iter)
00189                 if (iter->second>=baseIndex && iter->second<baseIndex+size)
00190                     iter->second = newOrder.at (iter->second-baseIndex)+baseIndex;
00191         }
00192 
00193         return true;
00194     }
00195 
00196     template<typename ESXRecordT, typename IdAccessorT>
00197     Collection<ESXRecordT, IdAccessorT>::Collection()
00198     {}
00199 
00200     template<typename ESXRecordT, typename IdAccessorT>
00201     Collection<ESXRecordT, IdAccessorT>::~Collection()
00202     {
00203         for (typename std::vector<Column<ESXRecordT> *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter)
00204             delete *iter;
00205     }
00206 
00207     template<typename ESXRecordT, typename IdAccessorT>
00208     void Collection<ESXRecordT, IdAccessorT>::add (const ESXRecordT& record)
00209     {
00210         std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record));
00211 
00212         std::map<std::string, int>::iterator iter = mIndex.find (id);
00213 
00214         if (iter==mIndex.end())
00215         {
00216             Record<ESXRecordT> record2;
00217             record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
00218             record2.mModified = record;
00219 
00220             insertRecord (record2, getAppendIndex (id));
00221         }
00222         else
00223         {
00224             mRecords[iter->second].setModified (record);
00225         }
00226     }
00227 
00228     template<typename ESXRecordT, typename IdAccessorT>
00229     int Collection<ESXRecordT, IdAccessorT>::getSize() const
00230     {
00231         return mRecords.size();
00232     }
00233 
00234     template<typename ESXRecordT, typename IdAccessorT>
00235     std::string Collection<ESXRecordT, IdAccessorT>::getId (int index) const
00236     {
00237         return IdAccessorT().getId (mRecords.at (index).get());
00238     }
00239 
00240     template<typename ESXRecordT, typename IdAccessorT>
00241     int  Collection<ESXRecordT, IdAccessorT>::getIndex (const std::string& id) const
00242     {
00243         int index = searchId (id);
00244 
00245         if (index==-1)
00246             throw std::runtime_error ("invalid ID: " + id);
00247 
00248         return index;
00249     }
00250 
00251     template<typename ESXRecordT, typename IdAccessorT>
00252     int Collection<ESXRecordT, IdAccessorT>::getColumns() const
00253     {
00254         return mColumns.size();
00255     }
00256 
00257     template<typename ESXRecordT, typename IdAccessorT>
00258     QVariant Collection<ESXRecordT, IdAccessorT>::getData (int index, int column) const
00259     {
00260         return mColumns.at (column)->get (mRecords.at (index));
00261     }
00262 
00263     template<typename ESXRecordT, typename IdAccessorT>
00264     void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data)
00265     {
00266         return mColumns.at (column)->set (mRecords.at (index), data);
00267     }
00268 
00269     template<typename ESXRecordT, typename IdAccessorT>
00270     const ColumnBase& Collection<ESXRecordT, IdAccessorT>::getColumn (int column) const
00271     {
00272         return *mColumns.at (column);
00273     }
00274 
00275     template<typename ESXRecordT, typename IdAccessorT>
00276     void Collection<ESXRecordT, IdAccessorT>::addColumn (Column<ESXRecordT> *column)
00277     {
00278         mColumns.push_back (column);
00279     }
00280 
00281     template<typename ESXRecordT, typename IdAccessorT>
00282     void Collection<ESXRecordT, IdAccessorT>::merge()
00283     {
00284         for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
00285             iter->merge();
00286 
00287         purge();
00288     }
00289 
00290     template<typename ESXRecordT, typename IdAccessorT>
00291     void  Collection<ESXRecordT, IdAccessorT>::purge()
00292     {
00293         int i = 0;
00294 
00295         while (i<static_cast<int> (mRecords.size()))
00296         {
00297             if (mRecords[i].isErased())
00298                 removeRows (i, 1);
00299             else
00300                 ++i;
00301         }
00302     }
00303 
00304     template<typename ESXRecordT, typename IdAccessorT>
00305     void Collection<ESXRecordT, IdAccessorT>::removeRows (int index, int count)
00306     {
00307         mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count);
00308 
00309         typename std::map<std::string, int>::iterator iter = mIndex.begin();
00310 
00311         while (iter!=mIndex.end())
00312         {
00313             if (iter->second>=index)
00314             {
00315                 if (iter->second>=index+count)
00316                 {
00317                     iter->second -= count;
00318                     ++iter;
00319                 }
00320                 else
00321                 {
00322                     mIndex.erase (iter++);
00323                 }
00324             }
00325             else
00326                 ++iter;
00327         }
00328     }
00329 
00330     template<typename ESXRecordT, typename IdAccessorT>
00331     void  Collection<ESXRecordT, IdAccessorT>::appendBlankRecord (const std::string& id,
00332         UniversalId::Type type)
00333     {
00334         ESXRecordT record;
00335         IdAccessorT().getId (record) = id;
00336         record.blank();
00337 
00338         Record<ESXRecordT> record2;
00339         record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
00340         record2.mModified = record;
00341 
00342         insertRecord (record2, getAppendIndex (id, type), type);
00343     }
00344 
00345     template<typename ESXRecordT, typename IdAccessorT>
00346     int Collection<ESXRecordT, IdAccessorT>::searchId (const std::string& id) const
00347     {
00348         std::string id2 = Misc::StringUtils::lowerCase(id);
00349 
00350         std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
00351 
00352         if (iter==mIndex.end())
00353             return -1;
00354 
00355         return iter->second;
00356     }
00357 
00358     template<typename ESXRecordT, typename IdAccessorT>
00359     void Collection<ESXRecordT, IdAccessorT>::replace (int index, const RecordBase& record)
00360     {
00361         mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
00362     }
00363 
00364     template<typename ESXRecordT, typename IdAccessorT>
00365     void Collection<ESXRecordT, IdAccessorT>::appendRecord (const RecordBase& record,
00366         UniversalId::Type type)
00367     {
00368         insertRecord (record,
00369             getAppendIndex (IdAccessorT().getId (
00370             dynamic_cast<const Record<ESXRecordT>&> (record).get()), type), type);
00371     }
00372 
00373     template<typename ESXRecordT, typename IdAccessorT>
00374     int Collection<ESXRecordT, IdAccessorT>::getAppendIndex (const std::string& id,
00375         UniversalId::Type type) const
00376     {
00377         return static_cast<int> (mRecords.size());
00378     }
00379 
00380     template<typename ESXRecordT, typename IdAccessorT>
00381     std::vector<std::string> Collection<ESXRecordT, IdAccessorT>::getIds (bool listDeleted) const
00382     {
00383         std::vector<std::string> ids;
00384 
00385         for (typename std::map<std::string, int>::const_iterator iter = mIndex.begin();
00386             iter!=mIndex.end(); ++iter)
00387         {
00388             if (listDeleted || !mRecords[iter->second].isDeleted())
00389                 ids.push_back (IdAccessorT().getId (mRecords[iter->second].get()));
00390         }
00391 
00392         return ids;
00393     }
00394 
00395     template<typename ESXRecordT, typename IdAccessorT>
00396     const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (const std::string& id) const
00397     {
00398         int index = getIndex (id);
00399         return mRecords.at (index);
00400     }
00401 
00402     template<typename ESXRecordT, typename IdAccessorT>
00403     const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (int index) const
00404     {
00405         return mRecords.at (index);
00406     }
00407 
00408     template<typename ESXRecordT, typename IdAccessorT>
00409     void Collection<ESXRecordT, IdAccessorT>::insertRecord (const RecordBase& record, int index,
00410         UniversalId::Type type)
00411     {
00412         if (index<0 || index>static_cast<int> (mRecords.size()))
00413             throw std::runtime_error ("index out of range");
00414 
00415         const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
00416 
00417         mRecords.insert (mRecords.begin()+index, record2);
00418 
00419         if (index<static_cast<int> (mRecords.size())-1)
00420         {
00421             for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
00422                 ++iter)
00423                  if (iter->second>=index)
00424                      ++(iter->second);
00425         }
00426 
00427         mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
00428             record2.get())), index));
00429     }
00430 
00431     template<typename ESXRecordT, typename IdAccessorT>
00432     void Collection<ESXRecordT, IdAccessorT>::setRecord (int index, const Record<ESXRecordT>& record)
00433     {
00434         if (IdAccessorT().getId (mRecords.at (index).get())!=IdAccessorT().getId (record.get()))
00435             throw std::runtime_error ("attempt to change the ID of a record");
00436 
00437         mRecords.at (index) = record;
00438     }
00439 
00440     template<typename ESXRecordT, typename IdAccessorT>
00441     bool Collection<ESXRecordT, IdAccessorT>::reorderRows (int baseIndex, const std::vector<int>& newOrder)
00442     {
00443         return false;
00444     }
00445 }
00446 
00447 #endif