diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index 17c2b4dca..d62947df6 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -284,20 +284,6 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) // write references if (references!=mState.getSubRecords().end()) { - // first pass: find highest RefNum - int lastRefNum = -1; - - for (std::vector::const_iterator iter (references->second.begin()); - iter!=references->second.end(); ++iter) - { - const CSMWorld::Record& ref = - mDocument.getData().getReferences().getRecord (*iter); - - if (ref.get().mRefNum.mContentFile==0 && ref.get().mRefNum.mIndex>lastRefNum) - lastRefNum = ref.get().mRefNum.mIndex; - } - - // second pass: write for (std::vector::const_iterator iter (references->second.begin()); iter!=references->second.end(); ++iter) { @@ -307,20 +293,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages) if (ref.mState==CSMWorld::RecordBase::State_Modified || ref.mState==CSMWorld::RecordBase::State_ModifiedOnly) { - if (ref.get().mRefNum.mContentFile==-2) - { - if (lastRefNum>=0xffffff) - throw std::runtime_error ( - "RefNums exhausted in cell: " + cell.get().mId); - - ESM::CellRef ref2 = ref.get(); - ref2.mRefNum.mContentFile = 0; - ref2.mRefNum.mIndex = ++lastRefNum; - - ref2.save (mState.getWriter()); - } - else - ref.get().save (mState.getWriter()); + ref.get().save (mState.getWriter()); } else if (ref.mState==CSMWorld::RecordBase::State_Deleted) { diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index 73dfc9ac0..b93deccb7 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -1918,6 +1918,70 @@ namespace CSMWorld return true; } }; + + template + struct RefNumCounterColumn : public Column + { + RefNumCounterColumn() + : Column (Columns::ColumnId_RefNumCounter, ColumnBase::Display_Integer, 0) + {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.get().mRefNumCounter); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mRefNumCounter = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + + virtual bool isUserEditable() const + { + return false; + } + }; + + template + struct RefNumColumn : public Column + { + RefNumColumn() + : Column (Columns::ColumnId_RefNum, ColumnBase::Display_Integer, 0) + {} + + virtual QVariant get (const Record& record) const + { + return static_cast (record.get().mRefNum.mIndex); + } + + virtual void set (Record& record, const QVariant& data) + { + ESXRecordT record2 = record.get(); + + record2.mRefNum.mIndex = data.toInt(); + + record.setModified (record2); + } + + virtual bool isEditable() const + { + return true; + } + + virtual bool isUserEditable() const + { + return false; + } + }; } #endif diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index 7d789e2f7..90af20059 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -184,6 +184,8 @@ namespace CSMWorld { ColumnId_DefaultProfile, "Default Profile" }, { ColumnId_BypassNewGame, "Bypass New Game" }, { ColumnId_GlobalProfile, "Global Profile" }, + { ColumnId_RefNumCounter, "RefNum Counter" }, + { ColumnId_RefNum, "RefNum" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index a1ddaabec..5da1765a4 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -177,6 +177,8 @@ namespace CSMWorld ColumnId_DefaultProfile = 165, ColumnId_BypassNewGame = 166, ColumnId_GlobalProfile = 167, + ColumnId_RefNumCounter = 168, + ColumnId_RefNum = 169, // Allocated to a separate value range, so we don't get a collision should we ever need // to extend the number of use values. diff --git a/apps/opencs/model/world/commands.cpp b/apps/opencs/model/world/commands.cpp index b60ffeb29..de0e9a4e5 100644 --- a/apps/opencs/model/world/commands.cpp +++ b/apps/opencs/model/world/commands.cpp @@ -10,13 +10,12 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI const QVariant& new_, QUndoCommand* parent) : QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) { - mOld = mModel.data (mIndex, Qt::EditRole); - setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); } void CSMWorld::ModifyCommand::redo() { + mOld = mModel.data (mIndex, Qt::EditRole); mModel.setData (mIndex, mNew); } @@ -25,6 +24,13 @@ void CSMWorld::ModifyCommand::undo() mModel.setData (mIndex, mOld); } + +void CSMWorld::CreateCommand::applyModifications() +{ + for (std::map::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter) + mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second); +} + CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent) : QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None) { @@ -44,9 +50,7 @@ void CSMWorld::CreateCommand::setType (UniversalId::Type type) void CSMWorld::CreateCommand::redo() { mModel.addRecord (mId, mType); - - for (std::map::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter) - mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second); + applyModifications(); } void CSMWorld::CreateCommand::undo() @@ -148,27 +152,22 @@ void CSMWorld::ReorderRowsCommand::undo() CSMWorld::CloneCommand::CloneCommand (CSMWorld::IdTable& model, const std::string& idOrigin, - const std::string& IdDestination, + const std::string& idDestination, const CSMWorld::UniversalId::Type type, - QUndoCommand* parent) : - QUndoCommand (parent), - mModel (model), - mIdOrigin (idOrigin), - mIdDestination (Misc::StringUtils::lowerCase (IdDestination)), - mType (type) + QUndoCommand* parent) +: CreateCommand (model, idDestination, parent), mIdOrigin (idOrigin) { - setText ( ("Clone record " + idOrigin + " to the " + IdDestination).c_str()); + setType (type); + setText ( ("Clone record " + idOrigin + " to the " + idDestination).c_str()); } void CSMWorld::CloneCommand::redo() { - mModel.cloneRecord (mIdOrigin, mIdDestination, mType); - - for (std::map::const_iterator iter (mValues.begin()); iter != mValues.end(); ++iter) - mModel.setData (mModel.getModelIndex (mIdDestination, iter->first), iter->second); + mModel.cloneRecord (mIdOrigin, mId, mType); + applyModifications(); } void CSMWorld::CloneCommand::undo() { - mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row()); + mModel.removeRow (mModel.getModelIndex (mId, 0).row()); } \ No newline at end of file diff --git a/apps/opencs/model/world/commands.hpp b/apps/opencs/model/world/commands.hpp index 947be68fd..a15c071a8 100644 --- a/apps/opencs/model/world/commands.hpp +++ b/apps/opencs/model/world/commands.hpp @@ -39,32 +39,20 @@ namespace CSMWorld virtual void undo(); }; - class CloneCommand : public QUndoCommand - { - IdTable& mModel; - std::string mIdOrigin; - std::string mIdDestination; - UniversalId::Type mType; - std::map mValues; - - public: - - CloneCommand (IdTable& model, const std::string& idOrigin, - const std::string& IdDestination, - const UniversalId::Type type, - QUndoCommand* parent = 0); - - virtual void redo(); - - virtual void undo(); - }; - class CreateCommand : public QUndoCommand { + std::map mValues; + + protected: + IdTable& mModel; std::string mId; UniversalId::Type mType; - std::map mValues; + + protected: + + /// Apply modifications set via addValue. + void applyModifications(); public: @@ -79,6 +67,22 @@ namespace CSMWorld virtual void undo(); }; + class CloneCommand : public CreateCommand + { + std::string mIdOrigin; + + public: + + CloneCommand (IdTable& model, const std::string& idOrigin, + const std::string& IdDestination, + const UniversalId::Type type, + QUndoCommand* parent = 0); + + virtual void redo(); + + virtual void undo(); + }; + class RevertCommand : public QUndoCommand { IdTable& mModel; diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index ec69b46bb..bb4fa0b43 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -200,6 +200,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new RegionColumn); + mCells.addColumn (new RefNumCounterColumn); mEnchantments.addColumn (new StringIdColumn); mEnchantments.addColumn (new RecordStateColumn); @@ -251,6 +252,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRefs.addColumn (new KeyColumn); mRefs.addColumn (new TrapColumn); mRefs.addColumn (new OwnerGlobalColumn); + mRefs.addColumn (new RefNumColumn); mFilters.addColumn (new StringIdColumn); mFilters.addColumn (new RecordStateColumn); diff --git a/apps/opencs/model/world/ref.cpp b/apps/opencs/model/world/ref.cpp index d1bd771f8..f3c1b0b73 100644 --- a/apps/opencs/model/world/ref.cpp +++ b/apps/opencs/model/world/ref.cpp @@ -4,7 +4,5 @@ CSMWorld::CellRef::CellRef() { mRefNum.mIndex = 0; - - // special marker: This reference does not have a RefNum assign to it yet. - mRefNum.mContentFile = -2; + mRefNum.mContentFile = 0; } \ No newline at end of file diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index e905cfef6..7beaf9c67 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -50,11 +50,22 @@ std::string CSVWorld::GenericCreator::getId() const void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {} +void CSVWorld::GenericCreator::pushCommand (std::auto_ptr command, + const std::string& id) +{ + mUndoStack.push (command.release()); +} + CSMWorld::Data& CSVWorld::GenericCreator::getData() const { return mData; } +QUndoStack& CSVWorld::GenericCreator::getUndoStack() +{ + return mUndoStack; +} + const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const { return mListId; @@ -173,24 +184,23 @@ void CSVWorld::GenericCreator::create() { std::string id = getId(); + std::auto_ptr command; + if (mCloneMode) { - std::auto_ptr command (new CSMWorld::CloneCommand ( + command.reset (new CSMWorld::CloneCommand ( dynamic_cast (*mData.getTableModel(mListId)), mClonedId, id, mClonedType)); - - mUndoStack.push(command.release()); - } else { - std::auto_ptr command (new CSMWorld::CreateCommand ( - dynamic_cast (*mData.getTableModel (mListId)), id)); + command.reset (new CSMWorld::CreateCommand ( + dynamic_cast (*mData.getTableModel (mListId)), id)); - configureCreateCommand (*command); - - mUndoStack.push (command.release()); } + configureCreateCommand (*command); + pushCommand (command, id); + emit done(); emit requestFocus(id); } diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index ea099248e..8d9e32966 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -1,6 +1,12 @@ #ifndef CSV_WORLD_GENERICCREATOR_H #define CSV_WORLD_GENERICCREATOR_H +#include + +#include "../../model/world/universalid.hpp" + +#include "creator.hpp" + class QString; class QPushButton; class QLineEdit; @@ -8,10 +14,6 @@ class QHBoxLayout; class QComboBox; class QLabel; -#include "creator.hpp" - -#include "../../model/world/universalid.hpp" - namespace CSMWorld { class CreateCommand; @@ -56,10 +58,18 @@ namespace CSVWorld virtual std::string getId() const; + /// Allow subclasses to add additional data to \a command. virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const; + /// Allow subclasses to wrap the create command together with additional commands + /// into a macro. + virtual void pushCommand (std::auto_ptr command, + const std::string& id); + CSMWorld::Data& getData() const; + QUndoStack& getUndoStack(); + const CSMWorld::UniversalId& getCollectionId() const; std::string getNamespace() const; diff --git a/apps/opencs/view/world/infocreator.cpp b/apps/opencs/view/world/infocreator.cpp index f09222930..1d914716b 100644 --- a/apps/opencs/view/world/infocreator.cpp +++ b/apps/opencs/view/world/infocreator.cpp @@ -53,6 +53,22 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, connect (mTopic, SIGNAL (textChanged (const QString&)), this, SLOT (topicChanged())); } +void CSVWorld::InfoCreator::cloneMode (const std::string& originId, + const CSMWorld::UniversalId::Type type) +{ + CSMWorld::IdTable& infoTable = + dynamic_cast (*getData().getTableModel (getCollectionId())); + + int topicColumn = infoTable.findColumnIndex ( + getCollectionId().getType()==CSMWorld::UniversalId::Type_TopicInfos ? + CSMWorld::Columns::ColumnId_Topic : CSMWorld::Columns::ColumnId_Journal); + + mTopic->setText ( + infoTable.data (infoTable.getModelIndex (originId, topicColumn)).toString()); + + GenericCreator::cloneMode (originId, type); +} + void CSVWorld::InfoCreator::reset() { mTopic->setText (""); diff --git a/apps/opencs/view/world/infocreator.hpp b/apps/opencs/view/world/infocreator.hpp index e9cb7e596..2296a8297 100644 --- a/apps/opencs/view/world/infocreator.hpp +++ b/apps/opencs/view/world/infocreator.hpp @@ -27,6 +27,9 @@ namespace CSVWorld InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); + virtual void cloneMode (const std::string& originId, + const CSMWorld::UniversalId::Type type); + virtual void reset(); virtual std::string getErrors() const; diff --git a/apps/opencs/view/world/referenceablecreator.cpp b/apps/opencs/view/world/referenceablecreator.cpp index 7a5fca853..e8055ed31 100644 --- a/apps/opencs/view/world/referenceablecreator.cpp +++ b/apps/opencs/view/world/referenceablecreator.cpp @@ -42,6 +42,13 @@ void CSVWorld::ReferenceableCreator::reset() GenericCreator::reset(); } +void CSVWorld::ReferenceableCreator::cloneMode (const std::string& originId, + const CSMWorld::UniversalId::Type type) +{ + GenericCreator::cloneMode (originId, type); + mType->setCurrentIndex (mType->findData (static_cast (type))); +} + void CSVWorld::ReferenceableCreator::toggleWidgets(bool active) { CSVWorld::GenericCreator::toggleWidgets(active); diff --git a/apps/opencs/view/world/referenceablecreator.hpp b/apps/opencs/view/world/referenceablecreator.hpp index 88545575e..14ad24b29 100644 --- a/apps/opencs/view/world/referenceablecreator.hpp +++ b/apps/opencs/view/world/referenceablecreator.hpp @@ -23,6 +23,10 @@ namespace CSVWorld const CSMWorld::UniversalId& id); virtual void reset(); + + virtual void cloneMode (const std::string& originId, + const CSMWorld::UniversalId::Type type); + virtual void toggleWidgets(bool active = true); }; diff --git a/apps/opencs/view/world/referencecreator.cpp b/apps/opencs/view/world/referencecreator.cpp index 6b8e02da0..1e3cc00d7 100644 --- a/apps/opencs/view/world/referencecreator.cpp +++ b/apps/opencs/view/world/referencecreator.cpp @@ -16,11 +16,58 @@ std::string CSVWorld::ReferenceCreator::getId() const void CSVWorld::ReferenceCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const { - int index = + // Set cellID + int cellIdColumn = dynamic_cast (*getData().getTableModel (getCollectionId())). findColumnIndex (CSMWorld::Columns::ColumnId_Cell); - command.addValue (index, mCell->text()); + command.addValue (cellIdColumn, mCell->text()); + + // Set RefNum + int refNumColumn = dynamic_cast ( + *getData().getTableModel (CSMWorld::UniversalId::Type_References)). + findColumnIndex (CSMWorld::Columns::ColumnId_RefNum); + + command.addValue (refNumColumn, getRefNumCount()); +} + +void CSVWorld::ReferenceCreator::pushCommand (std::auto_ptr command, + const std::string& id) +{ + // get the old count + std::string cellId = mCell->text().toUtf8().constData(); + + CSMWorld::IdTable& cellTable = dynamic_cast ( + *getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + + int countColumn = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter); + + QModelIndex countIndex = cellTable.getModelIndex (cellId, countColumn); + + int count = cellTable.data (countIndex).toInt(); + + // command for incrementing counter + std::auto_ptr increment (new CSMWorld::ModifyCommand + (cellTable, countIndex, count+1)); + + getUndoStack().beginMacro (command->text()); + GenericCreator::pushCommand (command, id); + getUndoStack().push (increment.release()); + getUndoStack().endMacro(); +} + +int CSVWorld::ReferenceCreator::getRefNumCount() const +{ + std::string cellId = mCell->text().toUtf8().constData(); + + CSMWorld::IdTable& cellTable = dynamic_cast ( + *getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); + + int countColumn = cellTable.findColumnIndex (CSMWorld::Columns::ColumnId_RefNumCounter); + + QModelIndex countIndex = cellTable.getModelIndex (cellId, countColumn); + + return cellTable.data (countIndex).toInt(); } CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack, @@ -47,12 +94,9 @@ void CSVWorld::ReferenceCreator::reset() std::string CSVWorld::ReferenceCreator::getErrors() const { - std::string errors = GenericCreator::getErrors(); - - if (mCloneMode) - { - return errors; - } + // We are ignoring errors coming from GenericCreator here, because the ID of the new + // record is internal and requires neither user input nor verification. + std::string errors; std::string cell = mCell->text().toUtf8().constData(); @@ -79,15 +123,17 @@ void CSVWorld::ReferenceCreator::cellChanged() update(); } -void CSVWorld::ReferenceCreator::toggleWidgets(bool active) -{ - CSVWorld::GenericCreator::toggleWidgets(active); - mCell->setEnabled(active); -} - void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type) { + CSMWorld::IdTable& referenceTable = dynamic_cast ( + *getData().getTableModel (CSMWorld::UniversalId::Type_References)); + + int cellIdColumn = referenceTable.findColumnIndex (CSMWorld::Columns::ColumnId_Cell); + + mCell->setText ( + referenceTable.data (referenceTable.getModelIndex (originId, cellIdColumn)).toString()); + CSVWorld::GenericCreator::cloneMode(originId, type); cellChanged(); //otherwise ok button will remain disabled } diff --git a/apps/opencs/view/world/referencecreator.hpp b/apps/opencs/view/world/referencecreator.hpp index 12fb12dd9..002a62d87 100644 --- a/apps/opencs/view/world/referencecreator.hpp +++ b/apps/opencs/view/world/referencecreator.hpp @@ -20,16 +20,20 @@ namespace CSVWorld virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const; + virtual void pushCommand (std::auto_ptr command, + const std::string& id); + + int getRefNumCount() const; + public: ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id); - virtual void cloneMode(const std::string& originId, + virtual void cloneMode(const std::string& originId, const CSMWorld::UniversalId::Type type); virtual void reset(); - virtual void toggleWidgets(bool active = true); virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty