mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-03 01:49:41 +00:00
Merge remote-tracking branch 'cc9cii/moveref'
This commit is contained in:
commit
f1c0847897
40 changed files with 485 additions and 99 deletions
|
@ -231,8 +231,29 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages)
|
|||
record.mState==CSMWorld::RecordBase::State_Modified ||
|
||||
record.mState==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mCell)]
|
||||
.push_back (i);
|
||||
std::string cellId = record.get().mOriginalCell.empty() ?
|
||||
record.get().mCell : record.get().mOriginalCell;
|
||||
|
||||
std::deque<int>& indices =
|
||||
mState.getSubRecords()[Misc::StringUtils::lowerCase (cellId)];
|
||||
|
||||
// collect moved references at the end of the container
|
||||
bool interior = cellId.substr (0, 1)!="#";
|
||||
std::ostringstream stream;
|
||||
if (!interior)
|
||||
{
|
||||
// recalculate the ref's cell location
|
||||
std::pair<int, int> index = record.get().getCellIndex();
|
||||
stream << "#" << index.first << " " << index.second;
|
||||
}
|
||||
|
||||
// An empty mOriginalCell is meant to indicate that it is the same as
|
||||
// the current cell. It is possible that a moved ref is moved again.
|
||||
if ((record.get().mOriginalCell.empty() ?
|
||||
record.get().mCell : record.get().mOriginalCell) != stream.str() && !interior)
|
||||
indices.push_back (i);
|
||||
else
|
||||
indices.push_front (i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +274,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
|
|||
const CSMWorld::Record<CSMWorld::Cell>& cell =
|
||||
mDocument.getData().getCells().getRecord (stage);
|
||||
|
||||
std::map<std::string, std::vector<int> >::const_iterator references =
|
||||
std::map<std::string, std::deque<int> >::const_iterator references =
|
||||
mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId));
|
||||
|
||||
if (cell.mState==CSMWorld::RecordBase::State_Modified ||
|
||||
|
@ -284,7 +305,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
|
|||
// write references
|
||||
if (references!=mState.getSubRecords().end())
|
||||
{
|
||||
for (std::vector<int>::const_iterator iter (references->second.begin());
|
||||
for (std::deque<int>::const_iterator iter (references->second.begin());
|
||||
iter!=references->second.end(); ++iter)
|
||||
{
|
||||
const CSMWorld::Record<CSMWorld::CellRef>& ref =
|
||||
|
@ -293,6 +314,32 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
|
|||
if (ref.mState==CSMWorld::RecordBase::State_Modified ||
|
||||
ref.mState==CSMWorld::RecordBase::State_ModifiedOnly)
|
||||
{
|
||||
// recalculate the ref's cell location
|
||||
std::ostringstream stream;
|
||||
if (!interior)
|
||||
{
|
||||
std::pair<int, int> index = ref.get().getCellIndex();
|
||||
stream << "#" << index.first << " " << index.second;
|
||||
}
|
||||
|
||||
// An empty mOriginalCell is meant to indicate that it is the same as
|
||||
// the current cell. It is possible that a moved ref is moved again.
|
||||
if ((ref.get().mOriginalCell.empty() ? ref.get().mCell : ref.get().mOriginalCell)
|
||||
!= stream.str() && !interior)
|
||||
{
|
||||
ESM::MovedCellRef moved;
|
||||
moved.mRefNum = ref.get().mRefNum;
|
||||
|
||||
// Need to fill mTarget with the ref's new position.
|
||||
std::istringstream istream (stream.str().c_str());
|
||||
|
||||
char ignore;
|
||||
istream >> ignore >> moved.mTarget[0] >> moved.mTarget[1];
|
||||
|
||||
ref.get().mRefNum.save (mState.getWriter(), false, "MVRF");
|
||||
mState.getWriter().writeHNT ("CNDT", moved.mTarget, 8);
|
||||
}
|
||||
|
||||
ref.get().save (mState.getWriter());
|
||||
}
|
||||
else if (ref.mState==CSMWorld::RecordBase::State_Deleted)
|
||||
|
|
|
@ -64,7 +64,7 @@ bool CSMDoc::SavingState::isProjectFile() const
|
|||
return mProjectFile;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<int> >& CSMDoc::SavingState::getSubRecords()
|
||||
std::map<std::string, std::deque<int> >& CSMDoc::SavingState::getSubRecords()
|
||||
{
|
||||
return mSubRecords;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <deque>
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
|
@ -26,7 +27,7 @@ namespace CSMDoc
|
|||
ESM::ESMWriter mWriter;
|
||||
boost::filesystem::path mProjectPath;
|
||||
bool mProjectFile;
|
||||
std::map<std::string, std::vector<int> > mSubRecords; // record ID, list of subrecords
|
||||
std::map<std::string, std::deque<int> > mSubRecords; // record ID, list of subrecords
|
||||
|
||||
public:
|
||||
|
||||
|
@ -49,7 +50,7 @@ namespace CSMDoc
|
|||
bool isProjectFile() const;
|
||||
///< Currently saving project file? (instead of content file)
|
||||
|
||||
std::map<std::string, std::vector<int> >& getSubRecords();
|
||||
std::map<std::string, std::deque<int> >& getSubRecords();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -17,7 +17,8 @@ namespace CSMWorld
|
|||
enum Roles
|
||||
{
|
||||
Role_Flags = Qt::UserRole,
|
||||
Role_Display = Qt::UserRole+1
|
||||
Role_Display = Qt::UserRole+1,
|
||||
Role_ColumnId = Qt::UserRole+2
|
||||
};
|
||||
|
||||
enum Flags
|
||||
|
|
|
@ -870,7 +870,13 @@ namespace CSMWorld
|
|||
template<typename ESXRecordT>
|
||||
struct CellColumn : public Column<ESXRecordT>
|
||||
{
|
||||
CellColumn() : Column<ESXRecordT> (Columns::ColumnId_Cell, ColumnBase::Display_Cell) {}
|
||||
bool mBlocked;
|
||||
|
||||
/// \param blocked Do not allow user-modification
|
||||
CellColumn (bool blocked = false)
|
||||
: Column<ESXRecordT> (Columns::ColumnId_Cell, ColumnBase::Display_Cell),
|
||||
mBlocked (blocked)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
|
@ -892,9 +898,41 @@ namespace CSMWorld
|
|||
}
|
||||
|
||||
virtual bool isUserEditable() const
|
||||
{
|
||||
return !mBlocked;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
struct OriginalCellColumn : public Column<ESXRecordT>
|
||||
{
|
||||
OriginalCellColumn()
|
||||
: Column<ESXRecordT> (Columns::ColumnId_OriginalCell, ColumnBase::Display_Cell)
|
||||
{}
|
||||
|
||||
virtual QVariant get (const Record<ESXRecordT>& record) const
|
||||
{
|
||||
return QString::fromUtf8 (record.get().mOriginalCell.c_str());
|
||||
}
|
||||
|
||||
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
|
||||
{
|
||||
ESXRecordT record2 = record.get();
|
||||
|
||||
record2.mOriginalCell = data.toString().toUtf8().constData();
|
||||
|
||||
record.setModified (record2);
|
||||
}
|
||||
|
||||
virtual bool isEditable() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool isUserEditable() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ESXRecordT>
|
||||
|
|
|
@ -222,6 +222,7 @@ namespace CSMWorld
|
|||
{ ColumnId_HitSound, "Hit Sound" },
|
||||
{ ColumnId_AreaSound, "Area Sound" },
|
||||
{ ColumnId_BoltSound, "Bolt Sound" },
|
||||
{ ColumnId_OriginalCell, "Original Cell" },
|
||||
|
||||
{ ColumnId_PathgridPoints, "Points" },
|
||||
{ ColumnId_PathgridIndex, "Index" },
|
||||
|
|
|
@ -264,6 +264,8 @@ namespace CSMWorld
|
|||
|
||||
ColumnId_InfoList = 240,
|
||||
|
||||
ColumnId_OriginalCell = 241,
|
||||
|
||||
// Allocated to a separate value range, so we don't get a collision should we ever need
|
||||
// to extend the number of use values.
|
||||
ColumnId_UseValue1 = 0x10000,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "commanddispatcher.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
|
@ -10,6 +11,7 @@
|
|||
#include "idtable.hpp"
|
||||
#include "record.hpp"
|
||||
#include "commands.hpp"
|
||||
#include "idtableproxymodel.hpp"
|
||||
|
||||
std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const
|
||||
{
|
||||
|
@ -131,6 +133,54 @@ std::vector<CSMWorld::UniversalId> CSMWorld::CommandDispatcher::getExtendedTypes
|
|||
return tables;
|
||||
}
|
||||
|
||||
void CSMWorld::CommandDispatcher::executeModify (QAbstractItemModel *model, const QModelIndex& index, const QVariant& new_)
|
||||
{
|
||||
if (mLocked)
|
||||
return;
|
||||
|
||||
std::auto_ptr<CSMWorld::UpdateCellCommand> modifyCell;
|
||||
|
||||
int columnId = model->data (index, ColumnBase::Role_ColumnId).toInt();
|
||||
|
||||
if (columnId==Columns::ColumnId_PositionXPos || columnId==Columns::ColumnId_PositionYPos)
|
||||
{
|
||||
IdTableProxyModel *proxy = dynamic_cast<IdTableProxyModel *> (model);
|
||||
|
||||
int row = proxy ? proxy->mapToSource (index).row() : index.row();
|
||||
|
||||
// This is not guaranteed to be the same as \a model, since a proxy could be used.
|
||||
IdTable& model2 = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
|
||||
|
||||
int cellColumn = model2.searchColumnIndex (Columns::ColumnId_Cell);
|
||||
|
||||
if (cellColumn!=-1)
|
||||
{
|
||||
QModelIndex cellIndex = model2.index (row, cellColumn);
|
||||
|
||||
std::string cellId = model2.data (cellIndex).toString().toUtf8().data();
|
||||
|
||||
if (cellId.find ('#')!=std::string::npos)
|
||||
{
|
||||
// Need to recalculate the cell
|
||||
modifyCell.reset (new UpdateCellCommand (model2, row));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::auto_ptr<CSMWorld::ModifyCommand> modifyData (
|
||||
new CSMWorld::ModifyCommand (*model, index, new_));
|
||||
|
||||
if (modifyCell.get())
|
||||
{
|
||||
mDocument.getUndoStack().beginMacro (modifyData->text());
|
||||
mDocument.getUndoStack().push (modifyData.release());
|
||||
mDocument.getUndoStack().push (modifyCell.release());
|
||||
mDocument.getUndoStack().endMacro();
|
||||
}
|
||||
else
|
||||
mDocument.getUndoStack().push (modifyData.release());
|
||||
}
|
||||
|
||||
void CSMWorld::CommandDispatcher::executeDelete()
|
||||
{
|
||||
if (mLocked)
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
#include "universalid.hpp"
|
||||
|
||||
class QModelIndex;
|
||||
class QAbstractItemModel;
|
||||
|
||||
namespace CSMDoc
|
||||
{
|
||||
class Document;
|
||||
|
@ -53,6 +56,12 @@ namespace CSMWorld
|
|||
/// the extended mode, the returned vector will be empty instead.
|
||||
std::vector<UniversalId> getExtendedTypes() const;
|
||||
|
||||
/// Add a modify command to the undo stack.
|
||||
///
|
||||
/// \attention model must either be a model for the table operated on by this
|
||||
/// dispatcher or a proxy of it.
|
||||
void executeModify (QAbstractItemModel *model, const QModelIndex& index, const QVariant& new_);
|
||||
|
||||
public slots:
|
||||
|
||||
void executeDelete();
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "commands.hpp"
|
||||
|
||||
#include <cmath>
|
||||
#include <sstream>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
@ -183,6 +186,47 @@ void CSMWorld::CloneCommand::undo()
|
|||
mModel.removeRow (mModel.getModelIndex (mId, 0).row());
|
||||
}
|
||||
|
||||
|
||||
CSMWorld::UpdateCellCommand::UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent)
|
||||
: QUndoCommand (parent), mModel (model), mRow (row)
|
||||
{
|
||||
setText ("Update cell ID");
|
||||
}
|
||||
|
||||
void CSMWorld::UpdateCellCommand::redo()
|
||||
{
|
||||
if (!mNew.isValid())
|
||||
{
|
||||
int cellColumn = mModel.searchColumnIndex (Columns::ColumnId_Cell);
|
||||
mIndex = mModel.index (mRow, cellColumn);
|
||||
|
||||
const int cellSize = 8192;
|
||||
|
||||
QModelIndex xIndex = mModel.index (
|
||||
mRow, mModel.findColumnIndex (Columns::ColumnId_PositionXPos));
|
||||
|
||||
QModelIndex yIndex = mModel.index (
|
||||
mRow, mModel.findColumnIndex (Columns::ColumnId_PositionYPos));
|
||||
|
||||
int x = std::floor (mModel.data (xIndex).toFloat() / cellSize);
|
||||
int y = std::floor (mModel.data (yIndex).toFloat() / cellSize);
|
||||
|
||||
std::ostringstream stream;
|
||||
|
||||
stream << "#" << x << " " << y;
|
||||
|
||||
mNew = QString::fromUtf8 (stream.str().c_str());
|
||||
}
|
||||
|
||||
mModel.setData (mIndex, mNew);
|
||||
}
|
||||
|
||||
void CSMWorld::UpdateCellCommand::undo()
|
||||
{
|
||||
mModel.setData (mIndex, mOld);
|
||||
}
|
||||
|
||||
|
||||
CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model,
|
||||
const std::string& id,
|
||||
int nestedRow,
|
||||
|
|
|
@ -144,6 +144,29 @@ namespace CSMWorld
|
|||
virtual void undo();
|
||||
};
|
||||
|
||||
/// \brief Update cell ID according to x/y-coordinates
|
||||
///
|
||||
/// \note The new value will be calculated in the first call to redo instead of the
|
||||
/// constructor to accommodate multiple coordinate-affecting commands being executed
|
||||
/// in a macro.
|
||||
class UpdateCellCommand : public QUndoCommand
|
||||
{
|
||||
IdTable& mModel;
|
||||
int mRow;
|
||||
QModelIndex mIndex;
|
||||
QVariant mNew; // invalid, if new cell ID has not been calculated yet
|
||||
QVariant mOld;
|
||||
|
||||
public:
|
||||
|
||||
UpdateCellCommand (IdTable& model, int row, QUndoCommand *parent = 0);
|
||||
|
||||
virtual void redo();
|
||||
|
||||
virtual void undo();
|
||||
};
|
||||
|
||||
|
||||
class NestedTableStoring
|
||||
{
|
||||
NestedTableWrapperBase* mOld;
|
||||
|
|
|
@ -368,7 +368,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
mRefs.addColumn (new StringIdColumn<CellRef> (true));
|
||||
mRefs.addColumn (new RecordStateColumn<CellRef>);
|
||||
mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference));
|
||||
mRefs.addColumn (new CellColumn<CellRef>);
|
||||
mRefs.addColumn (new CellColumn<CellRef> (true));
|
||||
mRefs.addColumn (new OriginalCellColumn<CellRef>);
|
||||
mRefs.addColumn (new IdColumn<CellRef>);
|
||||
mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false));
|
||||
mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 1, false));
|
||||
|
@ -457,6 +458,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
|
|||
UniversalId::Type_Texture);
|
||||
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
|
||||
UniversalId::Type_Video);
|
||||
|
||||
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
|
||||
}
|
||||
|
||||
CSMWorld::Data::~Data()
|
||||
|
@ -778,7 +781,6 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
|
|||
mReader = 0;
|
||||
|
||||
mDialogue = 0;
|
||||
mRefLoadCache.clear();
|
||||
|
||||
mReader = new ESM::ESMReader;
|
||||
mReader->setEncoder (&mEncoder);
|
||||
|
@ -815,7 +817,6 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
|||
mReader = 0;
|
||||
|
||||
mDialogue = 0;
|
||||
mRefLoadCache.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -860,9 +861,16 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
|
|||
|
||||
case ESM::REC_CELL:
|
||||
{
|
||||
mCells.load (*mReader, mBase);
|
||||
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1));
|
||||
mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages);
|
||||
int index = mCells.load (*mReader, mBase);
|
||||
if (index < 0 || index >= mCells.getSize())
|
||||
{
|
||||
// log an error and continue loading the refs to the last loaded cell
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_None);
|
||||
messages.add (id, "Logic error: cell index out of bounds");
|
||||
index = mCells.getSize()-1;
|
||||
}
|
||||
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index));
|
||||
mRefs.load (*mReader, index, mBase, mRefLoadCache[cellId], messages);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,15 @@ namespace CSMWorld
|
|||
{
|
||||
ESXRecordT record;
|
||||
|
||||
// Sometimes id (i.e. NAME of the cell) may be different to the id we stored
|
||||
// earlier. e.g. NAME == "Vivec, Arena" but id == "#-4 11". Sometime NAME is
|
||||
// missing altogether for scripts or cells.
|
||||
//
|
||||
// In such cases the returned index will be -1. We then try updating the
|
||||
// IdAccessor's id manually (e.g. set mId of the record to "Vivec, Arena")
|
||||
// and try getting the index once more after loading the record. The mId of the
|
||||
// record would have changed to "#-4 11" after the load, and searchId() should find
|
||||
// it (if this is a modify)
|
||||
int index = this->searchId (id);
|
||||
|
||||
if (index==-1)
|
||||
|
|
|
@ -28,9 +28,15 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const
|
|||
return mIdCollection->getColumns();
|
||||
}
|
||||
|
||||
QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
|
||||
QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
|
||||
{
|
||||
if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0)
|
||||
if (index.row() < 0 || index.column() < 0)
|
||||
return QVariant();
|
||||
|
||||
if (role==ColumnBase::Role_ColumnId)
|
||||
return QVariant (getColumnId (index.column()));
|
||||
|
||||
if ((role!=Qt::DisplayRole && role!=Qt::EditRole))
|
||||
return QVariant();
|
||||
|
||||
if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable())
|
||||
|
@ -56,6 +62,9 @@ QVariant CSMWorld::IdTable::headerData (int section, Qt::Orientation orientation
|
|||
if (role==ColumnBase::Role_Display)
|
||||
return mIdCollection->getColumn (section).mDisplayType;
|
||||
|
||||
if (role==ColumnBase::Role_ColumnId)
|
||||
return getColumnId (section);
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,18 @@
|
|||
|
||||
#include "ref.hpp"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
CSMWorld::CellRef::CellRef()
|
||||
{
|
||||
mRefNum.mIndex = 0;
|
||||
mRefNum.mContentFile = 0;
|
||||
}
|
||||
|
||||
std::pair<int, int> CSMWorld::CellRef::getCellIndex() const
|
||||
{
|
||||
const int cellSize = 8192;
|
||||
|
||||
return std::make_pair (
|
||||
std::floor (mPos.pos[0]/cellSize), std::floor (mPos.pos[1]/cellSize));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef CSM_WOLRD_REF_H
|
||||
#define CSM_WOLRD_REF_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <components/esm/cellref.hpp>
|
||||
|
||||
namespace CSMWorld
|
||||
|
@ -10,8 +12,12 @@ namespace CSMWorld
|
|||
{
|
||||
std::string mId;
|
||||
std::string mCell;
|
||||
std::string mOriginalCell;
|
||||
|
||||
CellRef();
|
||||
|
||||
/// Calculate cell index based on coordinates (x and y)
|
||||
std::pair<int, int> getCellIndex() const;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
#include "refcollection.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <components/misc/stringops.hpp>
|
||||
#include <components/esm/loadcell.hpp>
|
||||
|
||||
#include "ref.hpp"
|
||||
#include "cell.hpp"
|
||||
|
@ -20,14 +22,75 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
|
|||
CellRef ref;
|
||||
|
||||
bool deleted = false;
|
||||
ESM::MovedCellRef mref;
|
||||
|
||||
while (ESM::Cell::getNextRef (reader, ref, deleted))
|
||||
// hack to initialise mindex
|
||||
while (!(mref.mRefNum.mIndex = 0) && ESM::Cell::getNextRef(reader, ref, deleted, true, &mref))
|
||||
{
|
||||
ref.mCell = cell2.mId;
|
||||
// Keep mOriginalCell empty when in modified (as an indicator that the
|
||||
// original cell will always be equal the current cell).
|
||||
ref.mOriginalCell = base ? cell2.mId : "";
|
||||
|
||||
/// \todo handle moved references
|
||||
if (cell.get().isExterior())
|
||||
{
|
||||
// ignoring moved references sub-record; instead calculate cell from coordinates
|
||||
std::pair<int, int> index = ref.getCellIndex();
|
||||
|
||||
std::map<ESM::RefNum, std::string>::iterator iter = cache.find (ref.mRefNum);
|
||||
std::ostringstream stream;
|
||||
stream << "#" << index.first << " " << index.second;
|
||||
|
||||
ref.mCell = stream.str();
|
||||
|
||||
if (!base && // don't try to update base records
|
||||
mref.mRefNum.mIndex != 0) // MVRF tag found
|
||||
{
|
||||
// there is a requirement for a placeholder where the original object was
|
||||
//
|
||||
// see the forum discussions here for more details:
|
||||
// https://forum.openmw.org/viewtopic.php?f=6&t=577&start=30
|
||||
ref.mOriginalCell = cell2.mId;
|
||||
|
||||
if (deleted)
|
||||
{
|
||||
// FIXME: how to mark the record deleted?
|
||||
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell,
|
||||
mCells.getId (cellIndex));
|
||||
|
||||
messages.add (id, "Moved reference "+ref.mRefID+" is in DELE state");
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// It is not always possibe to ignore moved references sub-record and
|
||||
// calculate from coordinates. Some mods may place the ref in positions
|
||||
// outside normal bounds, resulting in non sensical cell id's. This often
|
||||
// happens if the moved ref was deleted.
|
||||
//
|
||||
// Use the target cell from the MVRF tag but if different output an error
|
||||
// message
|
||||
if (index.first != mref.mTarget[0] || index.second != mref.mTarget[1])
|
||||
{
|
||||
std::cerr << "The Position of moved ref "
|
||||
<< ref.mRefID << " does not match the target cell" << std::endl;
|
||||
std::cerr << "Position: #" << index.first << " " << index.second
|
||||
<<", Target #"<< mref.mTarget[0] << " " << mref.mTarget[1] << std::endl;
|
||||
|
||||
std::ostringstream stream;
|
||||
stream << "#" << mref.mTarget[0] << " " << mref.mTarget[1];
|
||||
ref.mCell = stream.str(); // overwrite
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
ref.mCell = cell2.mId;
|
||||
|
||||
// ignore content file number
|
||||
std::map<ESM::RefNum, std::string>::iterator iter = cache.begin();
|
||||
for (; iter != cache.end(); ++iter)
|
||||
{
|
||||
if (ref.mRefNum.mIndex == iter->first.mIndex)
|
||||
break;
|
||||
}
|
||||
|
||||
if (deleted)
|
||||
{
|
||||
|
|
|
@ -27,8 +27,7 @@ namespace CSMWorld
|
|||
{}
|
||||
|
||||
void load (ESM::ESMReader& reader, int cellIndex, bool base,
|
||||
std::map<ESM::RefNum, std::string>& cache,
|
||||
CSMDoc::Messages& messages);
|
||||
std::map<ESM::RefNum, std::string>& cache, CSMDoc::Messages& messages);
|
||||
///< Load a sequence of references.
|
||||
|
||||
std::string getNewId();
|
||||
|
|
|
@ -131,8 +131,8 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
|
|||
setModel (mModel);
|
||||
setColumnHidden (2, true);
|
||||
|
||||
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (
|
||||
document, this);
|
||||
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (0,
|
||||
mDocument, this);
|
||||
|
||||
setItemDelegateForColumn (0, mIdTypeDelegate);
|
||||
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
|
||||
CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
|
||||
const IconList &icons,
|
||||
CSMWorld::CommandDispatcher *dispatcher,
|
||||
CSMDoc::Document& document,
|
||||
const QString &pageName,
|
||||
const QString &settingName,
|
||||
QObject *parent)
|
||||
: EnumDelegate (values, document, parent), mDisplayMode (Mode_TextOnly),
|
||||
: EnumDelegate (values, dispatcher, document, parent), mDisplayMode (Mode_TextOnly),
|
||||
mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3),
|
||||
mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName)
|
||||
{
|
||||
|
@ -136,9 +137,9 @@ void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName,
|
|||
}
|
||||
|
||||
CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (
|
||||
CSMDoc::Document& document, QObject *parent) const
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const
|
||||
{
|
||||
return new DataDisplayDelegate (mValues, mIcons, document, "", "", parent);
|
||||
return new DataDisplayDelegate (mValues, mIcons, dispatcher, document, "", "", parent);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -38,12 +38,9 @@ namespace CSVWorld
|
|||
QString mSettingKey;
|
||||
|
||||
public:
|
||||
explicit DataDisplayDelegate (const ValueList & values,
|
||||
const IconList & icons,
|
||||
CSMDoc::Document& document,
|
||||
const QString &pageName,
|
||||
const QString &settingName,
|
||||
QObject *parent);
|
||||
DataDisplayDelegate (const ValueList & values, const IconList & icons,
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document,
|
||||
const QString &pageName, const QString &settingName, QObject *parent);
|
||||
|
||||
~DataDisplayDelegate();
|
||||
|
||||
|
@ -82,7 +79,7 @@ namespace CSVWorld
|
|||
|
||||
public:
|
||||
|
||||
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
|
||||
virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const;
|
||||
///< The ownership of the returned CommandDelegate is transferred to the caller.
|
||||
|
||||
protected:
|
||||
|
|
|
@ -177,10 +177,11 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::
|
|||
*/
|
||||
|
||||
CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent,
|
||||
CSMWorld::IdTable* table, CSMDoc::Document& document, QAbstractItemModel *model) :
|
||||
CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher,
|
||||
CSMDoc::Document& document, QAbstractItemModel *model) :
|
||||
mParent(parent),
|
||||
mTable(model ? model : table),
|
||||
mDocument (document),
|
||||
mCommandDispatcher (commandDispatcher), mDocument (document),
|
||||
mNotEditableDelegate(table, parent)
|
||||
{
|
||||
}
|
||||
|
@ -192,7 +193,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS
|
|||
if (delegateIt == mDelegates.end())
|
||||
{
|
||||
delegate = CommandDelegateFactoryCollection::get().makeDelegate (
|
||||
display, mDocument, mParent);
|
||||
display, &mCommandDispatcher, mDocument, mParent);
|
||||
mDelegates.insert(std::make_pair(display, delegate));
|
||||
} else
|
||||
{
|
||||
|
@ -352,13 +353,16 @@ CSVWorld::EditWidget::~EditWidget()
|
|||
delete mNestedTableDispatcher;
|
||||
}
|
||||
|
||||
CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) :
|
||||
mDispatcher(this, table, document),
|
||||
CSVWorld::EditWidget::EditWidget(QWidget *parent,
|
||||
int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher,
|
||||
CSMDoc::Document& document, bool createAndDelete) :
|
||||
mDispatcher(this, table, commandDispatcher, document),
|
||||
mNestedTableDispatcher(NULL),
|
||||
QScrollArea(parent),
|
||||
mWidgetMapper(NULL),
|
||||
mNestedTableMapper(NULL),
|
||||
mMainWidget(NULL),
|
||||
mCommandDispatcher (commandDispatcher),
|
||||
mDocument (document),
|
||||
mTable(table)
|
||||
{
|
||||
|
@ -442,7 +446,14 @@ void CSVWorld::EditWidget::remake(int row)
|
|||
{
|
||||
mNestedModels.push_back(new CSMWorld::NestedTableProxyModel (mTable->index(row, i), display, dynamic_cast<CSMWorld::IdTree*>(mTable)));
|
||||
|
||||
NestedTable* table = new NestedTable(mDocument, mNestedModels.back(), this);
|
||||
int idColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
|
||||
int typeColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType);
|
||||
|
||||
CSMWorld::UniversalId id = CSMWorld::UniversalId(
|
||||
static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (row, typeColumn)).toInt()),
|
||||
mTable->data (mTable->index (row, idColumn)).toString().toUtf8().constData());
|
||||
|
||||
NestedTable* table = new NestedTable(mDocument, id, mNestedModels.back(), this);
|
||||
// FIXME: does not work well when enum delegates are used
|
||||
//table->resizeColumnsToContents();
|
||||
table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged);
|
||||
|
@ -499,7 +510,7 @@ void CSVWorld::EditWidget::remake(int row)
|
|||
mNestedTableMapper->setModel(mNestedModels.back());
|
||||
// FIXME: lack MIME support?
|
||||
mNestedTableDispatcher =
|
||||
new DialogueDelegateDispatcher (this, mTable, mDocument, mNestedModels.back());
|
||||
new DialogueDelegateDispatcher (this, mTable, mCommandDispatcher, mDocument, mNestedModels.back());
|
||||
mNestedTableMapper->setItemDelegate(mNestedTableDispatcher);
|
||||
|
||||
int columnCount =
|
||||
|
@ -626,7 +637,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
|
|||
|
||||
mMainLayout = new QVBoxLayout(mainWidget);
|
||||
|
||||
mEditWidget = new EditWidget(mainWidget, mTable->getModelIndex(mCurrentId, 0).row(), mTable, document, false);
|
||||
mEditWidget = new EditWidget(mainWidget,
|
||||
mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false);
|
||||
connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
|
||||
this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
|
||||
|
||||
|
|
|
@ -109,6 +109,7 @@ namespace CSVWorld
|
|||
|
||||
QAbstractItemModel* mTable;
|
||||
|
||||
CSMWorld::CommandDispatcher& mCommandDispatcher;
|
||||
CSMDoc::Document& mDocument;
|
||||
|
||||
NotEditableSubDelegate mNotEditableDelegate;
|
||||
|
@ -119,6 +120,7 @@ namespace CSVWorld
|
|||
public:
|
||||
DialogueDelegateDispatcher(QObject* parent,
|
||||
CSMWorld::IdTable* table,
|
||||
CSMWorld::CommandDispatcher& commandDispatcher,
|
||||
CSMDoc::Document& document,
|
||||
QAbstractItemModel* model = 0);
|
||||
|
||||
|
@ -167,12 +169,14 @@ namespace CSVWorld
|
|||
DialogueDelegateDispatcher *mNestedTableDispatcher;
|
||||
QWidget* mMainWidget;
|
||||
CSMWorld::IdTable* mTable;
|
||||
CSMWorld::CommandDispatcher& mCommandDispatcher;
|
||||
CSMDoc::Document& mDocument;
|
||||
std::vector<CSMWorld::NestedTableProxyModel*> mNestedModels; //Plain, raw C pointers, deleted in the dtor
|
||||
|
||||
public:
|
||||
|
||||
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table,
|
||||
CSMWorld::CommandDispatcher& commandDispatcher,
|
||||
CSMDoc::Document& document, bool createAndDelete = false);
|
||||
|
||||
virtual ~EditWidget();
|
||||
|
|
|
@ -37,8 +37,8 @@ void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model,
|
|||
|
||||
|
||||
CSVWorld::EnumDelegate::EnumDelegate (const std::vector<std::pair<int, QString> >& values,
|
||||
CSMDoc::Document& document, QObject *parent)
|
||||
: CommandDelegate (document, parent), mValues (values)
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
|
||||
: CommandDelegate (dispatcher, document, parent), mValues (values)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -142,9 +142,9 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector<std::strin
|
|||
}
|
||||
|
||||
CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (
|
||||
CSMDoc::Document& document, QObject *parent) const
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const
|
||||
{
|
||||
return new EnumDelegate (mValues, document, parent);
|
||||
return new EnumDelegate (mValues, dispatcher, document, parent);
|
||||
}
|
||||
|
||||
void CSVWorld::EnumDelegateFactory::add (int value, const QString& name)
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace CSVWorld
|
|||
public:
|
||||
|
||||
EnumDelegate (const std::vector<std::pair<int, QString> >& values,
|
||||
CSMDoc::Document& document, QObject *parent);
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent);
|
||||
|
||||
virtual QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem& option,
|
||||
|
@ -64,7 +64,7 @@ namespace CSVWorld
|
|||
EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false);
|
||||
/// \param allowNone Use value of -1 for "none selected" (empty string)
|
||||
|
||||
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
|
||||
virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const;
|
||||
///< The ownership of the returned CommandDelegate is transferred to the caller.
|
||||
|
||||
void add (int value, const QString& name);
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
#include "../../model/world/universalid.hpp"
|
||||
|
||||
CSVWorld::IdTypeDelegate::IdTypeDelegate
|
||||
(const ValueList &values, const IconList &icons, CSMDoc::Document& document, QObject *parent)
|
||||
: DataDisplayDelegate (values, icons, document,
|
||||
(const ValueList &values, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
|
||||
: DataDisplayDelegate (values, icons, dispatcher, document,
|
||||
"records", "type-format",
|
||||
parent)
|
||||
{}
|
||||
|
@ -21,7 +21,7 @@ CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory()
|
|||
}
|
||||
|
||||
CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate (
|
||||
CSMDoc::Document& document, QObject *parent) const
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const
|
||||
{
|
||||
return new IdTypeDelegate (mValues, mIcons, document, parent);
|
||||
return new IdTypeDelegate (mValues, mIcons, dispatcher, document, parent);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace CSVWorld
|
|||
class IdTypeDelegate : public DataDisplayDelegate
|
||||
{
|
||||
public:
|
||||
IdTypeDelegate (const ValueList &mValues, const IconList &icons, CSMDoc::Document& document, QObject *parent);
|
||||
IdTypeDelegate (const ValueList &mValues, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent);
|
||||
};
|
||||
|
||||
class IdTypeDelegateFactory : public DataDisplayDelegateFactory
|
||||
|
@ -20,7 +20,7 @@ namespace CSVWorld
|
|||
|
||||
IdTypeDelegateFactory();
|
||||
|
||||
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
|
||||
virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const;
|
||||
///< The ownership of the returned CommandDelegate is transferred to the caller.
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "../../model/world/nestedtableproxymodel.hpp"
|
||||
#include "../../model/world/universalid.hpp"
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/commanddispatcher.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
#include <QHeaderView>
|
||||
|
@ -10,12 +11,14 @@
|
|||
#include <QDebug>
|
||||
|
||||
CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
|
||||
CSMWorld::UniversalId id,
|
||||
CSMWorld::NestedTableProxyModel* model,
|
||||
QWidget* parent)
|
||||
: QTableView(parent),
|
||||
mUndoStack(document.getUndoStack()),
|
||||
mModel(model)
|
||||
{
|
||||
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
|
||||
|
||||
setSelectionBehavior (QAbstractItemView::SelectRows);
|
||||
setSelectionMode (QAbstractItemView::ExtendedSelection);
|
||||
|
@ -31,6 +34,7 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
|
|||
model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display,
|
||||
mDispatcher,
|
||||
document,
|
||||
this);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ namespace CSMWorld
|
|||
{
|
||||
class NestedTableProxyModel;
|
||||
class UniversalId;
|
||||
class CommandDispatcher;
|
||||
}
|
||||
|
||||
namespace CSMDoc
|
||||
|
@ -29,9 +30,11 @@ namespace CSVWorld
|
|||
QAction *mRemoveRowAction;
|
||||
QUndoStack& mUndoStack;
|
||||
CSMWorld::NestedTableProxyModel* mModel;
|
||||
CSMWorld::CommandDispatcher *mDispatcher;
|
||||
|
||||
public:
|
||||
NestedTable(CSMDoc::Document& document,
|
||||
CSMWorld::UniversalId id,
|
||||
CSMWorld::NestedTableProxyModel* model,
|
||||
QWidget* parent = NULL);
|
||||
|
||||
|
|
|
@ -9,16 +9,16 @@
|
|||
|
||||
CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values,
|
||||
const IconList & icons,
|
||||
CSMDoc::Document& document, QObject *parent)
|
||||
: DataDisplayDelegate (values, icons, document,
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
|
||||
: DataDisplayDelegate (values, icons, dispatcher, document,
|
||||
"records", "status-format",
|
||||
parent)
|
||||
{}
|
||||
|
||||
CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate (
|
||||
CSMDoc::Document& document, QObject *parent) const
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const
|
||||
{
|
||||
return new RecordStatusDelegate (mValues, mIcons, document, parent);
|
||||
return new RecordStatusDelegate (mValues, mIcons, dispatcher, document, parent);
|
||||
}
|
||||
|
||||
CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory()
|
||||
|
|
|
@ -17,9 +17,9 @@ namespace CSVWorld
|
|||
{
|
||||
public:
|
||||
|
||||
explicit RecordStatusDelegate(const ValueList& values,
|
||||
const IconList& icons,
|
||||
CSMDoc::Document& document, QObject *parent = 0);
|
||||
RecordStatusDelegate (const ValueList& values, const IconList& icons,
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document,
|
||||
QObject *parent = 0);
|
||||
};
|
||||
|
||||
class RecordStatusDelegateFactory : public DataDisplayDelegateFactory
|
||||
|
@ -28,7 +28,7 @@ namespace CSVWorld
|
|||
|
||||
RecordStatusDelegateFactory();
|
||||
|
||||
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
|
||||
virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const;
|
||||
///< The ownership of the returned CommandDelegate is transferred to the caller.
|
||||
|
||||
};
|
||||
|
|
|
@ -281,7 +281,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
|
|||
mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
|
||||
|
||||
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display,
|
||||
mDocument, this);
|
||||
mDispatcher, document, this);
|
||||
|
||||
mDelegates.push_back (delegate);
|
||||
setItemDelegateForColumn (i, delegate);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "../../model/world/commands.hpp"
|
||||
#include "../../model/world/tablemimedata.hpp"
|
||||
#include "../../model/world/commanddispatcher.hpp"
|
||||
|
||||
#include "scriptedit.hpp"
|
||||
|
||||
|
@ -82,15 +83,15 @@ void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Disp
|
|||
}
|
||||
|
||||
CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate (
|
||||
CSMWorld::ColumnBase::Display display, CSMDoc::Document& document, QObject *parent) const
|
||||
CSMWorld::ColumnBase::Display display, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const
|
||||
{
|
||||
std::map<CSMWorld::ColumnBase::Display, CommandDelegateFactory *>::const_iterator iter =
|
||||
mFactories.find (display);
|
||||
|
||||
if (iter!=mFactories.end())
|
||||
return iter->second->makeDelegate (document, parent);
|
||||
return iter->second->makeDelegate (dispatcher, document, parent);
|
||||
|
||||
return new CommandDelegate (document, parent);
|
||||
return new CommandDelegate (dispatcher, document, parent);
|
||||
}
|
||||
|
||||
const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get()
|
||||
|
@ -115,17 +116,22 @@ CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const
|
|||
void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
if (!mCommandDispatcher)
|
||||
return;
|
||||
|
||||
NastyTableModelHack hack (*model);
|
||||
QStyledItemDelegate::setModelData (editor, &hack, index);
|
||||
|
||||
QVariant new_ = hack.getData();
|
||||
|
||||
if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable))
|
||||
getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_));
|
||||
mCommandDispatcher->executeModify (model, index, new_);
|
||||
}
|
||||
|
||||
CSVWorld::CommandDelegate::CommandDelegate (CSMDoc::Document& document, QObject *parent)
|
||||
: QStyledItemDelegate (parent), mDocument (document), mEditLock (false)
|
||||
CSVWorld::CommandDelegate::CommandDelegate (CSMWorld::CommandDispatcher *commandDispatcher,
|
||||
CSMDoc::Document& document, QObject *parent)
|
||||
: QStyledItemDelegate (parent), mEditLock (false),
|
||||
mCommandDispatcher (commandDispatcher), mDocument (document)
|
||||
{}
|
||||
|
||||
void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model,
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace CSMWorld
|
|||
{
|
||||
class TableMimeData;
|
||||
class UniversalId;
|
||||
class CommandDispatcher;
|
||||
}
|
||||
|
||||
namespace CSVWorld
|
||||
|
@ -51,7 +52,8 @@ namespace CSVWorld
|
|||
|
||||
virtual ~CommandDelegateFactory();
|
||||
|
||||
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent)
|
||||
virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher,
|
||||
CSMDoc::Document& document, QObject *parent)
|
||||
const = 0;
|
||||
///< The ownership of the returned CommandDelegate is transferred to the caller.
|
||||
};
|
||||
|
@ -78,7 +80,8 @@ namespace CSVWorld
|
|||
///
|
||||
/// This function must not be called more than once per value of \a display.
|
||||
|
||||
CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, CSMDoc::Document& document,
|
||||
CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display,
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document,
|
||||
QObject *parent) const;
|
||||
///< The ownership of the returned CommandDelegate is transferred to the caller.
|
||||
///
|
||||
|
@ -111,8 +114,9 @@ namespace CSVWorld
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
CSMDoc::Document& mDocument;
|
||||
bool mEditLock;
|
||||
CSMWorld::CommandDispatcher *mCommandDispatcher;
|
||||
CSMDoc::Document& mDocument;
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -125,7 +129,9 @@ namespace CSVWorld
|
|||
|
||||
public:
|
||||
|
||||
CommandDelegate (CSMDoc::Document& document, QObject *parent);
|
||||
/// \param commandDispatcher If CommandDelegate will be only be used on read-only
|
||||
/// cells, a 0-pointer can be passed here.
|
||||
CommandDelegate (CSMWorld::CommandDispatcher *commandDispatcher, CSMDoc::Document& document, QObject *parent);
|
||||
|
||||
virtual void setModelData (QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex& index) const;
|
||||
|
|
|
@ -47,8 +47,8 @@ void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QM
|
|||
}
|
||||
|
||||
CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
|
||||
CSMDoc::Document& document, QObject *parent)
|
||||
: EnumDelegate (values, document, parent)
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
|
||||
: EnumDelegate (values, dispatcher, document, parent)
|
||||
{}
|
||||
|
||||
|
||||
|
@ -69,9 +69,9 @@ CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0,
|
|||
}
|
||||
|
||||
CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (
|
||||
CSMDoc::Document& document, QObject *parent) const
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent) const
|
||||
{
|
||||
return new VarTypeDelegate (mValues, document, parent);
|
||||
return new VarTypeDelegate (mValues, dispatcher, document, parent);
|
||||
}
|
||||
|
||||
void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace CSVWorld
|
|||
public:
|
||||
|
||||
VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
|
||||
CSMDoc::Document& document, QObject *parent);
|
||||
CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent);
|
||||
};
|
||||
|
||||
class VarTypeDelegateFactory : public CommandDelegateFactory
|
||||
|
@ -30,7 +30,8 @@ namespace CSVWorld
|
|||
ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown,
|
||||
ESM::VarType type3 = ESM::VT_Unknown);
|
||||
|
||||
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
|
||||
virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher,
|
||||
CSMDoc::Document& document, QObject *parent) const;
|
||||
///< The ownership of the returned CommandDelegate is transferred to the caller.
|
||||
|
||||
void add (ESM::VarType type);
|
||||
|
|
|
@ -4,13 +4,34 @@
|
|||
#include "esmreader.hpp"
|
||||
#include "esmwriter.hpp"
|
||||
|
||||
void ESM::CellRef::load (ESMReader& esm, bool wideRefNum)
|
||||
void ESM::RefNum::load (ESMReader& esm, bool wide)
|
||||
{
|
||||
loadId(esm, wideRefNum);
|
||||
if (wide)
|
||||
esm.getHNT (*this, "FRMR", 8);
|
||||
else
|
||||
esm.getHNT (mIndex, "FRMR");
|
||||
}
|
||||
|
||||
void ESM::RefNum::save (ESMWriter &esm, bool wide, const std::string& tag) const
|
||||
{
|
||||
if (wide)
|
||||
esm.writeHNT (tag, *this, 8);
|
||||
else
|
||||
{
|
||||
int refNum = (mIndex & 0xffffff) | ((hasContentFile() ? mContentFile : 0xff)<<24);
|
||||
|
||||
esm.writeHNT (tag, refNum, 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ESM::CellRef::load (ESMReader& esm, bool wideRefNum, bool ignoreRefNum)
|
||||
{
|
||||
loadId(esm, wideRefNum, ignoreRefNum);
|
||||
loadData(esm);
|
||||
}
|
||||
|
||||
void ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum)
|
||||
void ESM::CellRef::loadId (ESMReader& esm, bool wideRefNum, bool ignoreRefNum)
|
||||
{
|
||||
// According to Hrnchamd, this does not belong to the actual ref. Instead, it is a marker indicating that
|
||||
// the following refs are part of a "temp refs" section. A temp ref is not being tracked by the moved references system.
|
||||
|
@ -19,10 +40,8 @@ void ESM::CellRef::loadId(ESMReader &esm, bool wideRefNum)
|
|||
if (esm.isNextSub ("NAM0"))
|
||||
esm.skipHSub();
|
||||
|
||||
if (wideRefNum)
|
||||
esm.getHNT (mRefNum, "FRMR", 8);
|
||||
else
|
||||
esm.getHNT (mRefNum.mIndex, "FRMR");
|
||||
if (!ignoreRefNum)
|
||||
mRefNum.load (esm, wideRefNum);
|
||||
|
||||
mRefID = esm.getHNString ("NAME");
|
||||
}
|
||||
|
@ -83,10 +102,7 @@ void ESM::CellRef::loadData(ESMReader &esm)
|
|||
|
||||
void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const
|
||||
{
|
||||
if (wideRefNum)
|
||||
esm.writeHNT ("FRMR", mRefNum, 8);
|
||||
else
|
||||
esm.writeHNT ("FRMR", mRefNum.mIndex, 4);
|
||||
mRefNum.save (esm, wideRefNum);
|
||||
|
||||
esm.writeHNCString("NAME", mRefID);
|
||||
|
||||
|
|
|
@ -16,6 +16,10 @@ namespace ESM
|
|||
unsigned int mIndex;
|
||||
int mContentFile;
|
||||
|
||||
void load (ESMReader& esm, bool wide = false);
|
||||
|
||||
void save (ESMWriter &esm, bool wide = false, const std::string& tag = "FRMR") const;
|
||||
|
||||
enum { RefNum_NoContentFile = -1 };
|
||||
inline bool hasContentFile() const { return mContentFile != RefNum_NoContentFile; }
|
||||
inline void unset() { mIndex = 0; mContentFile = RefNum_NoContentFile; }
|
||||
|
@ -96,9 +100,9 @@ namespace ESM
|
|||
Position mPos;
|
||||
|
||||
/// Calls loadId and loadData
|
||||
void load (ESMReader& esm, bool wideRefNum = false);
|
||||
void load (ESMReader& esm, bool wideRefNum = false, bool ignoreRefNum = false);
|
||||
|
||||
void loadId (ESMReader& esm, bool wideRefNum = false);
|
||||
void loadId (ESMReader& esm, bool wideRefNum = false, bool ignoreRefNum = false);
|
||||
|
||||
/// Implicitly called by load
|
||||
void loadData (ESMReader& esm);
|
||||
|
|
|
@ -168,7 +168,7 @@ std::string Cell::getDescription() const
|
|||
}
|
||||
}
|
||||
|
||||
bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted)
|
||||
bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted, bool ignoreMoves, MovedCellRef *mref)
|
||||
{
|
||||
// TODO: Try and document reference numbering, I don't think this has been done anywhere else.
|
||||
if (!esm.hasMoreSubs())
|
||||
|
@ -176,10 +176,20 @@ bool Cell::getNextRef(ESMReader &esm, CellRef &ref, bool& deleted)
|
|||
|
||||
// NOTE: We should not need this check. It is a safety check until we have checked
|
||||
// more plugins, and how they treat these moved references.
|
||||
if (esm.isNextSub("MVRF")) {
|
||||
// skip rest of cell record (moved references), they are handled elsewhere
|
||||
esm.skipRecord(); // skip MVRF, CNDT
|
||||
return false;
|
||||
if (esm.isNextSub("MVRF"))
|
||||
{
|
||||
if (ignoreMoves)
|
||||
{
|
||||
esm.getHT (mref->mRefNum.mIndex);
|
||||
esm.getHNOT (mref->mTarget, "CNDT");
|
||||
adjustRefNum (mref->mRefNum, esm);
|
||||
}
|
||||
else
|
||||
{
|
||||
// skip rest of cell record (moved references), they are handled elsewhere
|
||||
esm.skipRecord(); // skip MVRF, CNDT
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ref.load (esm);
|
||||
|
|
|
@ -156,7 +156,9 @@ struct Cell
|
|||
All fields of the CellRef struct are overwritten. You can safely
|
||||
reuse one memory location without blanking it between calls.
|
||||
*/
|
||||
static bool getNextRef(ESMReader &esm, CellRef &ref, bool& deleted);
|
||||
/// \param ignoreMoves ignore MVRF record and read reference like a regular CellRef.
|
||||
static bool getNextRef(ESMReader &esm,
|
||||
CellRef &ref, bool& deleted, bool ignoreMoves = false, MovedCellRef *mref = 0);
|
||||
|
||||
/* This fetches an MVRF record, which is used to track moved references.
|
||||
* Since they are comparably rare, we use a separate method for this.
|
||||
|
|
Loading…
Reference in a new issue