OpenMW
|
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