Merge remote-tracking branch 'cc9cii/moveref'

test
Marc Zinnschlag 10 years ago
commit f1c0847897

@ -231,8 +231,29 @@ void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages)
record.mState==CSMWorld::RecordBase::State_Modified || record.mState==CSMWorld::RecordBase::State_Modified ||
record.mState==CSMWorld::RecordBase::State_ModifiedOnly) record.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mCell)] std::string cellId = record.get().mOriginalCell.empty() ?
.push_back (i); 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 = const CSMWorld::Record<CSMWorld::Cell>& cell =
mDocument.getData().getCells().getRecord (stage); 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)); mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId));
if (cell.mState==CSMWorld::RecordBase::State_Modified || if (cell.mState==CSMWorld::RecordBase::State_Modified ||
@ -284,7 +305,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
// write references // write references
if (references!=mState.getSubRecords().end()) 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) iter!=references->second.end(); ++iter)
{ {
const CSMWorld::Record<CSMWorld::CellRef>& ref = 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 || if (ref.mState==CSMWorld::RecordBase::State_Modified ||
ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) 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()); ref.get().save (mState.getWriter());
} }
else if (ref.mState==CSMWorld::RecordBase::State_Deleted) else if (ref.mState==CSMWorld::RecordBase::State_Deleted)

@ -64,7 +64,7 @@ bool CSMDoc::SavingState::isProjectFile() const
return mProjectFile; return mProjectFile;
} }
std::map<std::string, std::vector<int> >& CSMDoc::SavingState::getSubRecords() std::map<std::string, std::deque<int> >& CSMDoc::SavingState::getSubRecords()
{ {
return mSubRecords; return mSubRecords;
} }

@ -3,6 +3,7 @@
#include <fstream> #include <fstream>
#include <map> #include <map>
#include <deque>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
@ -26,7 +27,7 @@ namespace CSMDoc
ESM::ESMWriter mWriter; ESM::ESMWriter mWriter;
boost::filesystem::path mProjectPath; boost::filesystem::path mProjectPath;
bool mProjectFile; 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: public:
@ -49,7 +50,7 @@ namespace CSMDoc
bool isProjectFile() const; bool isProjectFile() const;
///< Currently saving project file? (instead of content file) ///< 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 enum Roles
{ {
Role_Flags = Qt::UserRole, Role_Flags = Qt::UserRole,
Role_Display = Qt::UserRole+1 Role_Display = Qt::UserRole+1,
Role_ColumnId = Qt::UserRole+2
}; };
enum Flags enum Flags

@ -870,7 +870,13 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct CellColumn : public Column<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 virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -892,9 +898,41 @@ namespace CSMWorld
} }
virtual bool isUserEditable() const 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; return true;
} }
virtual bool isUserEditable() const
{
return false;
}
}; };
template<typename ESXRecordT> template<typename ESXRecordT>

@ -222,6 +222,7 @@ namespace CSMWorld
{ ColumnId_HitSound, "Hit Sound" }, { ColumnId_HitSound, "Hit Sound" },
{ ColumnId_AreaSound, "Area Sound" }, { ColumnId_AreaSound, "Area Sound" },
{ ColumnId_BoltSound, "Bolt Sound" }, { ColumnId_BoltSound, "Bolt Sound" },
{ ColumnId_OriginalCell, "Original Cell" },
{ ColumnId_PathgridPoints, "Points" }, { ColumnId_PathgridPoints, "Points" },
{ ColumnId_PathgridIndex, "Index" }, { ColumnId_PathgridIndex, "Index" },

@ -264,6 +264,8 @@ namespace CSMWorld
ColumnId_InfoList = 240, ColumnId_InfoList = 240,
ColumnId_OriginalCell = 241,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.
ColumnId_UseValue1 = 0x10000, ColumnId_UseValue1 = 0x10000,

@ -2,6 +2,7 @@
#include "commanddispatcher.hpp" #include "commanddispatcher.hpp"
#include <algorithm> #include <algorithm>
#include <memory>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
@ -10,6 +11,7 @@
#include "idtable.hpp" #include "idtable.hpp"
#include "record.hpp" #include "record.hpp"
#include "commands.hpp" #include "commands.hpp"
#include "idtableproxymodel.hpp"
std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const
{ {
@ -131,6 +133,54 @@ std::vector<CSMWorld::UniversalId> CSMWorld::CommandDispatcher::getExtendedTypes
return tables; 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() void CSMWorld::CommandDispatcher::executeDelete()
{ {
if (mLocked) if (mLocked)

@ -7,6 +7,9 @@
#include "universalid.hpp" #include "universalid.hpp"
class QModelIndex;
class QAbstractItemModel;
namespace CSMDoc namespace CSMDoc
{ {
class Document; class Document;
@ -53,6 +56,12 @@ namespace CSMWorld
/// the extended mode, the returned vector will be empty instead. /// the extended mode, the returned vector will be empty instead.
std::vector<UniversalId> getExtendedTypes() const; 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: public slots:
void executeDelete(); void executeDelete();

@ -1,5 +1,8 @@
#include "commands.hpp" #include "commands.hpp"
#include <cmath>
#include <sstream>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <QAbstractItemModel> #include <QAbstractItemModel>
@ -183,6 +186,47 @@ void CSMWorld::CloneCommand::undo()
mModel.removeRow (mModel.getModelIndex (mId, 0).row()); 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, CSMWorld::DeleteNestedCommand::DeleteNestedCommand (IdTree& model,
const std::string& id, const std::string& id,
int nestedRow, int nestedRow,

@ -144,6 +144,29 @@ namespace CSMWorld
virtual void undo(); 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 class NestedTableStoring
{ {
NestedTableWrapperBase* mOld; NestedTableWrapperBase* mOld;

@ -368,7 +368,8 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mRefs.addColumn (new StringIdColumn<CellRef> (true)); mRefs.addColumn (new StringIdColumn<CellRef> (true));
mRefs.addColumn (new RecordStateColumn<CellRef>); mRefs.addColumn (new RecordStateColumn<CellRef>);
mRefs.addColumn (new FixedRecordTypeColumn<CellRef> (UniversalId::Type_Reference)); 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 IdColumn<CellRef>);
mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false)); mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 0, false));
mRefs.addColumn (new PosColumn<CellRef> (&CellRef::mPos, 1, 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); UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)), addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video); UniversalId::Type_Video);
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
} }
CSMWorld::Data::~Data() CSMWorld::Data::~Data()
@ -778,7 +781,6 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
mReader = 0; mReader = 0;
mDialogue = 0; mDialogue = 0;
mRefLoadCache.clear();
mReader = new ESM::ESMReader; mReader = new ESM::ESMReader;
mReader->setEncoder (&mEncoder); mReader->setEncoder (&mEncoder);
@ -815,7 +817,6 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
mReader = 0; mReader = 0;
mDialogue = 0; mDialogue = 0;
mRefLoadCache.clear();
return true; return true;
} }
@ -860,9 +861,16 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
case ESM::REC_CELL: case ESM::REC_CELL:
{ {
mCells.load (*mReader, mBase); int index = mCells.load (*mReader, mBase);
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1)); if (index < 0 || index >= mCells.getSize())
mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages); {
// 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; break;
} }

@ -74,6 +74,15 @@ namespace CSMWorld
{ {
ESXRecordT record; 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); int index = this->searchId (id);
if (index==-1) if (index==-1)

@ -28,9 +28,15 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const
return mIdCollection->getColumns(); 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(); return QVariant();
if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) 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) if (role==ColumnBase::Role_Display)
return mIdCollection->getColumn (section).mDisplayType; return mIdCollection->getColumn (section).mDisplayType;
if (role==ColumnBase::Role_ColumnId)
return getColumnId (section);
return QVariant(); return QVariant();
} }

@ -1,8 +1,18 @@
#include "ref.hpp" #include "ref.hpp"
#include <cmath>
CSMWorld::CellRef::CellRef() CSMWorld::CellRef::CellRef()
{ {
mRefNum.mIndex = 0; mRefNum.mIndex = 0;
mRefNum.mContentFile = 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 #ifndef CSM_WOLRD_REF_H
#define CSM_WOLRD_REF_H #define CSM_WOLRD_REF_H
#include <utility>
#include <components/esm/cellref.hpp> #include <components/esm/cellref.hpp>
namespace CSMWorld namespace CSMWorld
@ -10,8 +12,12 @@ namespace CSMWorld
{ {
std::string mId; std::string mId;
std::string mCell; std::string mCell;
std::string mOriginalCell;
CellRef(); CellRef();
/// Calculate cell index based on coordinates (x and y)
std::pair<int, int> getCellIndex() const;
}; };
} }

@ -2,8 +2,10 @@
#include "refcollection.hpp" #include "refcollection.hpp"
#include <sstream> #include <sstream>
#include <iostream>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/esm/loadcell.hpp>
#include "ref.hpp" #include "ref.hpp"
#include "cell.hpp" #include "cell.hpp"
@ -20,14 +22,75 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
CellRef ref; CellRef ref;
bool deleted = false; 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::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;
std::map<ESM::RefNum, std::string>::iterator iter = cache.find (ref.mRefNum); // 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) if (deleted)
{ {

@ -27,8 +27,7 @@ namespace CSMWorld
{} {}
void load (ESM::ESMReader& reader, int cellIndex, bool base, void load (ESM::ESMReader& reader, int cellIndex, bool base,
std::map<ESM::RefNum, std::string>& cache, std::map<ESM::RefNum, std::string>& cache, CSMDoc::Messages& messages);
CSMDoc::Messages& messages);
///< Load a sequence of references. ///< Load a sequence of references.
std::string getNewId(); std::string getNewId();

@ -131,8 +131,8 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
setModel (mModel); setModel (mModel);
setColumnHidden (2, true); setColumnHidden (2, true);
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate ( mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (0,
document, this); mDocument, this);
setItemDelegateForColumn (0, mIdTypeDelegate); setItemDelegateForColumn (0, mIdTypeDelegate);

@ -6,11 +6,12 @@
CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
const IconList &icons, const IconList &icons,
CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document, CSMDoc::Document& document,
const QString &pageName, const QString &pageName,
const QString &settingName, const QString &settingName,
QObject *parent) 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), mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3),
mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName) mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName)
{ {
@ -136,9 +137,9 @@ void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName,
} }
CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate ( 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; QString mSettingKey;
public: public:
explicit DataDisplayDelegate (const ValueList & values, DataDisplayDelegate (const ValueList & values, const IconList & icons,
const IconList & icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document,
CSMDoc::Document& document, const QString &pageName, const QString &settingName, QObject *parent);
const QString &pageName,
const QString &settingName,
QObject *parent);
~DataDisplayDelegate(); ~DataDisplayDelegate();
@ -82,7 +79,7 @@ namespace CSVWorld
public: 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. ///< The ownership of the returned CommandDelegate is transferred to the caller.
protected: protected:

@ -177,10 +177,11 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::
*/ */
CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, 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), mParent(parent),
mTable(model ? model : table), mTable(model ? model : table),
mDocument (document), mCommandDispatcher (commandDispatcher), mDocument (document),
mNotEditableDelegate(table, parent) mNotEditableDelegate(table, parent)
{ {
} }
@ -192,7 +193,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS
if (delegateIt == mDelegates.end()) if (delegateIt == mDelegates.end())
{ {
delegate = CommandDelegateFactoryCollection::get().makeDelegate ( delegate = CommandDelegateFactoryCollection::get().makeDelegate (
display, mDocument, mParent); display, &mCommandDispatcher, mDocument, mParent);
mDelegates.insert(std::make_pair(display, delegate)); mDelegates.insert(std::make_pair(display, delegate));
} else } else
{ {
@ -352,13 +353,16 @@ CSVWorld::EditWidget::~EditWidget()
delete mNestedTableDispatcher; delete mNestedTableDispatcher;
} }
CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : CSVWorld::EditWidget::EditWidget(QWidget *parent,
mDispatcher(this, table, document), int row, CSMWorld::IdTable* table, CSMWorld::CommandDispatcher& commandDispatcher,
CSMDoc::Document& document, bool createAndDelete) :
mDispatcher(this, table, commandDispatcher, document),
mNestedTableDispatcher(NULL), mNestedTableDispatcher(NULL),
QScrollArea(parent), QScrollArea(parent),
mWidgetMapper(NULL), mWidgetMapper(NULL),
mNestedTableMapper(NULL), mNestedTableMapper(NULL),
mMainWidget(NULL), mMainWidget(NULL),
mCommandDispatcher (commandDispatcher),
mDocument (document), mDocument (document),
mTable(table) 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))); 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 // FIXME: does not work well when enum delegates are used
//table->resizeColumnsToContents(); //table->resizeColumnsToContents();
table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged); table->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::CurrentChanged);
@ -499,7 +510,7 @@ void CSVWorld::EditWidget::remake(int row)
mNestedTableMapper->setModel(mNestedModels.back()); mNestedTableMapper->setModel(mNestedModels.back());
// FIXME: lack MIME support? // FIXME: lack MIME support?
mNestedTableDispatcher = mNestedTableDispatcher =
new DialogueDelegateDispatcher (this, mTable, mDocument, mNestedModels.back()); new DialogueDelegateDispatcher (this, mTable, mCommandDispatcher, mDocument, mNestedModels.back());
mNestedTableMapper->setItemDelegate(mNestedTableDispatcher); mNestedTableMapper->setItemDelegate(mNestedTableDispatcher);
int columnCount = int columnCount =
@ -626,7 +637,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
mMainLayout = new QVBoxLayout(mainWidget); 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*)), 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*))); this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));

@ -109,6 +109,7 @@ namespace CSVWorld
QAbstractItemModel* mTable; QAbstractItemModel* mTable;
CSMWorld::CommandDispatcher& mCommandDispatcher;
CSMDoc::Document& mDocument; CSMDoc::Document& mDocument;
NotEditableSubDelegate mNotEditableDelegate; NotEditableSubDelegate mNotEditableDelegate;
@ -119,6 +120,7 @@ namespace CSVWorld
public: public:
DialogueDelegateDispatcher(QObject* parent, DialogueDelegateDispatcher(QObject* parent,
CSMWorld::IdTable* table, CSMWorld::IdTable* table,
CSMWorld::CommandDispatcher& commandDispatcher,
CSMDoc::Document& document, CSMDoc::Document& document,
QAbstractItemModel* model = 0); QAbstractItemModel* model = 0);
@ -167,12 +169,14 @@ namespace CSVWorld
DialogueDelegateDispatcher *mNestedTableDispatcher; DialogueDelegateDispatcher *mNestedTableDispatcher;
QWidget* mMainWidget; QWidget* mMainWidget;
CSMWorld::IdTable* mTable; CSMWorld::IdTable* mTable;
CSMWorld::CommandDispatcher& mCommandDispatcher;
CSMDoc::Document& mDocument; CSMDoc::Document& mDocument;
std::vector<CSMWorld::NestedTableProxyModel*> mNestedModels; //Plain, raw C pointers, deleted in the dtor std::vector<CSMWorld::NestedTableProxyModel*> mNestedModels; //Plain, raw C pointers, deleted in the dtor
public: public:
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table,
CSMWorld::CommandDispatcher& commandDispatcher,
CSMDoc::Document& document, bool createAndDelete = false); CSMDoc::Document& document, bool createAndDelete = false);
virtual ~EditWidget(); virtual ~EditWidget();

@ -37,8 +37,8 @@ void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model,
CSVWorld::EnumDelegate::EnumDelegate (const std::vector<std::pair<int, QString> >& values, CSVWorld::EnumDelegate::EnumDelegate (const std::vector<std::pair<int, QString> >& values,
CSMDoc::Document& document, QObject *parent) CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
: CommandDelegate (document, parent), mValues (values) : CommandDelegate (dispatcher, document, parent), mValues (values)
{ {
} }
@ -142,9 +142,9 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector<std::strin
} }
CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate ( 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) void CSVWorld::EnumDelegateFactory::add (int value, const QString& name)

@ -30,7 +30,7 @@ namespace CSVWorld
public: public:
EnumDelegate (const std::vector<std::pair<int, QString> >& values, 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, virtual QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem& option, const QStyleOptionViewItem& option,
@ -64,7 +64,7 @@ namespace CSVWorld
EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false); EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false);
/// \param allowNone Use value of -1 for "none selected" (empty string) /// \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. ///< The ownership of the returned CommandDelegate is transferred to the caller.
void add (int value, const QString& name); void add (int value, const QString& name);

@ -3,8 +3,8 @@
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
CSVWorld::IdTypeDelegate::IdTypeDelegate CSVWorld::IdTypeDelegate::IdTypeDelegate
(const ValueList &values, const IconList &icons, CSMDoc::Document& document, QObject *parent) (const ValueList &values, const IconList &icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
: DataDisplayDelegate (values, icons, document, : DataDisplayDelegate (values, icons, dispatcher, document,
"records", "type-format", "records", "type-format",
parent) parent)
{} {}
@ -21,7 +21,7 @@ CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory()
} }
CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate ( 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 class IdTypeDelegate : public DataDisplayDelegate
{ {
public: 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 class IdTypeDelegateFactory : public DataDisplayDelegateFactory
@ -20,7 +20,7 @@ namespace CSVWorld
IdTypeDelegateFactory(); 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. ///< The ownership of the returned CommandDelegate is transferred to the caller.
}; };
} }

@ -2,6 +2,7 @@
#include "../../model/world/nestedtableproxymodel.hpp" #include "../../model/world/nestedtableproxymodel.hpp"
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/commanddispatcher.hpp"
#include "util.hpp" #include "util.hpp"
#include <QHeaderView> #include <QHeaderView>
@ -10,12 +11,14 @@
#include <QDebug> #include <QDebug>
CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document, CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
CSMWorld::UniversalId id,
CSMWorld::NestedTableProxyModel* model, CSMWorld::NestedTableProxyModel* model,
QWidget* parent) QWidget* parent)
: QTableView(parent), : QTableView(parent),
mUndoStack(document.getUndoStack()), mUndoStack(document.getUndoStack()),
mModel(model) mModel(model)
{ {
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
setSelectionBehavior (QAbstractItemView::SelectRows); setSelectionBehavior (QAbstractItemView::SelectRows);
setSelectionMode (QAbstractItemView::ExtendedSelection); setSelectionMode (QAbstractItemView::ExtendedSelection);
@ -31,6 +34,7 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); model->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display, CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate(display,
mDispatcher,
document, document,
this); this);

@ -12,6 +12,7 @@ namespace CSMWorld
{ {
class NestedTableProxyModel; class NestedTableProxyModel;
class UniversalId; class UniversalId;
class CommandDispatcher;
} }
namespace CSMDoc namespace CSMDoc
@ -29,9 +30,11 @@ namespace CSVWorld
QAction *mRemoveRowAction; QAction *mRemoveRowAction;
QUndoStack& mUndoStack; QUndoStack& mUndoStack;
CSMWorld::NestedTableProxyModel* mModel; CSMWorld::NestedTableProxyModel* mModel;
CSMWorld::CommandDispatcher *mDispatcher;
public: public:
NestedTable(CSMDoc::Document& document, NestedTable(CSMDoc::Document& document,
CSMWorld::UniversalId id,
CSMWorld::NestedTableProxyModel* model, CSMWorld::NestedTableProxyModel* model,
QWidget* parent = NULL); QWidget* parent = NULL);

@ -9,16 +9,16 @@
CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values,
const IconList & icons, const IconList & icons,
CSMDoc::Document& document, QObject *parent) CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
: DataDisplayDelegate (values, icons, document, : DataDisplayDelegate (values, icons, dispatcher, document,
"records", "status-format", "records", "status-format",
parent) parent)
{} {}
CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate ( 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() CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory()

@ -17,9 +17,9 @@ namespace CSVWorld
{ {
public: public:
explicit RecordStatusDelegate(const ValueList& values, RecordStatusDelegate (const ValueList& values, const IconList& icons,
const IconList& icons, CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document,
CSMDoc::Document& document, QObject *parent = 0); QObject *parent = 0);
}; };
class RecordStatusDelegateFactory : public DataDisplayDelegateFactory class RecordStatusDelegateFactory : public DataDisplayDelegateFactory
@ -28,7 +28,7 @@ namespace CSVWorld
RecordStatusDelegateFactory(); 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. ///< 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()); mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display,
mDocument, this); mDispatcher, document, this);
mDelegates.push_back (delegate); mDelegates.push_back (delegate);
setItemDelegateForColumn (i, delegate); setItemDelegateForColumn (i, delegate);

@ -18,6 +18,7 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commanddispatcher.hpp"
#include "scriptedit.hpp" #include "scriptedit.hpp"
@ -82,15 +83,15 @@ void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Disp
} }
CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate ( 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 = std::map<CSMWorld::ColumnBase::Display, CommandDelegateFactory *>::const_iterator iter =
mFactories.find (display); mFactories.find (display);
if (iter!=mFactories.end()) 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() const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get()
@ -115,17 +116,22 @@ CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const
void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const const QModelIndex& index) const
{ {
if (!mCommandDispatcher)
return;
NastyTableModelHack hack (*model); NastyTableModelHack hack (*model);
QStyledItemDelegate::setModelData (editor, &hack, index); QStyledItemDelegate::setModelData (editor, &hack, index);
QVariant new_ = hack.getData(); QVariant new_ = hack.getData();
if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) 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) CSVWorld::CommandDelegate::CommandDelegate (CSMWorld::CommandDispatcher *commandDispatcher,
: QStyledItemDelegate (parent), mDocument (document), mEditLock (false) CSMDoc::Document& document, QObject *parent)
: QStyledItemDelegate (parent), mEditLock (false),
mCommandDispatcher (commandDispatcher), mDocument (document)
{} {}
void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model,

@ -16,6 +16,7 @@ namespace CSMWorld
{ {
class TableMimeData; class TableMimeData;
class UniversalId; class UniversalId;
class CommandDispatcher;
} }
namespace CSVWorld namespace CSVWorld
@ -51,7 +52,8 @@ namespace CSVWorld
virtual ~CommandDelegateFactory(); virtual ~CommandDelegateFactory();
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) virtual CommandDelegate *makeDelegate (CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document, QObject *parent)
const = 0; const = 0;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< 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. /// 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; QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
/// ///
@ -111,8 +114,9 @@ namespace CSVWorld
{ {
Q_OBJECT Q_OBJECT
CSMDoc::Document& mDocument;
bool mEditLock; bool mEditLock;
CSMWorld::CommandDispatcher *mCommandDispatcher;
CSMDoc::Document& mDocument;
protected: protected:
@ -125,7 +129,9 @@ namespace CSVWorld
public: 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, virtual void setModelData (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const; 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, CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
CSMDoc::Document& document, QObject *parent) CSMWorld::CommandDispatcher *dispatcher, CSMDoc::Document& document, QObject *parent)
: EnumDelegate (values, document, parent) : EnumDelegate (values, dispatcher, document, parent)
{} {}
@ -69,9 +69,9 @@ CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0,
} }
CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate ( 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) void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)

@ -17,7 +17,7 @@ namespace CSVWorld
public: public:
VarTypeDelegate (const std::vector<std::pair<int, QString> >& values, 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 class VarTypeDelegateFactory : public CommandDelegateFactory
@ -30,7 +30,8 @@ namespace CSVWorld
ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown,
ESM::VarType type3 = 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. ///< The ownership of the returned CommandDelegate is transferred to the caller.
void add (ESM::VarType type); void add (ESM::VarType type);

@ -4,13 +4,34 @@
#include "esmreader.hpp" #include "esmreader.hpp"
#include "esmwriter.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); 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 // 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. // 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")) if (esm.isNextSub ("NAM0"))
esm.skipHSub(); esm.skipHSub();
if (wideRefNum) if (!ignoreRefNum)
esm.getHNT (mRefNum, "FRMR", 8); mRefNum.load (esm, wideRefNum);
else
esm.getHNT (mRefNum.mIndex, "FRMR");
mRefID = esm.getHNString ("NAME"); 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 void ESM::CellRef::save (ESMWriter &esm, bool wideRefNum, bool inInventory) const
{ {
if (wideRefNum) mRefNum.save (esm, wideRefNum);
esm.writeHNT ("FRMR", mRefNum, 8);
else
esm.writeHNT ("FRMR", mRefNum.mIndex, 4);
esm.writeHNCString("NAME", mRefID); esm.writeHNCString("NAME", mRefID);

@ -16,6 +16,10 @@ namespace ESM
unsigned int mIndex; unsigned int mIndex;
int mContentFile; 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 }; enum { RefNum_NoContentFile = -1 };
inline bool hasContentFile() const { return mContentFile != RefNum_NoContentFile; } inline bool hasContentFile() const { return mContentFile != RefNum_NoContentFile; }
inline void unset() { mIndex = 0; mContentFile = RefNum_NoContentFile; } inline void unset() { mIndex = 0; mContentFile = RefNum_NoContentFile; }
@ -96,9 +100,9 @@ namespace ESM
Position mPos; Position mPos;
/// Calls loadId and loadData /// 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 /// Implicitly called by load
void loadData (ESMReader& esm); 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. // TODO: Try and document reference numbering, I don't think this has been done anywhere else.
if (!esm.hasMoreSubs()) 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 // 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. // more plugins, and how they treat these moved references.
if (esm.isNextSub("MVRF")) { if (esm.isNextSub("MVRF"))
// skip rest of cell record (moved references), they are handled elsewhere {
esm.skipRecord(); // skip MVRF, CNDT if (ignoreMoves)
return false; {
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); ref.load (esm);

@ -156,7 +156,9 @@ struct Cell
All fields of the CellRef struct are overwritten. You can safely All fields of the CellRef struct are overwritten. You can safely
reuse one memory location without blanking it between calls. 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. /* This fetches an MVRF record, which is used to track moved references.
* Since they are comparably rare, we use a separate method for this. * Since they are comparably rare, we use a separate method for this.

Loading…
Cancel
Save