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 <functional>
10 
11 #include <QVariant>
12 
14 
15 #include "columnbase.hpp"
16 
17 #include "collectionbase.hpp"
18 
19 namespace CSMWorld
20 {
22  template<typename ESXRecordT>
23  struct IdAccessor
24  {
25  std::string& getId (ESXRecordT& record);
26 
27  const std::string getId (const ESXRecordT& record) const;
28  };
29 
30  template<typename ESXRecordT>
31  std::string& IdAccessor<ESXRecordT>::getId (ESXRecordT& record)
32  {
33  return record.mId;
34  }
35 
36  template<typename ESXRecordT>
37  const std::string IdAccessor<ESXRecordT>::getId (const ESXRecordT& record) const
38  {
39  return record.mId;
40  }
41 
43  template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
44  class Collection : public CollectionBase
45  {
46  public:
47 
48  typedef ESXRecordT ESXRecord;
49 
50  private:
51 
52  std::vector<Record<ESXRecordT> > mRecords;
53  std::map<std::string, int> mIndex;
54  std::vector<Column<ESXRecordT> *> mColumns;
55 
56  // not implemented
57  Collection (const Collection&);
59 
60  protected:
61 
62  const std::map<std::string, int>& getIdMap() const;
63 
64  const std::vector<Record<ESXRecordT> >& getRecords() const;
65 
66  bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
71 
72  public:
73 
74  Collection();
75 
76  virtual ~Collection();
77 
78  void add (const ESXRecordT& record);
80 
81  virtual int getSize() const;
82 
83  virtual std::string getId (int index) const;
84 
85  virtual int getIndex (const std::string& id) const;
86 
87  virtual int getColumns() const;
88 
89  virtual QVariant getData (int index, int column) const;
90 
91  virtual void setData (int index, int column, const QVariant& data);
92 
93  virtual const ColumnBase& getColumn (int column) const;
94 
95  virtual void merge();
97 
98  virtual void purge();
100 
101  virtual void removeRows (int index, int count) ;
102 
103  virtual void appendBlankRecord (const std::string& id,
106 
107  virtual void cloneRecord(const std::string& origin,
108  const std::string& destination,
109  const UniversalId::Type type);
110 
111  virtual int searchId (const std::string& id) const;
114 
115  virtual void replace (int index, const RecordBase& record);
119 
120  virtual void appendRecord (const RecordBase& record,
124 
125  virtual const Record<ESXRecordT>& getRecord (const std::string& id) const;
126 
127  virtual const Record<ESXRecordT>& getRecord (int index) const;
128 
129  virtual int getAppendIndex (const std::string& id,
132 
133  virtual std::vector<std::string> getIds (bool listDeleted = true) const;
137 
138  virtual void insertRecord (const RecordBase& record, int index,
146 
147  virtual bool reorderRows (int baseIndex, const std::vector<int>& newOrder);
152 
153  void addColumn (Column<ESXRecordT> *column);
154 
155  void setRecord (int index, const Record<ESXRecordT>& record);
157 
158  NestableColumn *getNestableColumn (int column) const;
159  };
160 
161  template<typename ESXRecordT, typename IdAccessorT>
162  const std::map<std::string, int>& Collection<ESXRecordT, IdAccessorT>::getIdMap() const
163  {
164  return mIndex;
165  }
166 
167  template<typename ESXRecordT, typename IdAccessorT>
168  const std::vector<Record<ESXRecordT> >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
169  {
170  return mRecords;
171  }
172 
173  template<typename ESXRecordT, typename IdAccessorT>
175  const std::vector<int>& newOrder)
176  {
177  if (!newOrder.empty())
178  {
179  int size = static_cast<int> (newOrder.size());
180 
181  // check that all indices are present
182  std::vector<int> test (newOrder);
183  std::sort (test.begin(), test.end());
184  if (*test.begin()!=0 || *--test.end()!=size-1)
185  return false;
186 
187  // reorder records
188  std::vector<Record<ESXRecordT> > buffer (size);
189 
190  for (int i=0; i<size; ++i)
191  {
192  buffer[newOrder[i]] = mRecords [baseIndex+i];
193  buffer[newOrder[i]].setModified (buffer[newOrder[i]].get());
194  }
195 
196  std::copy (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
197 
198  // adjust index
199  for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
200  ++iter)
201  if (iter->second>=baseIndex && iter->second<baseIndex+size)
202  iter->second = newOrder.at (iter->second-baseIndex)+baseIndex;
203  }
204 
205  return true;
206  }
207 
208  template<typename ESXRecordT, typename IdAccessorT>
209  void Collection<ESXRecordT, IdAccessorT>::cloneRecord(const std::string& origin,
210  const std::string& destination,
211  const UniversalId::Type type)
212  {
213  Record<ESXRecordT> copy;
214  copy.mModified = getRecord(origin).get();
216  copy.get().mId = destination;
217 
218  insertRecord(copy, getAppendIndex(destination, type));
219  }
220 
221  template<typename ESXRecordT, typename IdAccessorT>
223  {}
224 
225  template<typename ESXRecordT, typename IdAccessorT>
227  {
228  for (typename std::vector<Column<ESXRecordT> *>::iterator iter (mColumns.begin()); iter!=mColumns.end(); ++iter)
229  delete *iter;
230  }
231 
232  template<typename ESXRecordT, typename IdAccessorT>
233  void Collection<ESXRecordT, IdAccessorT>::add (const ESXRecordT& record)
234  {
235  std::string id = Misc::StringUtils::lowerCase (IdAccessorT().getId (record));
236 
237  std::map<std::string, int>::iterator iter = mIndex.find (id);
238 
239  if (iter==mIndex.end())
240  {
241  Record<ESXRecordT> record2;
243  record2.mModified = record;
244 
245  insertRecord (record2, getAppendIndex (id));
246  }
247  else
248  {
249  mRecords[iter->second].setModified (record);
250  }
251  }
252 
253  template<typename ESXRecordT, typename IdAccessorT>
255  {
256  return mRecords.size();
257  }
258 
259  template<typename ESXRecordT, typename IdAccessorT>
260  std::string Collection<ESXRecordT, IdAccessorT>::getId (int index) const
261  {
262  return IdAccessorT().getId (mRecords.at (index).get());
263  }
264 
265  template<typename ESXRecordT, typename IdAccessorT>
266  int Collection<ESXRecordT, IdAccessorT>::getIndex (const std::string& id) const
267  {
268  int index = searchId (id);
269 
270  if (index==-1)
271  throw std::runtime_error ("invalid ID: " + id);
272 
273  return index;
274  }
275 
276  template<typename ESXRecordT, typename IdAccessorT>
278  {
279  return mColumns.size();
280  }
281 
282  template<typename ESXRecordT, typename IdAccessorT>
283  QVariant Collection<ESXRecordT, IdAccessorT>::getData (int index, int column) const
284  {
285  return mColumns.at (column)->get (mRecords.at (index));
286  }
287 
288  template<typename ESXRecordT, typename IdAccessorT>
289  void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data)
290  {
291  return mColumns.at (column)->set (mRecords.at (index), data);
292  }
293 
294  template<typename ESXRecordT, typename IdAccessorT>
296  {
297  return *mColumns.at (column);
298  }
299 
300  template<typename ESXRecordT, typename IdAccessorT>
302  {
303  if (column < 0 || column >= static_cast<int>(mColumns.size()))
304  throw std::runtime_error("column index out of range");
305 
306  return mColumns.at (column);
307  }
308 
309  template<typename ESXRecordT, typename IdAccessorT>
311  {
312  mColumns.push_back (column);
313  }
314 
315  template<typename ESXRecordT, typename IdAccessorT>
317  {
318  for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
319  iter->merge();
320 
321  purge();
322  }
323 
324  template<typename ESXRecordT, typename IdAccessorT>
326  {
327  int i = 0;
328 
329  while (i<static_cast<int> (mRecords.size()))
330  {
331  if (mRecords[i].isErased())
332  removeRows (i, 1);
333  else
334  ++i;
335  }
336  }
337 
338  template<typename ESXRecordT, typename IdAccessorT>
340  {
341  mRecords.erase (mRecords.begin()+index, mRecords.begin()+index+count);
342 
343  typename std::map<std::string, int>::iterator iter = mIndex.begin();
344 
345  while (iter!=mIndex.end())
346  {
347  if (iter->second>=index)
348  {
349  if (iter->second>=index+count)
350  {
351  iter->second -= count;
352  ++iter;
353  }
354  else
355  {
356  mIndex.erase (iter++);
357  }
358  }
359  else
360  ++iter;
361  }
362  }
363 
364  template<typename ESXRecordT, typename IdAccessorT>
366  UniversalId::Type type)
367  {
368  ESXRecordT record;
369  IdAccessorT().getId (record) = id;
370  record.blank();
371 
372  Record<ESXRecordT> record2;
374  record2.mModified = record;
375 
376  insertRecord (record2, getAppendIndex (id, type), type);
377  }
378 
379  template<typename ESXRecordT, typename IdAccessorT>
380  int Collection<ESXRecordT, IdAccessorT>::searchId (const std::string& id) const
381  {
382  std::string id2 = Misc::StringUtils::lowerCase(id);
383 
384  std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
385 
386  if (iter==mIndex.end())
387  return -1;
388 
389  return iter->second;
390  }
391 
392  template<typename ESXRecordT, typename IdAccessorT>
394  {
395  mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
396  }
397 
398  template<typename ESXRecordT, typename IdAccessorT>
400  UniversalId::Type type)
401  {
402  insertRecord (record,
403  getAppendIndex (IdAccessorT().getId (
404  dynamic_cast<const Record<ESXRecordT>&> (record).get()), type), type);
405  }
406 
407  template<typename ESXRecordT, typename IdAccessorT>
409  UniversalId::Type type) const
410  {
411  return static_cast<int> (mRecords.size());
412  }
413 
414  template<typename ESXRecordT, typename IdAccessorT>
415  std::vector<std::string> Collection<ESXRecordT, IdAccessorT>::getIds (bool listDeleted) const
416  {
417  std::vector<std::string> ids;
418 
419  for (typename std::map<std::string, int>::const_iterator iter = mIndex.begin();
420  iter!=mIndex.end(); ++iter)
421  {
422  if (listDeleted || !mRecords[iter->second].isDeleted())
423  ids.push_back (IdAccessorT().getId (mRecords[iter->second].get()));
424  }
425 
426  return ids;
427  }
428 
429  template<typename ESXRecordT, typename IdAccessorT>
431  {
432  int index = getIndex (id);
433  return mRecords.at (index);
434  }
435 
436  template<typename ESXRecordT, typename IdAccessorT>
438  {
439  return mRecords.at (index);
440  }
441 
442  template<typename ESXRecordT, typename IdAccessorT>
444  UniversalId::Type type)
445  {
446  if (index<0 || index>static_cast<int> (mRecords.size()))
447  throw std::runtime_error ("index out of range");
448 
449  const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
450 
451  mRecords.insert (mRecords.begin()+index, record2);
452 
453  if (index<static_cast<int> (mRecords.size())-1)
454  {
455  for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
456  ++iter)
457  if (iter->second>=index)
458  ++(iter->second);
459  }
460 
461  mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
462  record2.get())), index));
463  }
464 
465  template<typename ESXRecordT, typename IdAccessorT>
467  {
468  if (Misc::StringUtils::lowerCase (IdAccessorT().getId (mRecords.at (index).get()))!=
469  Misc::StringUtils::lowerCase (IdAccessorT().getId (record.get())))
470  throw std::runtime_error ("attempt to change the ID of a record");
471 
472  mRecords.at (index) = record;
473  }
474 
475  template<typename ESXRecordT, typename IdAccessorT>
476  bool Collection<ESXRecordT, IdAccessorT>::reorderRows (int baseIndex, const std::vector<int>& newOrder)
477  {
478  return false;
479  }
480 }
481 
482 #endif
virtual bool reorderRows(int baseIndex, const std::vector< int > &newOrder)
Definition: collection.hpp:476
virtual std::string getId(int index) const
Definition: collection.hpp:260
virtual void appendBlankRecord(const std::string &id, UniversalId::Type type=UniversalId::Type_None)
Definition: collection.hpp:365
Collection & operator=(const Collection &)
int getId(const std::string &name)
Will return -1 for an invalid name.
Definition: columns.cpp:377
State mState
Definition: record.hpp:19
Collection()
Definition: collection.hpp:222
const std::vector< Record< ESXRecordT > > & getRecords() const
Definition: collection.hpp:168
Definition: columnbase.hpp:167
static std::string lowerCase(const std::string &in)
Returns lower case copy of input string.
Definition: stringops.hpp:103
Type
Definition: universalid.hpp:40
bool reorderRowsImp(int baseIndex, const std::vector< int > &newOrder)
Definition: collection.hpp:174
void addColumn(Column< ESXRecordT > *column)
Definition: collection.hpp:310
std::vector< Record< ESXRecordT > > mRecords
Definition: collection.hpp:52
Single-type record collection.
Definition: collection.hpp:44
virtual int searchId(const std::string &id) const
Definition: collection.hpp:380
virtual const Record< ESXRecordT > & getRecord(const std::string &id) const
Definition: collection.hpp:430
const std::map< std::string, int > & getIdMap() const
Definition: collection.hpp:162
virtual int getIndex(const std::string &id) const
Definition: collection.hpp:266
virtual ~Collection()
Definition: collection.hpp:226
std::string & getId(ESXRecordT &record)
Definition: collection.hpp:31
virtual int getAppendIndex(const std::string &id, UniversalId::Type type=UniversalId::Type_None) const
Definition: collection.hpp:408
virtual int getColumns() const
Definition: collection.hpp:277
MWWorld::Ptr searchId(MWWorld::CellRefList< T > &list, const std::string &id, MWWorld::ContainerStore *store)
Definition: containerstore.cpp:42
virtual void replace(int index, const RecordBase &record)
Definition: collection.hpp:393
Definition: nestedcolumnadapter.hpp:11
std::map< std::string, int > mIndex
Definition: collection.hpp:53
Definition: columnbase.hpp:185
void setRecord(int index, const Record< ESXRecordT > &record)
Definition: collection.hpp:466
virtual void insertRecord(const RecordBase &record, int index, UniversalId::Type type=UniversalId::Type_None)
Definition: collection.hpp:443
virtual const ColumnBase & getColumn(int column) const
Definition: collection.hpp:295
virtual void purge()
Remove records that are flagged as erased.
Definition: collection.hpp:325
ESXRecordT mModified
Definition: record.hpp:41
void add(const ESXRecordT &record)
Add a new record (modified)
Definition: collection.hpp:233
virtual void setData(int index, int column, const QVariant &data)
Definition: collection.hpp:289
virtual void removeRows(int index, int count)
< Merge modified into base.
Definition: collection.hpp:339
virtual void merge()
Merge modified into base.
Definition: collection.hpp:316
const ESXRecordT & get() const
Throws an exception, if the record is deleted.
Definition: record.hpp:106
Definition: columnbase.hpp:15
Base class for record collections.
Definition: collectionbase.hpp:23
virtual int getSize() const
Definition: collection.hpp:254
Definition: record.hpp:8
void test(const MWWorld::Ptr &actor, int &compiled, int &total, const Compiler::Extensions *extensions, int warningsMode)
Definition: scripttest.cpp:27
virtual void cloneRecord(const std::string &origin, const std::string &destination, const UniversalId::Type type)
Definition: collection.hpp:209
virtual std::vector< std::string > getIds(bool listDeleted=true) const
Definition: collection.hpp:415
Access to ID field in records.
Definition: collection.hpp:23
NestableColumn * getNestableColumn(int column) const
Definition: collection.hpp:301
Definition: universalid.hpp:42
ESXRecordT ESXRecord
Definition: collection.hpp:48
virtual QVariant getData(int index, int column) const
Definition: collection.hpp:283
std::vector< Column< ESXRecordT > * > mColumns
Definition: collection.hpp:54
virtual void appendRecord(const RecordBase &record, UniversalId::Type type=UniversalId::Type_None)
Definition: collection.hpp:399