|
|
|
@ -8,6 +8,7 @@
|
|
|
|
|
#include <stdexcept>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
|
|
#include <QVariant>
|
|
|
|
|
|
|
|
|
@ -84,7 +85,7 @@ namespace CSMWorld
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
std::vector<Record<ESXRecordT> > mRecords;
|
|
|
|
|
std::vector<std::unique_ptr<Record<ESXRecordT> > > mRecords;
|
|
|
|
|
std::map<std::string, int> mIndex;
|
|
|
|
|
std::vector<Column<ESXRecordT> *> mColumns;
|
|
|
|
|
|
|
|
|
@ -96,7 +97,7 @@ namespace CSMWorld
|
|
|
|
|
|
|
|
|
|
const std::map<std::string, int>& getIdMap() const;
|
|
|
|
|
|
|
|
|
|
const std::vector<Record<ESXRecordT> >& getRecords() const;
|
|
|
|
|
const std::vector<std::unique_ptr<Record<ESXRecordT> > >& getRecords() const;
|
|
|
|
|
|
|
|
|
|
bool reorderRowsImp (int baseIndex, const std::vector<int>& newOrder);
|
|
|
|
|
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
|
|
|
|
@ -158,12 +159,12 @@ namespace CSMWorld
|
|
|
|
|
////< Search record with \a id.
|
|
|
|
|
/// \return index of record (if found) or -1 (not found)
|
|
|
|
|
|
|
|
|
|
void replace (int index, const RecordBase& record) override;
|
|
|
|
|
void replace (int index, std::unique_ptr<RecordBase> record) override;
|
|
|
|
|
///< If the record type does not match, an exception is thrown.
|
|
|
|
|
///
|
|
|
|
|
/// \attention \a record must not change the ID.
|
|
|
|
|
|
|
|
|
|
void appendRecord (const RecordBase& record,
|
|
|
|
|
void appendRecord (std::unique_ptr<RecordBase> record,
|
|
|
|
|
UniversalId::Type type = UniversalId::Type_None) override;
|
|
|
|
|
///< If the record type does not match, an exception is thrown.
|
|
|
|
|
///< \param type Will be ignored, unless the collection supports multiple record types
|
|
|
|
@ -181,7 +182,7 @@ namespace CSMWorld
|
|
|
|
|
///
|
|
|
|
|
/// \param listDeleted include deleted record in the list
|
|
|
|
|
|
|
|
|
|
virtual void insertRecord (const RecordBase& record, int index,
|
|
|
|
|
virtual void insertRecord (std::unique_ptr<RecordBase> record, int index,
|
|
|
|
|
UniversalId::Type type = UniversalId::Type_None);
|
|
|
|
|
///< Insert record before index.
|
|
|
|
|
///
|
|
|
|
@ -198,7 +199,7 @@ namespace CSMWorld
|
|
|
|
|
|
|
|
|
|
void addColumn (Column<ESXRecordT> *column);
|
|
|
|
|
|
|
|
|
|
void setRecord (int index, const Record<ESXRecordT>& record);
|
|
|
|
|
void setRecord (int index, std::unique_ptr<Record<ESXRecordT> > record);
|
|
|
|
|
///< \attention This function must not change the ID.
|
|
|
|
|
|
|
|
|
|
NestableColumn *getNestableColumn (int column) const;
|
|
|
|
@ -211,7 +212,7 @@ namespace CSMWorld
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
const std::vector<Record<ESXRecordT> >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
|
|
|
|
|
const std::vector<std::unique_ptr<Record<ESXRecordT> > >& Collection<ESXRecordT, IdAccessorT>::getRecords() const
|
|
|
|
|
{
|
|
|
|
|
return mRecords;
|
|
|
|
|
}
|
|
|
|
@ -231,15 +232,15 @@ namespace CSMWorld
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// reorder records
|
|
|
|
|
std::vector<Record<ESXRecordT> > buffer (size);
|
|
|
|
|
std::vector<std::unique_ptr<Record<ESXRecordT> > > buffer (size);
|
|
|
|
|
|
|
|
|
|
for (int i=0; i<size; ++i)
|
|
|
|
|
{
|
|
|
|
|
buffer[newOrder[i]] = mRecords [baseIndex+i];
|
|
|
|
|
buffer[newOrder[i]].setModified (buffer[newOrder[i]].get());
|
|
|
|
|
buffer[newOrder[i]] = std::move(mRecords [baseIndex+i]);
|
|
|
|
|
buffer[newOrder[i]]->setModified (buffer[newOrder[i]]->get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::copy (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
|
|
|
|
|
std::move (buffer.begin(), buffer.end(), mRecords.begin()+baseIndex);
|
|
|
|
|
|
|
|
|
|
// adjust index
|
|
|
|
|
for (std::map<std::string, int>::iterator iter (mIndex.begin()); iter!=mIndex.end();
|
|
|
|
@ -255,18 +256,18 @@ namespace CSMWorld
|
|
|
|
|
int Collection<ESXRecordT, IdAccessorT>::cloneRecordImp(const std::string& origin,
|
|
|
|
|
const std::string& destination, UniversalId::Type type)
|
|
|
|
|
{
|
|
|
|
|
Record<ESXRecordT> copy;
|
|
|
|
|
copy.mModified = getRecord(origin).get();
|
|
|
|
|
copy.mState = RecordBase::State_ModifiedOnly;
|
|
|
|
|
IdAccessorT().setId(copy.get(), destination);
|
|
|
|
|
std::unique_ptr<Record<ESXRecordT> > copy(new Record<ESXRecordT>);
|
|
|
|
|
copy->mModified = getRecord(origin).get();
|
|
|
|
|
copy->mState = RecordBase::State_ModifiedOnly;
|
|
|
|
|
IdAccessorT().setId(copy->get(), destination);
|
|
|
|
|
|
|
|
|
|
if (type == UniversalId::Type_Reference) {
|
|
|
|
|
CSMWorld::CellRef* ptr = (CSMWorld::CellRef*) ©.mModified;
|
|
|
|
|
CSMWorld::CellRef* ptr = (CSMWorld::CellRef*) ©->mModified;
|
|
|
|
|
ptr->mRefNum.mIndex = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int index = getAppendIndex(destination, type);
|
|
|
|
|
insertRecord(copy, getAppendIndex(destination, type));
|
|
|
|
|
insertRecord(std::move(copy), getAppendIndex(destination, type));
|
|
|
|
|
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
@ -275,7 +276,7 @@ namespace CSMWorld
|
|
|
|
|
int Collection<ESXRecordT, IdAccessorT>::touchRecordImp(const std::string& id)
|
|
|
|
|
{
|
|
|
|
|
int index = getIndex(id);
|
|
|
|
|
Record<ESXRecordT>& record = mRecords.at(index);
|
|
|
|
|
Record<ESXRecordT>& record = *mRecords.at(index);
|
|
|
|
|
if (record.isDeleted())
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error("attempt to touch deleted record");
|
|
|
|
@ -302,7 +303,7 @@ namespace CSMWorld
|
|
|
|
|
const std::string& destination, const UniversalId::Type type)
|
|
|
|
|
{
|
|
|
|
|
int index = cloneRecordImp(origin, destination, type);
|
|
|
|
|
mRecords.at(index).get().mPlugin = 0;
|
|
|
|
|
mRecords.at(index)->get().mPlugin = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
@ -317,7 +318,7 @@ namespace CSMWorld
|
|
|
|
|
int index = touchRecordImp(id);
|
|
|
|
|
if (index >= 0)
|
|
|
|
|
{
|
|
|
|
|
mRecords.at(index).get().mPlugin = 0;
|
|
|
|
|
mRecords.at(index)->get().mPlugin = 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -344,15 +345,15 @@ namespace CSMWorld
|
|
|
|
|
|
|
|
|
|
if (iter==mIndex.end())
|
|
|
|
|
{
|
|
|
|
|
Record<ESXRecordT> record2;
|
|
|
|
|
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
|
|
|
|
|
record2.mModified = record;
|
|
|
|
|
std::unique_ptr<Record<ESXRecordT> > record2(new Record<ESXRecordT>);
|
|
|
|
|
record2->mState = Record<ESXRecordT>::State_ModifiedOnly;
|
|
|
|
|
record2->mModified = record;
|
|
|
|
|
|
|
|
|
|
insertRecord (record2, getAppendIndex (id));
|
|
|
|
|
insertRecord (std::move(record2), getAppendIndex (id));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
mRecords[iter->second].setModified (record);
|
|
|
|
|
mRecords[iter->second]->setModified (record);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -365,7 +366,7 @@ namespace CSMWorld
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
std::string Collection<ESXRecordT, IdAccessorT>::getId (int index) const
|
|
|
|
|
{
|
|
|
|
|
return IdAccessorT().getId (mRecords.at (index).get());
|
|
|
|
|
return IdAccessorT().getId (mRecords.at (index)->get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
@ -388,13 +389,13 @@ namespace CSMWorld
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
QVariant Collection<ESXRecordT, IdAccessorT>::getData (int index, int column) const
|
|
|
|
|
{
|
|
|
|
|
return mColumns.at (column)->get (mRecords.at (index));
|
|
|
|
|
return mColumns.at (column)->get (*mRecords.at (index));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data)
|
|
|
|
|
{
|
|
|
|
|
return mColumns.at (column)->set (mRecords.at (index), data);
|
|
|
|
|
return mColumns.at (column)->set (*mRecords.at (index), data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
@ -421,8 +422,8 @@ namespace CSMWorld
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::merge()
|
|
|
|
|
{
|
|
|
|
|
for (typename std::vector<Record<ESXRecordT> >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
|
|
|
|
|
iter->merge();
|
|
|
|
|
for (typename std::vector<std::unique_ptr<Record<ESXRecordT> > >::iterator iter (mRecords.begin()); iter!=mRecords.end(); ++iter)
|
|
|
|
|
(*iter)->merge();
|
|
|
|
|
|
|
|
|
|
purge();
|
|
|
|
|
}
|
|
|
|
@ -434,7 +435,7 @@ namespace CSMWorld
|
|
|
|
|
|
|
|
|
|
while (i<static_cast<int> (mRecords.size()))
|
|
|
|
|
{
|
|
|
|
|
if (mRecords[i].isErased())
|
|
|
|
|
if (mRecords[i]->isErased())
|
|
|
|
|
removeRows (i, 1);
|
|
|
|
|
else
|
|
|
|
|
++i;
|
|
|
|
@ -475,11 +476,11 @@ namespace CSMWorld
|
|
|
|
|
IdAccessorT().setId(record, id);
|
|
|
|
|
record.blank();
|
|
|
|
|
|
|
|
|
|
Record<ESXRecordT> record2;
|
|
|
|
|
record2.mState = Record<ESXRecordT>::State_ModifiedOnly;
|
|
|
|
|
record2.mModified = record;
|
|
|
|
|
std::unique_ptr<Record<ESXRecordT> > record2(new Record<ESXRecordT>);
|
|
|
|
|
record2->mState = Record<ESXRecordT>::State_ModifiedOnly;
|
|
|
|
|
record2->mModified = record;
|
|
|
|
|
|
|
|
|
|
insertRecord (record2, getAppendIndex (id, type), type);
|
|
|
|
|
insertRecord (std::move(record2), getAppendIndex (id, type), type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
@ -496,18 +497,19 @@ namespace CSMWorld
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::replace (int index, const RecordBase& record)
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::replace (int index, std::unique_ptr<RecordBase> record)
|
|
|
|
|
{
|
|
|
|
|
mRecords.at (index) = dynamic_cast<const Record<ESXRecordT>&> (record);
|
|
|
|
|
std::unique_ptr<Record<ESXRecordT> > tmp(static_cast<Record<ESXRecordT>*>(record.release()));
|
|
|
|
|
mRecords.at (index) = std::move(tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::appendRecord (const RecordBase& record,
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::appendRecord (std::unique_ptr<RecordBase> record,
|
|
|
|
|
UniversalId::Type type)
|
|
|
|
|
{
|
|
|
|
|
insertRecord (record,
|
|
|
|
|
getAppendIndex (IdAccessorT().getId (
|
|
|
|
|
dynamic_cast<const Record<ESXRecordT>&> (record).get()), type), type);
|
|
|
|
|
int index =
|
|
|
|
|
getAppendIndex(IdAccessorT().getId(static_cast<Record<ESXRecordT>*>(record.get())->get()), type);
|
|
|
|
|
insertRecord (std::move(record), index, type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
@ -525,8 +527,8 @@ namespace CSMWorld
|
|
|
|
|
for (typename std::map<std::string, int>::const_iterator iter = mIndex.begin();
|
|
|
|
|
iter!=mIndex.end(); ++iter)
|
|
|
|
|
{
|
|
|
|
|
if (listDeleted || !mRecords[iter->second].isDeleted())
|
|
|
|
|
ids.push_back (IdAccessorT().getId (mRecords[iter->second].get()));
|
|
|
|
|
if (listDeleted || !mRecords[iter->second]->isDeleted())
|
|
|
|
|
ids.push_back (IdAccessorT().getId (mRecords[iter->second]->get()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ids;
|
|
|
|
@ -536,25 +538,26 @@ namespace CSMWorld
|
|
|
|
|
const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (const std::string& id) const
|
|
|
|
|
{
|
|
|
|
|
int index = getIndex (id);
|
|
|
|
|
return mRecords.at (index);
|
|
|
|
|
return *mRecords.at (index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
const Record<ESXRecordT>& Collection<ESXRecordT, IdAccessorT>::getRecord (int index) const
|
|
|
|
|
{
|
|
|
|
|
return mRecords.at (index);
|
|
|
|
|
return *mRecords.at (index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::insertRecord (const RecordBase& record, int index,
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::insertRecord (std::unique_ptr<RecordBase> record, int index,
|
|
|
|
|
UniversalId::Type type)
|
|
|
|
|
{
|
|
|
|
|
if (index<0 || index>static_cast<int> (mRecords.size()))
|
|
|
|
|
throw std::runtime_error ("index out of range");
|
|
|
|
|
|
|
|
|
|
const Record<ESXRecordT>& record2 = dynamic_cast<const Record<ESXRecordT>&> (record);
|
|
|
|
|
std::unique_ptr<Record<ESXRecordT> > record2(static_cast<Record<ESXRecordT>*>(record.release()));
|
|
|
|
|
std::string lowerId = Misc::StringUtils::lowerCase(IdAccessorT().getId(record2->get()));
|
|
|
|
|
|
|
|
|
|
mRecords.insert (mRecords.begin()+index, record2);
|
|
|
|
|
mRecords.insert (mRecords.begin()+index, std::move(record2));
|
|
|
|
|
|
|
|
|
|
if (index<static_cast<int> (mRecords.size())-1)
|
|
|
|
|
{
|
|
|
|
@ -564,18 +567,18 @@ namespace CSMWorld
|
|
|
|
|
++(iter->second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mIndex.insert (std::make_pair (Misc::StringUtils::lowerCase (IdAccessorT().getId (
|
|
|
|
|
record2.get())), index));
|
|
|
|
|
mIndex.insert (std::make_pair (lowerId, index));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::setRecord (int index, const Record<ESXRecordT>& record)
|
|
|
|
|
void Collection<ESXRecordT, IdAccessorT>::setRecord (int index,
|
|
|
|
|
std::unique_ptr<Record<ESXRecordT> > record)
|
|
|
|
|
{
|
|
|
|
|
if (Misc::StringUtils::lowerCase (IdAccessorT().getId (mRecords.at (index).get()))!=
|
|
|
|
|
Misc::StringUtils::lowerCase (IdAccessorT().getId (record.get())))
|
|
|
|
|
if (Misc::StringUtils::lowerCase (IdAccessorT().getId (mRecords.at (index)->get())) !=
|
|
|
|
|
Misc::StringUtils::lowerCase (IdAccessorT().getId (record->get())))
|
|
|
|
|
throw std::runtime_error ("attempt to change the ID of a record");
|
|
|
|
|
|
|
|
|
|
mRecords.at (index) = record;
|
|
|
|
|
mRecords.at (index) = std::move(record);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename ESXRecordT, typename IdAccessorT>
|
|
|
|
|