OpenMW
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
collection.hpp
Go to the documentation of this file.
1 #ifndef CSM_WOLRD_COLLECTION_H
2 #define CSM_WOLRD_COLLECTION_H
3 
4 #include <vector>
5 #include <map>
6 #include <algorithm>
7 #include <cctype>
8 #include <stdexcept>
9 #include <string>
10 #include <functional>
11 
12 #include <QVariant>
13 
15 
16 #include "columnbase.hpp"
17 #include "collectionbase.hpp"
18 #include "land.hpp"
19 #include "landtexture.hpp"
20 
21 namespace CSMWorld
22 {
24  template<typename ESXRecordT>
25  struct IdAccessor
26  {
27  void setId(ESXRecordT& record, const std::string& id) const;
28  const std::string getId (const ESXRecordT& record) const;
29  };
30 
31  template<typename ESXRecordT>
32  void IdAccessor<ESXRecordT>::setId(ESXRecordT& record, const std::string& id) const
33  {
34  record.mId = id;
35  }
36 
37  template<typename ESXRecordT>
38  const std::string IdAccessor<ESXRecordT>::getId (const ESXRecordT& record) const
39  {
40  return record.mId;
41  }
42 
43  template<>
44  inline void IdAccessor<Land>::setId (Land& record, const std::string& id) const
45  {
46  int x=0, y=0;
47 
48  Land::parseUniqueRecordId(id, x, y);
49  record.mX = x;
50  record.mY = y;
51  }
52 
53  template<>
54  inline void IdAccessor<LandTexture>::setId (LandTexture& record, const std::string& id) const
55  {
56  int plugin = 0;
57  int index = 0;
58 
59  LandTexture::parseUniqueRecordId(id, plugin, index);
60  record.mPluginIndex = plugin;
61  record.mIndex = index;
62  }
63 
64  template<>
65  inline const std::string IdAccessor<Land>::getId (const Land& record) const
66  {
67  return Land::createUniqueRecordId(record.mX, record.mY);
68  }
69 
70  template<>
71  inline const std::string IdAccessor<LandTexture>::getId (const LandTexture& record) const
72  {
74  }
75 
77  template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
78  class Collection : public CollectionBase
79  {
80  public:
81 
82  typedef ESXRecordT ESXRecord;
83 
84  private:
85 
86  std::vector<Record<ESXRecordT> > mRecords;
87  std::map<std::string, int> mIndex;
88  std::vector<Column<ESXRecordT> *> mColumns;
89 
90  // not implemented
91  Collection (const Collection&);
93 
94  protected:
95 
96  const std::map<std::string, int>& getIdMap() const;
97 
98  const std::vector<Record<ESXRecordT> >& getRecords() const;
99 
100  bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
105 
106  int cloneRecordImp (const std::string& origin, const std::string& dest,
107  UniversalId::Type type);
109 
110  int touchRecordImp (const std::string& id);
112 
113  public:
114 
115  Collection();
116 
117  virtual ~Collection();
118 
119  void add (const ESXRecordT& record);
121 
122  virtual int getSize() const;
123 
124  virtual std::string getId (int index) const;
125 
126  virtual int getIndex (const std::string& id) const;
127 
128  virtual int getColumns() const;
129 
130  virtual QVariant getData (int index, int column) const;
131 
132  virtual void setData (int index, int column, const QVariant& data);
133 
134  virtual const ColumnBase& getColumn (int column) const;
135 
136  virtual void merge();
138 
139  virtual void purge();
141 
142  virtual void removeRows (int index, int count) ;
143 
144  virtual void appendBlankRecord (const std::string& id,
147 
148  virtual void cloneRecord(const std::string& origin,
149  const std::string& destination,
150  const UniversalId::Type type);
151 
152  virtual bool touchRecord(const std::string& id);
155 
156  virtual int searchId (const std::string& id) const;
159 
160  virtual void replace (int index, const RecordBase& record);
164 
165  virtual void appendRecord (const RecordBase& record,
169 
170  virtual const Record<ESXRecordT>& getRecord (const std::string& id) const;
171 
172  virtual const Record<ESXRecordT>& getRecord (int index) const;
173 
174  virtual int getAppendIndex (const std::string& id,
177 
178  virtual std::vector<std::string> getIds (bool listDeleted = true) const;
182 
183  virtual void insertRecord (const RecordBase& record, int index,
191 
192  virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
197 
198  void addColumn (Column<ESXRecordT> *column);
199 
200  void setRecord (int index, const Record<ESXRecordT>& record);
202 
203  NestableColumn *getNestableColumn (int column) const;
204  };
205 
206  template<typename ESXRecordT, typename IdAccessorT>
207  const std::map<std::string, int>& Collection<ESXRecordT, IdAccessorT>::getIdMap() const
208  {
209  return mIndex;
210  }
211 
212  template<typename ESXRecordT, typename IdAccessorT>
213  const std::vector<Record<ESXRecordT> >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
214  {
215  return mRecords;
216  }
217 
218  template<typename ESXRecordT, typename IdAccessorT>
220  const std::vector<int>& newOrder)
221  {
222  if (!newOrder.empty())
223  {
224  int size = static_cast<int> (newOrder.size());
225 
226  // check that all indices are present
227  std::vector<int> test (newOrder);
228  std::sort (test.begin(), test.end());
229  if (*test.begin()!=0 || *--test.end()!=size-1)
230  return false;
231 
232  // reorder records
233  std::vector<Record<ESXRecordT> > buffer (size);
234 
235  for (int i=0; i<size; ++i)
236  {
237  buffer[newOrder[i]] = mRecords [baseIndex+i];
238  buffer[newOrder[i]].setModified (buffer[newOrder[i]].get());
239  }
240 
241  std::copy (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
242 
243  // adjust index
244  for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
245  ++iter)
246  if (iter->second>=baseIndex && iter->second<baseIndex+size)
247  iter->second = newOrder.at (iter->second-baseIndex)+baseIndex;
248  }
249 
250  return true;
251  }
252 
253  template<typename ESXRecordT, typename IdAccessorT>
255  const std::string& destination, UniversalId::Type type)
256  {
258  copy.mModified = getRecord(origin).get();
260  IdAccessorT().setId(copy.get(), destination);
261 
262  int index = getAppendIndex(destination, type);
263  insertRecord(copy, getAppendIndex(destination, type));
264 
265  return index;
266  }
267 
268  template<typename ESXRecordT, typename IdAccessorT>
270  {
271  int index = getIndex(id);
272  Record<ESXRecordT>& record = mRecords.at(index);
273  if (record.isDeleted())
274  {
275  throw std::runtime_error("attempt to touch deleted record");
276  }
277 
278  if (!record.isModified())
279  {
280  record.setModified(record.get());
281  return index;
282  }
283 
284  return -1;
285  }
286 
287  template<typename ESXRecordT, typename IdAccessorT>
288  void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
289  const std::string& destination, const UniversalId::Type type)
290  {
291  cloneRecordImp(origin, destination, type);
292  }
293 
294  template<>
295  inline void Collection<Land, IdAccessor<Land> >::cloneRecord(const std::string& origin,
296  const std::string& destination, const UniversalId::Type type)
297  {
298  int index = cloneRecordImp(origin, destination, type);
299  mRecords.at(index).get().mPlugin = 0;
300  }
301 
302  template<typename ESXRecordT, typename IdAccessorT>
304  {
305  return touchRecordImp(id) != -1;
306  }
307 
308  template<>
309  inline bool Collection<Land, IdAccessor<Land> >::touchRecord(const std::string& id)
310  {
311  int index = touchRecordImp(id);
312  if (index >= 0)
313  {
314  mRecords.at(index).get().mPlugin = 0;
315  return true;
316  }
317 
318  return false;
319  }
320 
321  template<typename ESXRecordT, typename IdAccessorT>
323  {}
324 
325  template<typename ESXRecordT, typename IdAccessorT>
327  {
328  for (typename std::vector<Column<ESXRecordT> *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter)
329  delete *iter;
330  }
331 
332  template<typename ESXRecordT, typename IdAccessorT>
333  void Collection<ESXRecordT, IdAccessorT>::add (const ESXRecordT& record)
334  {
335  std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record));
336 
337  std::map<std::string, int>::iterator iter = mIndex.find (id);
338 
339  if (iter==mIndex.end())
340  {
341  Record<ESXRecordT> record2;
343  record2.mModified = record;
344 
345  insertRecord (record2, getAppendIndex (id));
346  }
347  else
348  {
349  mRecords[iter->second].setModified (record);
350  }
351  }
352 
353  template<typename ESXRecordT, typename IdAccessorT>
355  {
356  return mRecords.size();
357  }
358 
359  template<typename ESXRecordT, typename IdAccessorT>
360  std::string Collection<ESXRecordT, IdAccessorT>::getId (int index) const
361  {
362  return IdAccessorT().getId (mRecords.at (index).get());
363  }
364 
365  template<typename ESXRecordT, typename IdAccessorT>
366  int Collection<ESXRecordT, IdAccessorT>::getIndex (const std::string& id) const
367  {
368  int index = searchId (id);
369 
370  if (index==-1)
371  throw std::runtime_error ("invalid ID: " + id);
372 
373  return index;
374  }
375 
376  template<typename ESXRecordT, typename IdAccessorT>
378  {
379  return mColumns.size();
380  }
381 
382  template<typename ESXRecordT, typename IdAccessorT>
383  QVariant Collection<ESXRecordT, IdAccessorT>::getData (int index, int column) const
384  {
385  return mColumns.at (column)->get (mRecords.at (index));
386  }
387 
388  template<typename ESXRecordT, typename IdAccessorT>
389  void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data)
390  {
391  return mColumns.at (column)->set (mRecords.at (index), data);
392  }
393 
394  template<typename ESXRecordT, typename IdAccessorT>
396  {
397  return *mColumns.at (column);
398  }
399 
400  template<typename ESXRecordT, typename IdAccessorT>
402  {
403  if (column < 0 || column >= static_cast<int>(mColumns.size()))
404  throw std::runtime_error("column index out of range");
405 
406  return mColumns.at (column);
407  }
408 
409  template<typename ESXRecordT, typename IdAccessorT>
411  {
412  mColumns.push_back (column);
413  }
414 
415  template<typename ESXRecordT, typename IdAccessorT>
417  {
418  for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
419  iter->merge();
420 
421  purge();
422  }
423 
424  template<typename ESXRecordT, typename IdAccessorT>
426  {
427  int i = 0;
428 
429  while (i<static_cast<int> (mRecords.size()))
430  {
431  if (mRecords[i].isErased())
432  removeRows (i, 1);
433  else
434  ++i;
435  }
436  }
437 
438  template<typename ESXRecordT, typename IdAccessorT>
440  {
441  mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count);
442 
443  typename std::map<std::string, int>::iterator iter = mIndex.begin();
444 
445  while (iter!=mIndex.end())
446  {
447  if (iter->second>=index)
448  {
449  if (iter->second>=index+count)
450  {
451  iter->second -= count;
452  ++iter;
453  }
454  else
455  {
456  mIndex.erase (iter++);
457  }
458  }
459  else
460  ++iter;
461  }
462  }
463 
464  template<typename ESXRecordT, typename IdAccessorT>
466  UniversalId::Type type)
467  {
468  ESXRecordT record;
469  IdAccessorT().setId(record, id);
470  record.blank();
471 
472  Record<ESXRecordT> record2;
474  record2.mModified = record;
475 
476  insertRecord (record2, getAppendIndex (id, type), type);
477  }
478 
479  template<typename ESXRecordT, typename IdAccessorT>
480  int Collection<ESXRecordT, IdAccessorT>::searchId (const std::string& id) const
481  {
482  std::string id2 = Misc::StringUtils::lowerCase(id);
483 
484  std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
485 
486  if (iter==mIndex.end())
487  return -1;
488 
489  return iter->second;
490  }
491 
492  template<typename ESXRecordT, typename IdAccessorT>
494  {
495  mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
496  }
497 
498  template<typename ESXRecordT, typename IdAccessorT>
500  UniversalId::Type type)
501  {
502  insertRecord (record,
503  getAppendIndex (IdAccessorT().getId (
504  dynamic_cast<const Record<ESXRecordT>&> (record).get()), type), type);
505  }
506 
507  template<typename ESXRecordT, typename IdAccessorT>
509  UniversalId::Type type) const
510  {
511  return static_cast<int> (mRecords.size());
512  }
513 
514  template<typename ESXRecordT, typename IdAccessorT>
515  std::vector<std::string> Collection<ESXRecordT, IdAccessorT>::getIds (bool listDeleted) const
516  {
517  std::vector<std::string> ids;
518 
519  for (typename std::map<std::string, int>::const_iterator iter = mIndex.begin();
520  iter!=mIndex.end(); ++iter)
521  {
522  if (listDeleted || !mRecords[iter->second].isDeleted())
523  ids.push_back (IdAccessorT().getId (mRecords[iter->second].get()));
524  }
525 
526  return ids;
527  }
528 
529  template<typename ESXRecordT, typename IdAccessorT>
531  {
532  int index = getIndex (id);
533  return mRecords.at (index);
534  }
535 
536  template<typename ESXRecordT, typename IdAccessorT>
538  {
539  return mRecords.at (index);
540  }
541 
542  template<typename ESXRecordT, typename IdAccessorT>
544  UniversalId::Type type)
545  {
546  if (index<0 || index>static_cast<int> (mRecords.size()))
547  throw std::runtime_error ("index out of range");
548 
549  const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
550 
551  mRecords.insert (mRecords.begin()+index, record2);
552 
553  if (index<static_cast<int> (mRecords.size())-1)
554  {
555  for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
556  ++iter)
557  if (iter->second>=index)
558  ++(iter->second);
559  }
560 
561  mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
562  record2.get())), index));
563  }
564 
565  template<typename ESXRecordT, typename IdAccessorT>
567  {
568  if (Misc::StringUtils::lowerCase (IdAccessorT().getId (mRecords.at (index).get()))!=
569  Misc::StringUtils::lowerCase (IdAccessorT().getId (record.get())))
570  throw std::runtime_error ("attempt to change the ID of a record");
571 
572  mRecords.at (index) = record;
573  }
574 
575  template<typename ESXRecordT, typename IdAccessorT>
576  bool Collection<ESXRecordT, IdAccessorT>::reorderRows (int baseIndex, const std::vector<int>& newOrder)
577  {
578  return false;
579  }
580 }
581 
582 #endif
virtual bool reorderRows(int baseIndex, const std::vector< int > &newOrder)
Definition: collection.hpp:576
virtual std::string getId(int index) const
Definition: collection.hpp:360
void copy(const btTransform &src, Nif::Transformation &dst)
Definition: testbulletnifloader.cpp:269
virtual void appendBlankRecord(const std::string &id, UniversalId::Type type=UniversalId::Type_None)
Definition: collection.hpp:465
Collection & operator=(const Collection &)
int getId(const std::string &name)
Will return -1 for an invalid name.
Definition: columns.cpp:384
State mState
Definition: record.hpp:19
Collection()
Definition: collection.hpp:322
const std::vector< Record< ESXRecordT > > & getRecords() const
Definition: collection.hpp:213
static void parseUniqueRecordId(const std::string &id, int &x, int &y)
Definition: land.cpp:20
Definition: columnbase.hpp:172
Wrapper for LandTexture record, providing info which plugin the LandTexture was loaded from...
Definition: landtexture.hpp:11
int cloneRecordImp(const std::string &origin, const std::string &dest, UniversalId::Type type)
Returns the index of the clone.
Definition: collection.hpp:254
static std::string lowerCase(const std::string &in)
Returns lower case copy of input string.
Definition: stringops.hpp:177
Type
Definition: universalid.hpp:40
Wrapper for Land record. Encodes X and Y cell index in the ID.
Definition: land.hpp:13
bool reorderRowsImp(int baseIndex, const std::vector< int > &newOrder)
Definition: collection.hpp:219
void addColumn(Column< ESXRecordT > *column)
Definition: collection.hpp:410
std::vector< Record< ESXRecordT > > mRecords
Definition: collection.hpp:86
Single-type record collection.
Definition: collection.hpp:78
virtual int searchId(const std::string &id) const
Definition: collection.hpp:480
virtual const Record< ESXRecordT > & getRecord(const std::string &id) const
Definition: collection.hpp:530
const std::map< std::string, int > & getIdMap() const
Definition: collection.hpp:207
virtual int getIndex(const std::string &id) const
Definition: collection.hpp:366
int mIndex
Definition: loadltex.hpp:36
virtual ~Collection()
Definition: collection.hpp:326
const std::string getId(const ESXRecordT &record) const
Definition: collection.hpp:38
virtual int getAppendIndex(const std::string &id, UniversalId::Type type=UniversalId::Type_None) const
Definition: collection.hpp:508
virtual int getColumns() const
Definition: collection.hpp:377
MWWorld::Ptr searchId(MWWorld::CellRefList< T > &list, const std::string &id, MWWorld::ContainerStore *store)
Definition: containerstore.cpp:43
int mX
Definition: loadland.hpp:31
virtual void replace(int index, const RecordBase &record)
Definition: collection.hpp:493
Definition: nestedcolumnadapter.hpp:11
std::map< std::string, int > mIndex
Definition: collection.hpp:87
Definition: columnbase.hpp:190
static void parseUniqueRecordId(const std::string &id, int &plugin, int &index)
Deconstructs a unique string identifier into plugin and index.
Definition: landtexture.cpp:24
void setRecord(int index, const Record< ESXRecordT > &record)
Definition: collection.hpp:566
int mY
Definition: loadland.hpp:31
virtual void insertRecord(const RecordBase &record, int index, UniversalId::Type type=UniversalId::Type_None)
Definition: collection.hpp:543
static std::string createUniqueRecordId(int plugin, int index)
Returns a string identifier that will be unique to any LandTexture.
Definition: landtexture.cpp:17
virtual const ColumnBase & getColumn(int column) const
Definition: collection.hpp:395
virtual void purge()
Remove records that are flagged as erased.
Definition: collection.hpp:425
ESXRecordT mModified
Definition: record.hpp:41
void add(const ESXRecordT &record)
Add a new record (modified)
Definition: collection.hpp:333
virtual void setData(int index, int column, const QVariant &data)
Definition: collection.hpp:389
virtual void removeRows(int index, int count)
< Merge modified into base.
Definition: collection.hpp:439
virtual void merge()
Merge modified into base.
Definition: collection.hpp:416
const ESXRecordT & get() const
Throws an exception, if the record is deleted.
Definition: record.hpp:106
virtual bool touchRecord(const std::string &id)
Definition: collection.hpp:303
int touchRecordImp(const std::string &id)
Returns the index of the record on success, -1 on failure.
Definition: collection.hpp:269
static std::string createUniqueRecordId(int x, int y)
Definition: land.cpp:13
Definition: columnbase.hpp:15
Base class for record collections.
Definition: collectionbase.hpp:23
void setId(ESXRecordT &record, const std::string &id) const
Definition: collection.hpp:32
virtual int getSize() const
Definition: collection.hpp:354
void setModified(const ESXRecordT &modified)
Throws an exception, if the record is deleted.
Definition: record.hpp:133
Definition: record.hpp:8
void test(const MWWorld::Ptr &actor, int &compiled, int &total, const Compiler::Extensions *extensions, int warningsMode)
Definition: scripttest.cpp:26
virtual void cloneRecord(const std::string &origin, const std::string &destination, const UniversalId::Type type)
Definition: collection.hpp:288
virtual std::vector< std::string > getIds(bool listDeleted=true) const
Definition: collection.hpp:515
Access to ID field in records.
Definition: collection.hpp:25
NestableColumn * getNestableColumn(int column) const
Definition: collection.hpp:401
Definition: universalid.hpp:42
ESXRecordT ESXRecord
Definition: collection.hpp:82
virtual QVariant getData(int index, int column) const
Definition: collection.hpp:383
std::vector< Column< ESXRecordT > * > mColumns
Definition: collection.hpp:88
virtual void appendRecord(const RecordBase &record, UniversalId::Type type=UniversalId::Type_None)
Definition: collection.hpp:499
bool isModified() const
Definition: record.cpp:17
bool isDeleted() const
Definition: record.cpp:5
int mPluginIndex
Definition: landtexture.hpp:13