Merge branch 'master' into autocalc

Conflicts:
	apps/opencs/CMakeLists.txt
	apps/opencs/model/world/columns.cpp
	apps/opencs/model/world/columns.hpp
	apps/opencs/model/world/data.hpp
	apps/opencs/view/world/dialoguesubview.cpp
This commit is contained in:
cc9cii 2015-06-27 07:46:36 +10:00
commit 2612a91f8d
38 changed files with 639 additions and 325 deletions

View File

@ -26,7 +26,7 @@ opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
idcompletionmanager npcstats idcompletionmanager npcstats metadata
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world

View File

@ -2282,9 +2282,6 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (mNew) if (mNew)
{ {
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1) if (mContentFiles.size()==1)
createBase(); createBase();
} }
@ -2369,9 +2366,9 @@ void CSMDoc::Document::save()
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
CSMWorld::UniversalId CSMDoc::Document::verify() CSMWorld::UniversalId CSMDoc::Document::verify (const CSMWorld::UniversalId& reportId)
{ {
CSMWorld::UniversalId id = mTools.runVerifier(); CSMWorld::UniversalId id = mTools.runVerifier (reportId);
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
return id; return id;
} }

View File

@ -120,7 +120,7 @@ namespace CSMDoc
void save(); void save();
CSMWorld::UniversalId verify(); CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
CSMWorld::UniversalId newSearch(); CSMWorld::UniversalId newSearch();

View File

@ -53,18 +53,16 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages)
mState.getWriter().clearMaster(); mState.getWriter().clearMaster();
mState.getWriter().setFormat (0);
if (mSimple) if (mSimple)
{ {
mState.getWriter().setAuthor (""); mState.getWriter().setAuthor ("");
mState.getWriter().setDescription (""); mState.getWriter().setDescription ("");
mState.getWriter().setRecordCount (0); mState.getWriter().setRecordCount (0);
mState.getWriter().setFormat (ESM::Header::CurrentFormat);
} }
else else
{ {
mState.getWriter().setAuthor (mDocument.getData().getAuthor()); mDocument.getData().getMetaData().save (mState.getWriter());
mState.getWriter().setDescription (mDocument.getData().getDescription());
mState.getWriter().setRecordCount ( mState.getWriter().setRecordCount (
mDocument.getData().count (CSMWorld::RecordBase::State_Modified) + mDocument.getData().count (CSMWorld::RecordBase::State_Modified) +
mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) + mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) +

View File

@ -30,9 +30,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
// check the number of pathgrid points // check the number of pathgrid points
if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size())) if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
messages.push_back (std::make_pair (id, pathgrid.mId + " has less points than expected")); messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error);
else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size())) else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error);
std::vector<CSMTools::Point> pointList(pathgrid.mPoints.size()); std::vector<CSMTools::Point> pointList(pathgrid.mPoints.size());
std::vector<int> duplList; std::vector<int> duplList;
@ -51,7 +51,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
std::ostringstream ss; std::ostringstream ss;
ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0 ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0
<< " and " << pathgrid.mEdges[i].mV1; << " and " << pathgrid.mEdges[i].mV1;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
break; break;
} }
} }
@ -64,7 +64,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0; ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
} }
@ -75,13 +75,13 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has has less edges than expected for point " << i; ss << " has has less edges than expected for point " << i;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum) else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum)
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has has more edges than expected for point " << i; ss << " has has more edges than expected for point " << i;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
// check that edges are bidirectional // check that edges are bidirectional
@ -101,7 +101,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j];
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
} }
@ -124,7 +124,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX << ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY << ", y=" << pathgrid.mPoints[i].mY
<< ", z=" << pathgrid.mPoints[i].mZ; << ", z=" << pathgrid.mPoints[i].mZ;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning);
duplList.push_back(i); duplList.push_back(i);
break; break;
@ -143,7 +143,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX << ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY << ", y=" << pathgrid.mPoints[i].mY
<< ", z=" << pathgrid.mPoints[i].mZ; << ", z=" << pathgrid.mPoints[i].mZ;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning);
} }
} }

View File

@ -120,7 +120,7 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value) void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value)
{ {
if (name=="script-editor/warnings") if (name=="script-editor/warnings" && !value.isEmpty())
{ {
if (value.at (0)=="Ignore") if (value.at (0)=="Ignore")
mWarningMode = Mode_Ignore; mWarningMode = Mode_Ignore;

View File

@ -146,14 +146,19 @@ CSMTools::Tools::~Tools()
delete iter->second; delete iter->second;
} }
CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& reportId)
{ {
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); int reportNumber = reportId.getType()==CSMWorld::UniversalId::Type_VerificationResults ?
mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; reportId.getIndex() : mNextReportNumber++;
if (mReports.find (reportNumber)==mReports.end())
mReports.insert (std::make_pair (reportNumber, new ReportModel));
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
getVerifier()->start(); getVerifier()->start();
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, reportNumber);
} }
CSMWorld::UniversalId CSMTools::Tools::newSearch() CSMWorld::UniversalId CSMTools::Tools::newSearch()

View File

@ -57,8 +57,11 @@ namespace CSMTools
virtual ~Tools(); virtual ~Tools();
CSMWorld::UniversalId runVerifier(); /// \param reportId If a valid VerificationResults ID, run verifier for the
///< \return ID of the report for this verification run /// specified report instead of creating a new one.
///
/// \return ID of the report for this verification run
CSMWorld::UniversalId runVerifier (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
/// Return ID of the report for this search. /// Return ID of the report for this search.
CSMWorld::UniversalId newSearch(); CSMWorld::UniversalId newSearch();

View File

@ -100,7 +100,8 @@ bool CSMWorld::ColumnBase::isId (Display display)
bool CSMWorld::ColumnBase::isText (Display display) bool CSMWorld::ColumnBase::isText (Display display)
{ {
return display==Display_String || display==Display_LongString; return display==Display_String || display==Display_LongString ||
display==Display_String32 || display==Display_LongString256;
} }
bool CSMWorld::ColumnBase::isScript (Display display) bool CSMWorld::ColumnBase::isScript (Display display)

View File

@ -123,6 +123,8 @@ namespace CSMWorld
Display_InfoCondVar, Display_InfoCondVar,
Display_InfoCondComp, Display_InfoCondComp,
Display_RaceSkill, Display_RaceSkill,
Display_String32,
Display_LongString256,
//top level columns that nest other columns //top level columns that nest other columns
Display_NestedHeader Display_NestedHeader

View File

@ -2308,6 +2308,78 @@ namespace CSMWorld
return true; return true;
} }
}; };
template<typename ESXRecordT>
struct FormatColumn : public Column<ESXRecordT>
{
FormatColumn()
: Column<ESXRecordT> (Columns::ColumnId_FileFormat, ColumnBase::Display_Integer)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mFormat;
}
virtual bool isEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct AuthorColumn : public Column<ESXRecordT>
{
AuthorColumn()
: Column<ESXRecordT> (Columns::ColumnId_Author, ColumnBase::Display_String32)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mAuthor.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mAuthor = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct FileDescriptionColumn : public Column<ESXRecordT>
{
FileDescriptionColumn()
: Column<ESXRecordT> (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString256)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mDescription.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mDescription = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
} }
#endif #endif

View File

@ -311,6 +311,10 @@ namespace CSMWorld
{ ColumnId_WaterLevel, "Water Level" }, { ColumnId_WaterLevel, "Water Level" },
{ ColumnId_MapColor, "Map Color" }, { ColumnId_MapColor, "Map Color" },
{ ColumnId_FileFormat, "File Format" },
{ ColumnId_FileDescription, "File Description" },
{ ColumnId_Author, "Author" },
{ ColumnId_SpellSrc, "From Race" }, { ColumnId_SpellSrc, "From Race" },
{ ColumnId_SpellCost, "Cast Cost" }, { ColumnId_SpellCost, "Cast Cost" },
{ ColumnId_SpellChance, "Cast Chance" }, { ColumnId_SpellChance, "Cast Chance" },

View File

@ -302,9 +302,13 @@ namespace CSMWorld
ColumnId_WaterLevel = 273, ColumnId_WaterLevel = 273,
ColumnId_MapColor = 274, ColumnId_MapColor = 274,
ColumnId_SpellSrc = 275, ColumnId_FileFormat = 275,
ColumnId_SpellCost = 276, ColumnId_FileDescription = 276,
ColumnId_SpellChance = 277, ColumnId_Author = 277,
ColumnId_SpellSrc = 278,
ColumnId_SpellCost = 279,
ColumnId_SpellChance = 280,
// 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.

View File

@ -544,6 +544,14 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> ( mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
ScriptColumn<ESM::DebugProfile>::Type_Lines)); ScriptColumn<ESM::DebugProfile>::Type_Lines));
mMetaData.appendBlankRecord ("sys::meta");
mMetaData.addColumn (new StringIdColumn<MetaData> (true));
mMetaData.addColumn (new RecordStateColumn<MetaData>);
mMetaData.addColumn (new FormatColumn<MetaData>);
mMetaData.addColumn (new AuthorColumn<MetaData>);
mMetaData.addColumn (new FileDescriptionColumn<MetaData>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
@ -584,6 +592,7 @@ 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);
addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData);
// for autocalc updates when gmst/race/class/skils tables change // for autocalc updates when gmst/race/class/skils tables change
CSMWorld::IdTable *gmsts = CSMWorld::IdTable *gmsts =
@ -901,6 +910,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id)
return mResourcesManager.get (id.getType()); return mResourcesManager.get (id.getType());
} }
const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const
{
return mMetaData.getRecord (0).get();
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
{ {
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType()); std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -945,9 +959,15 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
mBase = base; mBase = base;
mProject = project; mProject = project;
mAuthor = mReader->getAuthor(); if (!mProject && !mBase)
mDescription = mReader->getDesc(); {
MetaData metaData;
metaData.mId = "sys::meta";
metaData.load (*mReader);
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
}
return mReader->getRecordCount(); return mReader->getRecordCount();
} }
@ -1201,26 +1221,6 @@ int CSMWorld::Data::count (RecordBase::State state) const
count (state, mPathgrids); count (state, mPathgrids);
} }
void CSMWorld::Data::setDescription (const std::string& description)
{
mDescription = description;
}
std::string CSMWorld::Data::getDescription() const
{
return mDescription;
}
void CSMWorld::Data::setAuthor (const std::string& author)
{
mAuthor = author;
}
std::string CSMWorld::Data::getAuthor() const
{
return mAuthor;
}
std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
{ {
std::vector<std::string> ids; std::vector<std::string> ids;

View File

@ -44,6 +44,7 @@
#include "infocollection.hpp" #include "infocollection.hpp"
#include "nestedinfocollection.hpp" #include "nestedinfocollection.hpp"
#include "pathgrid.hpp" #include "pathgrid.hpp"
#include "metadata.hpp"
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include "subcellcollection.hpp" #include "subcellcollection.hpp"
#endif #endif
@ -95,11 +96,10 @@ namespace CSMWorld
RefIdCollection mReferenceables; RefIdCollection mReferenceables;
RefCollection mRefs; RefCollection mRefs;
IdCollection<ESM::Filter> mFilters; IdCollection<ESM::Filter> mFilters;
Collection<MetaData> mMetaData;
const ResourcesManager& mResourcesManager; const ResourcesManager& mResourcesManager;
std::vector<QAbstractItemModel *> mModels; std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex; std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
std::string mAuthor;
std::string mDescription;
ESM::ESMReader *mReader; ESM::ESMReader *mReader;
const ESM::Dialogue *mDialogue; // last loaded dialogue const ESM::Dialogue *mDialogue; // last loaded dialogue
bool mBase; bool mBase;
@ -245,6 +245,8 @@ namespace CSMWorld
/// Throws an exception, if \a id does not match a resources list. /// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const; const Resources& getResources (const UniversalId& id) const;
const MetaData& getMetaData() const;
QAbstractItemModel *getTableModel (const UniversalId& id); QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown. ///< If no table model is available for \a id, an exception is thrown.
/// ///
@ -274,14 +276,6 @@ namespace CSMWorld
int count (RecordBase::State state) const; int count (RecordBase::State state) const;
///< Return number of top-level records with the given \a state. ///< Return number of top-level records with the given \a state.
void setDescription (const std::string& description);
std::string getDescription() const;
void setAuthor (const std::string& author);
std::string getAuthor() const;
NpcStats* npcAutoCalculate (const ESM::NPC& npc) const; NpcStats* npcAutoCalculate (const ESM::NPC& npc) const;
NpcStats* getCachedNpcData (const std::string& id) const; NpcStats* getCachedNpcData (const std::string& id) const;

View File

@ -97,7 +97,8 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int
return false; return false;
// Check that topics match // Check that topics match
if (getRecord (baseIndex).get().mTopicId!=getRecord (lastIndex).get().mTopicId) if (!Misc::StringUtils::ciEqual(getRecord(baseIndex).get().mTopicId,
getRecord(lastIndex).get().mTopicId))
return false; return false;
// reorder // reorder

View File

@ -1,12 +1,24 @@
#include "infotableproxymodel.hpp" #include "infotableproxymodel.hpp"
#include <components/misc/stringops.hpp>
#include "idtablebase.hpp" #include "idtablebase.hpp"
#include "columns.hpp" #include "columns.hpp"
namespace
{
QString toLower(const QString &str)
{
return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str());
}
}
CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent) CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent)
: IdTableProxyModel(parent), : IdTableProxyModel(parent),
mType(type), mType(type),
mSourceModel(NULL) mSourceModel(NULL),
mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic :
Columns::ColumnId_Journal)
{ {
Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos); Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos);
} }
@ -15,44 +27,53 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod
{ {
IdTableProxyModel::setSourceModel(sourceModel); IdTableProxyModel::setSourceModel(sourceModel);
mSourceModel = dynamic_cast<IdTableBase *>(sourceModel); mSourceModel = dynamic_cast<IdTableBase *>(sourceModel);
connect(mSourceModel, if (mSourceModel != NULL)
SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), {
this, connect(mSourceModel,
SLOT(modelDataChanged(const QModelIndex &, const QModelIndex &))); SIGNAL(rowsInserted(const QModelIndex &, int, int)),
mFirstRowCache.clear(); this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
connect(mSourceModel,
SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
mFirstRowCache.clear();
}
} }
bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{ {
QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column()); QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column());
QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column()); QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column());
// If both indexes are belonged to the same Topic/Journal, compare their original rows only
if (first.row() == second.row())
{
return sortOrder() == Qt::AscendingOrder ? left.row() < right.row() : right.row() < left.row();
}
return IdTableProxyModel::lessThan(first, second); return IdTableProxyModel::lessThan(first, second);
} }
int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
{ {
Columns::ColumnId columnId = Columns::ColumnId_Topic; int row = currentRow;
if (mType == UniversalId::Type_JournalInfos) int column = mSourceModel->findColumnIndex(mInfoColumnId);
{ QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString());
columnId = Columns::ColumnId_Journal;
}
int column = mSourceModel->findColumnIndex(columnId);
QString info = mSourceModel->data(mSourceModel->index(currentRow, column)).toString();
if (mFirstRowCache.contains(info)) if (mFirstRowCache.contains(info))
{ {
return mFirstRowCache[info]; return mFirstRowCache[info];
} }
while (--currentRow >= 0 && while (--row >= 0 &&
mSourceModel->data(mSourceModel->index(currentRow, column)) == info); toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()) == info);
++row;
mFirstRowCache[info] = currentRow + 1; mFirstRowCache[info] = row;
return currentRow + 1; return row;
} }
void CSMWorld::InfoTableProxyModel::modelDataChanged(const QModelIndex &/*topLeft*/, const QModelIndex &/*bottomRight*/) void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/)
{ {
mFirstRowCache.clear(); mFirstRowCache.clear();
} }

View File

@ -4,6 +4,7 @@
#include <QHash> #include <QHash>
#include "idtableproxymodel.hpp" #include "idtableproxymodel.hpp"
#include "columns.hpp"
#include "universalid.hpp" #include "universalid.hpp"
namespace CSMWorld namespace CSMWorld
@ -16,6 +17,8 @@ namespace CSMWorld
UniversalId::Type mType; UniversalId::Type mType;
IdTableBase *mSourceModel; IdTableBase *mSourceModel;
Columns::ColumnId mInfoColumnId;
///< Contains ID for Topic or Journal ID
mutable QHash<QString, int> mFirstRowCache; mutable QHash<QString, int> mFirstRowCache;
@ -31,7 +34,7 @@ namespace CSMWorld
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const; virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
private slots: private slots:
void modelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight); void modelRowsChanged(const QModelIndex &parent, int start, int end);
}; };
} }

View File

@ -0,0 +1,27 @@
#include "metadata.hpp"
#include <components/esm/loadtes3.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
void CSMWorld::MetaData::blank()
{
mFormat = ESM::Header::CurrentFormat;
mAuthor.clear();
mDescription.clear();
}
void CSMWorld::MetaData::load (ESM::ESMReader& esm)
{
mFormat = esm.getHeader().mFormat;
mAuthor = esm.getHeader().mData.author.toString();
mDescription = esm.getHeader().mData.desc.toString();
}
void CSMWorld::MetaData::save (ESM::ESMWriter& esm) const
{
esm.setFormat (mFormat);
esm.setAuthor (mAuthor);
esm.setDescription (mDescription);
}

View File

@ -0,0 +1,29 @@
#ifndef CSM_WOLRD_METADATA_H
#define CSM_WOLRD_METADATA_H
#include <string>
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace CSMWorld
{
struct MetaData
{
std::string mId;
int mFormat;
std::string mAuthor;
std::string mDescription;
void blank();
void load (ESM::ESMReader& esm);
void save (ESM::ESMWriter& esm) const;
};
}
#endif

View File

@ -56,6 +56,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };
@ -120,6 +121,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };

View File

@ -131,6 +131,8 @@ namespace CSMWorld
Type_StartScripts, Type_StartScripts,
Type_StartScript, Type_StartScript,
Type_Search, Type_Search,
Type_MetaDatas,
Type_MetaData,
Type_RunLog Type_RunLog
}; };

View File

@ -70,6 +70,10 @@ void CSVDoc::View::setupFileMenu()
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
file->addAction (loadErrors); file->addAction (loadErrors);
QAction *meta = new QAction (tr ("Meta Data"), this);
connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView()));
file->addAction (meta);
QAction *close = new QAction (tr ("&Close"), this); QAction *close = new QAction (tr ("&Close"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close())); connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close); file->addAction(close);
@ -813,6 +817,11 @@ void CSVDoc::View::addSearchSubView()
addSubView (mDocument->newSearch()); addSubView (mDocument->newSearch());
} }
void CSVDoc::View::addMetaDataSubView()
{
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta"));
}
void CSVDoc::View::abortOperation (int type) void CSVDoc::View::abortOperation (int type)
{ {
mDocument->abortOperation (type); mDocument->abortOperation (type);

View File

@ -224,6 +224,8 @@ namespace CSVDoc
void addSearchSubView(); void addSearchSubView();
void addMetaDataSubView();
void toggleShowStatusBar (bool show); void toggleShowStatusBar (bool show);
void loadErrorLog(); void loadErrorLog();

View File

@ -4,12 +4,23 @@
#include "reporttable.hpp" #include "reporttable.hpp"
CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: CSVDoc::SubView (id) : CSVDoc::SubView (id), mDocument (document), mRefreshState (0)
{ {
setWidget (mTable = new ReportTable (document, id, false, this)); if (id.getType()==CSMWorld::UniversalId::Type_VerificationResults)
mRefreshState = CSMDoc::State_Verifying;
setWidget (mTable = new ReportTable (document, id, false, mRefreshState, this));
connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)), connect (mTable, SIGNAL (editRequest (const CSMWorld::UniversalId&, const std::string&)),
SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&))); SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)));
if (mRefreshState==CSMDoc::State_Verifying)
{
connect (mTable, SIGNAL (refreshRequest()), this, SLOT (refreshRequest()));
connect (&document, SIGNAL (stateChanged (int, CSMDoc::Document *)),
mTable, SLOT (stateChanged (int, CSMDoc::Document *)));
}
} }
void CSVTools::ReportSubView::setEditLock (bool locked) void CSVTools::ReportSubView::setEditLock (bool locked)
@ -21,3 +32,15 @@ void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStr
{ {
mTable->updateUserSetting (name, list); mTable->updateUserSetting (name, list);
} }
void CSVTools::ReportSubView::refreshRequest()
{
if (!(mDocument.getState() & mRefreshState))
{
if (mRefreshState==CSMDoc::State_Verifying)
{
mTable->clear();
mDocument.verify (getUniversalId());
}
}
}

View File

@ -20,6 +20,8 @@ namespace CSVTools
Q_OBJECT Q_OBJECT
ReportTable *mTable; ReportTable *mTable;
CSMDoc::Document& mDocument;
int mRefreshState;
public: public:
@ -28,6 +30,10 @@ namespace CSVTools
virtual void setEditLock (bool locked); virtual void setEditLock (bool locked);
virtual void updateUserSetting (const QString &, const QStringList &); virtual void updateUserSetting (const QString &, const QStringList &);
private slots:
void refreshRequest();
}; };
} }

View File

@ -74,8 +74,10 @@ void CSVTools::ReportTable::contextMenuEvent (QContextMenuEvent *event)
if (found) if (found)
menu.addAction (mReplaceAction); menu.addAction (mReplaceAction);
} }
if (mRefreshAction)
menu.addAction (mRefreshAction);
menu.exec (event->globalPos()); menu.exec (event->globalPos());
} }
@ -134,8 +136,10 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
} }
CSVTools::ReportTable::ReportTable (CSMDoc::Document& document, CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent) const CSMWorld::UniversalId& id, bool richTextDescription, int refreshState,
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)) QWidget *parent)
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)),
mRefreshAction (0), mRefreshState (refreshState)
{ {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) #if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive); horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive);
@ -171,6 +175,14 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest()));
addAction (mReplaceAction); addAction (mReplaceAction);
if (mRefreshState)
{
mRefreshAction = new QAction (tr ("Refresh"), this);
mRefreshAction->setEnabled (!(mDocument.getState() & mRefreshState));
connect (mRefreshAction, SIGNAL (triggered()), this, SIGNAL (refreshRequest()));
addAction (mRefreshAction);
}
mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit)); mDoubleClickActions.insert (std::make_pair (Qt::NoModifier, Action_Edit));
mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove)); mDoubleClickActions.insert (std::make_pair (Qt::ShiftModifier, Action_Remove));
mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove)); mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove));
@ -287,3 +299,9 @@ void CSVTools::ReportTable::clear()
{ {
mModel->clear(); mModel->clear();
} }
void CSVTools::ReportTable::stateChanged (int state, CSMDoc::Document *document)
{
if (mRefreshAction)
mRefreshAction->setEnabled (!(state & mRefreshState));
}

View File

@ -36,7 +36,9 @@ namespace CSVTools
QAction *mShowAction; QAction *mShowAction;
QAction *mRemoveAction; QAction *mRemoveAction;
QAction *mReplaceAction; QAction *mReplaceAction;
QAction *mRefreshAction;
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions; std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
int mRefreshState;
private: private:
@ -49,8 +51,11 @@ namespace CSVTools
public: public:
/// \param richTextDescription Use rich text in the description column. /// \param richTextDescription Use rich text in the description column.
/// \param refreshState Document state to check for refresh function. If value is
/// 0 no refresh function exists. If the document current has the specified state
/// the refresh function is disabled.
ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id, ReportTable (CSMDoc::Document& document, const CSMWorld::UniversalId& id,
bool richTextDescription, QWidget *parent = 0); bool richTextDescription, int refreshState = 0, QWidget *parent = 0);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const; virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
@ -71,11 +76,17 @@ namespace CSVTools
void removeSelection(); void removeSelection();
public slots:
void stateChanged (int state, CSMDoc::Document *document);
signals: signals:
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint); void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
void replaceRequest(); void replaceRequest();
void refreshRequest();
}; };
} }

View File

@ -35,7 +35,7 @@ void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event)
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType)) if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{ {
CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType); CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType);
setText(id.getId().c_str()); setText(QString::fromUtf8(id.getId().c_str()));
emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr()); emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr());
} }
} }

View File

@ -64,16 +64,24 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo
} }
} }
CSMWorld::Columns::ColumnId columnId = static_cast<CSMWorld::Columns::ColumnId> (
mTable->getColumnId (index.column()));
if (QVariant::String == v.type()) if (QVariant::String == v.type())
{ {
label->setText(v.toString()); label->setText(v.toString());
} }
else //else we are facing enums else if (CSMWorld::Columns::hasEnums (columnId))
{ {
int data = v.toInt(); int data = v.toInt();
std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mTable->getColumnId (index.column())))); std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (columnId));
label->setText(QString::fromUtf8(enumNames.at(data).c_str())); label->setText(QString::fromUtf8(enumNames.at(data).c_str()));
} }
else
{
label->setText (v.toString());
}
} }
void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
@ -550,12 +558,38 @@ void CSVWorld::EditWidget::remake(int row)
this->setWidgetResizable(true); this->setWidgetResizable(true);
} }
/*
==============================DialogueSubView==========================================
*/
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, QVBoxLayout& CSVWorld::SimpleDialogueSubView::getMainLayout()
const CreatorFactoryBase& creatorFactory, bool sorting) : {
return *mMainLayout;
}
CSMWorld::IdTable& CSVWorld::SimpleDialogueSubView::getTable()
{
return *mTable;
}
CSMWorld::CommandDispatcher& CSVWorld::SimpleDialogueSubView::getCommandDispatcher()
{
return mCommandDispatcher;
}
std::string CSVWorld::SimpleDialogueSubView::getCurrentId() const
{
return mCurrentId;
}
CSVWorld::EditWidget& CSVWorld::SimpleDialogueSubView::getEditWidget()
{
return *mEditWidget;
}
bool CSVWorld::SimpleDialogueSubView::isLocked() const
{
return mLocked;
}
CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) :
SubView (id), SubView (id),
mEditWidget(0), mEditWidget(0),
mMainLayout(NULL), mMainLayout(NULL),
@ -572,60 +606,8 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
QWidget *mainWidget = new QWidget(this); QWidget *mainWidget = new QWidget(this);
QHBoxLayout *buttonsLayout = new QHBoxLayout;
QToolButton* prevButton = new QToolButton(mainWidget);
prevButton->setIcon(QIcon(":/go-previous.png"));
prevButton->setToolTip ("Switch to previous record");
QToolButton* nextButton = new QToolButton(mainWidget);
nextButton->setIcon(QIcon(":/go-next.png"));
nextButton->setToolTip ("Switch to next record");
buttonsLayout->addWidget(prevButton, 0);
buttonsLayout->addWidget(nextButton, 1);
buttonsLayout->addStretch(2);
QToolButton* cloneButton = new QToolButton(mainWidget);
cloneButton->setIcon(QIcon(":/edit-clone.png"));
cloneButton->setToolTip ("Clone record");
QToolButton* addButton = new QToolButton(mainWidget);
addButton->setIcon(QIcon(":/add.png"));
addButton->setToolTip ("Add new record");
QToolButton* deleteButton = new QToolButton(mainWidget);
deleteButton->setIcon(QIcon(":/edit-delete.png"));
deleteButton->setToolTip ("Delete record");
QToolButton* revertButton = new QToolButton(mainWidget);
revertButton->setIcon(QIcon(":/edit-undo.png"));
revertButton->setToolTip ("Revert record");
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview)
{
QToolButton* previewButton = new QToolButton(mainWidget);
previewButton->setIcon(QIcon(":/edit-preview.png"));
previewButton->setToolTip ("Open a preview of this record");
buttonsLayout->addWidget(previewButton);
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
}
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_View)
{
QToolButton* viewButton = new QToolButton(mainWidget);
viewButton->setIcon(QIcon(":/cell.png"));
viewButton->setToolTip ("Open a scene view of the cell this record is located in");
buttonsLayout->addWidget(viewButton);
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
}
buttonsLayout->addWidget(cloneButton);
buttonsLayout->addWidget(addButton);
buttonsLayout->addWidget(deleteButton);
buttonsLayout->addWidget(revertButton);
connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId()));
connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId()));
connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest()));
connect(revertButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeRevert()));
connect(deleteButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeDelete()));
mMainLayout = new QVBoxLayout(mainWidget); mMainLayout = new QVBoxLayout(mainWidget);
setWidget (mainWidget);
mEditWidget = new EditWidget(mainWidget, mEditWidget = new EditWidget(mainWidget,
mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false);
@ -641,98 +623,10 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
mMainLayout->addWidget(mEditWidget); mMainLayout->addWidget(mEditWidget);
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
mMainLayout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this));
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&)));
connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest()));
if(!mBottom->canCreateAndDelete())
{
cloneButton->setDisabled (true);
addButton->setDisabled (true);
deleteButton->setDisabled (true);
}
dataChanged(mTable->getModelIndex (mCurrentId, 0)); dataChanged(mTable->getModelIndex (mCurrentId, 0));
mMainLayout->addLayout (buttonsLayout);
setWidget (mainWidget);
} }
void CSVWorld::DialogueSubView::prevId () void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked)
{
int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1;
if (newRow < 0)
{
return;
}
while (newRow >= 0)
{
QModelIndex newIndex(mTable->index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased))
{
mEditWidget->remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
mEditWidget->setDisabled(mLocked);
return;
}
--newRow;
}
}
void CSVWorld::DialogueSubView::nextId ()
{
int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1;
if (newRow >= mTable->rowCount())
{
return;
}
while (newRow < mTable->rowCount())
{
QModelIndex newIndex(mTable->index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted))
{
mEditWidget->remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
mEditWidget->setDisabled(mLocked);
return;
}
++newRow;
}
}
void CSVWorld::DialogueSubView::setEditLock (bool locked)
{ {
if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid
return; return;
@ -751,7 +645,7 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked)
} }
void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index)
{ {
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0));
@ -784,7 +678,7 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index)
} }
} }
void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{ {
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0));
@ -799,45 +693,14 @@ void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent,
} }
} }
void CSVWorld::DialogueSubView::requestFocus (const std::string& id) void CSVWorld::SimpleDialogueSubView::requestFocus (const std::string& id)
{ {
changeCurrentId(id); changeCurrentId(id);
mEditWidget->remake(mTable->getModelIndex (id, 0).row()); mEditWidget->remake(mTable->getModelIndex (id, 0).row());
} }
void CSVWorld::DialogueSubView::cloneRequest () void CSVWorld::SimpleDialogueSubView::changeCurrentId (const std::string& newId)
{
mBottom->cloneRequest(mCurrentId, static_cast<CSMWorld::UniversalId::Type>(mTable->data(mTable->getModelIndex(mCurrentId, 2)).toInt()));
}
void CSVWorld::DialogueSubView::showPreview ()
{
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0));
if (currentIndex.isValid() &&
mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview &&
currentIndex.row() < mTable->rowCount())
{
emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), "");
}
}
void CSVWorld::DialogueSubView::viewRecord ()
{
QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0));
if (currentIndex.isValid() &&
currentIndex.row() < mTable->rowCount())
{
std::pair<CSMWorld::UniversalId, std::string> params = mTable->view (currentIndex.row());
if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
emit focusId (params.first, params.second);
}
}
void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId)
{ {
std::vector<std::string> selection; std::vector<std::string> selection;
mCurrentId = std::string(newId); mCurrentId = std::string(newId);
@ -846,26 +709,184 @@ void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId)
mCommandDispatcher.setSelection(selection); mCommandDispatcher.setSelection(selection);
} }
void CSVWorld::DialogueSubView::refreshNpcDialogue (int type, const std::string& id) CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting)
: SimpleDialogueSubView (id, document)
{ {
int typeColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_RecordType); // bottom box
if (CSMWorld::UniversalId::Type_Npc getMainLayout().addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this));
!= mTable->data(mTable->getModelIndex(mCurrentId, typeColumn), Qt::DisplayRole).toInt())
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&)));
// buttons
QHBoxLayout *buttonsLayout = new QHBoxLayout;
QToolButton* prevButton = new QToolButton (this);
prevButton->setIcon(QIcon(":/go-previous.png"));
prevButton->setToolTip ("Switch to previous record");
QToolButton* nextButton = new QToolButton (this);
nextButton->setIcon(QIcon(":/go-next.png"));
nextButton->setToolTip ("Switch to next record");
buttonsLayout->addWidget(prevButton, 0);
buttonsLayout->addWidget(nextButton, 1);
buttonsLayout->addStretch(2);
QToolButton* cloneButton = new QToolButton (this);
cloneButton->setIcon(QIcon(":/edit-clone.png"));
cloneButton->setToolTip ("Clone record");
QToolButton* addButton = new QToolButton (this);
addButton->setIcon(QIcon(":/add.png"));
addButton->setToolTip ("Add new record");
QToolButton* deleteButton = new QToolButton (this);
deleteButton->setIcon(QIcon(":/edit-delete.png"));
deleteButton->setToolTip ("Delete record");
QToolButton* revertButton = new QToolButton (this);
revertButton->setIcon(QIcon(":/edit-undo.png"));
revertButton->setToolTip ("Revert record");
if (getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview)
{
QToolButton* previewButton = new QToolButton (this);
previewButton->setIcon(QIcon(":/edit-preview.png"));
previewButton->setToolTip ("Open a preview of this record");
buttonsLayout->addWidget(previewButton);
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
}
if (getTable().getFeatures() & CSMWorld::IdTable::Feature_View)
{
QToolButton* viewButton = new QToolButton (this);
viewButton->setIcon(QIcon(":/cell.png"));
viewButton->setToolTip ("Open a scene view of the cell this record is located in");
buttonsLayout->addWidget(viewButton);
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
}
buttonsLayout->addWidget(cloneButton);
buttonsLayout->addWidget(addButton);
buttonsLayout->addWidget(deleteButton);
buttonsLayout->addWidget(revertButton);
connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId()));
connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId()));
connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest()));
connect(revertButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeRevert()));
connect(deleteButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeDelete()));
connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest()));
if(!mBottom->canCreateAndDelete())
{
cloneButton->setDisabled (true);
addButton->setDisabled (true);
deleteButton->setDisabled (true);
}
getMainLayout().addLayout (buttonsLayout);
}
void CSVWorld::DialogueSubView::cloneRequest()
{
mBottom->cloneRequest (getCurrentId(),
static_cast<CSMWorld::UniversalId::Type> (getTable().
data (getTable().getModelIndex(getCurrentId(), 2)).toInt()));
}
void CSVWorld::DialogueSubView::prevId()
{
int newRow = getTable().getModelIndex (getCurrentId(), 0).row() - 1;
if (newRow < 0)
{
return;
}
while (newRow >= 0)
{
QModelIndex newIndex (getTable().index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> (getTable().data (getTable().index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased))
{
getEditWidget().remake (newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (getTable().data (getTable().index (newRow, 2)).toInt()),
getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
getEditWidget().setDisabled (isLocked());
return;
}
--newRow;
}
}
void CSVWorld::DialogueSubView::nextId ()
{
int newRow = getTable().getModelIndex (getCurrentId(), 0).row() + 1;
if (newRow >= getTable().rowCount())
{ {
return; return;
} }
int raceColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_Race); while (newRow < getTable().rowCount())
int classColumn = mTable->findColumnIndex (CSMWorld::Columns::ColumnId_Class);
if ((type == 0/*FIXME*/ && id == "") // skill or gmst changed
|| (id == mTable->data(mTable->getModelIndex(mCurrentId, raceColumn),
Qt::DisplayRole).toString().toUtf8().constData()) // race
|| (id == mTable->data(mTable->getModelIndex(mCurrentId, classColumn),
Qt::DisplayRole).toString().toUtf8().constData())) // class
{ {
int y = mEditWidget->verticalScrollBar()->value(); QModelIndex newIndex (getTable().index(newRow, 0));
mEditWidget->remake (mTable->getModelIndex(mCurrentId, 0).row());
mEditWidget->verticalScrollBar()->setValue(y); if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> (getTable().data (getTable().index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted))
{
getEditWidget().remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (getTable().data (getTable().index (newRow, 2)).toInt()),
getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
getEditWidget().setDisabled (isLocked());
return;
}
++newRow;
}
}
void CSVWorld::DialogueSubView::showPreview ()
{
QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0));
if (currentIndex.isValid() &&
getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview &&
currentIndex.row() < getTable().rowCount())
{
emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getCurrentId()), "");
}
}
void CSVWorld::DialogueSubView::viewRecord ()
{
QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0));
if (currentIndex.isValid() &&
currentIndex.row() < getTable().rowCount())
{
std::pair<CSMWorld::UniversalId, std::string> params = getTable().view (currentIndex.row());
if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
emit focusId (params.first, params.second);
} }
} }

View File

@ -173,7 +173,7 @@ namespace CSVWorld
void remake(int row); void remake(int row);
}; };
class DialogueSubView : public CSVDoc::SubView class SimpleDialogueSubView : public CSVDoc::SubView
{ {
Q_OBJECT Q_OBJECT
@ -184,33 +184,32 @@ namespace CSVWorld
std::string mCurrentId; std::string mCurrentId;
bool mLocked; bool mLocked;
const CSMDoc::Document& mDocument; const CSMDoc::Document& mDocument;
TableBottomBox* mBottom;
CSMWorld::CommandDispatcher mCommandDispatcher; CSMWorld::CommandDispatcher mCommandDispatcher;
protected:
QVBoxLayout& getMainLayout();
CSMWorld::IdTable& getTable();
CSMWorld::CommandDispatcher& getCommandDispatcher();
std::string getCurrentId() const;
EditWidget& getEditWidget();
void changeCurrentId(const std::string& newCurrent);
bool isLocked() const;
public: public:
DialogueSubView (const CSMWorld::UniversalId& id, SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory,
bool sorting = false);
virtual void setEditLock (bool locked); virtual void setEditLock (bool locked);
private:
void changeCurrentId(const std::string& newCurrent);
private slots: private slots:
void nextId();
void prevId();
void showPreview();
void viewRecord();
void cloneRequest();
void dataChanged(const QModelIndex & index); void dataChanged(const QModelIndex & index);
///\brief we need to care for deleting currently edited record ///\brief we need to care for deleting currently edited record
@ -220,6 +219,30 @@ namespace CSVWorld
void refreshNpcDialogue (int type, const std::string& id); void refreshNpcDialogue (int type, const std::string& id);
}; };
class DialogueSubView : public SimpleDialogueSubView
{
Q_OBJECT
TableBottomBox* mBottom;
public:
DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory, bool sorting = false);
private slots:
void cloneRequest();
void nextId();
void prevId();
void showPreview();
void viewRecord();
};
} }
#endif #endif

View File

@ -4,7 +4,6 @@
#include <algorithm> #include <algorithm>
#include <QLabel> #include <QLabel>
#include <QLineEdit>
#include <QUuid> #include <QUuid>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
@ -17,6 +16,8 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp" #include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::InfoCreator::getId() const std::string CSVWorld::InfoCreator::getId() const
{ {
std::string id = Misc::StringUtils::lowerCase (mTopic->text().toUtf8().constData()); std::string id = Misc::StringUtils::lowerCase (mTopic->text().toUtf8().constData());
@ -48,12 +49,12 @@ CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
QLabel *label = new QLabel ("Topic", this); QLabel *label = new QLabel ("Topic", this);
insertBeforeButtons (label, false); insertBeforeButtons (label, false);
mTopic = new QLineEdit (this);
CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic; CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic;
if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos) if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos)
{ {
displayType = CSMWorld::ColumnBase::Display_Journal; displayType = CSMWorld::ColumnBase::Display_Journal;
} }
mTopic = new CSVWidget::DropLineEdit(displayType, this);
mTopic->setCompleter(completionManager.getCompleter(displayType).get()); mTopic->setCompleter(completionManager.getCompleter(displayType).get());
insertBeforeButtons (mTopic, true); insertBeforeButtons (mTopic, true);

View File

@ -3,21 +3,24 @@
#include "genericcreator.hpp" #include "genericcreator.hpp"
class QLineEdit;
namespace CSMWorld namespace CSMWorld
{ {
class InfoCollection; class InfoCollection;
class IdCompletionManager; class IdCompletionManager;
} }
namespace CSVWidget
{
class DropLineEdit;
}
namespace CSVWorld namespace CSVWorld
{ {
class InfoCreator : public GenericCreator class InfoCreator : public GenericCreator
{ {
Q_OBJECT Q_OBJECT
QLineEdit *mTopic; CSVWidget::DropLineEdit *mTopic;
virtual std::string getId() const; virtual std::string getId() const;

View File

@ -2,7 +2,6 @@
#include "referencecreator.hpp" #include "referencecreator.hpp"
#include <QLabel> #include <QLabel>
#include <QLineEdit>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
@ -12,6 +11,8 @@
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp" #include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::ReferenceCreator::getId() const std::string CSVWorld::ReferenceCreator::getId() const
{ {
return mId; return mId;
@ -80,7 +81,7 @@ CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack&
QLabel *label = new QLabel ("Cell", this); QLabel *label = new QLabel ("Cell", this);
insertBeforeButtons (label, false); insertBeforeButtons (label, false);
mCell = new QLineEdit (this); mCell = new CSVWidget::DropLineEdit(CSMWorld::ColumnBase::Display_Cell, this);
mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get()); mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get());
insertBeforeButtons (mCell, true); insertBeforeButtons (mCell, true);

View File

@ -3,13 +3,16 @@
#include "genericcreator.hpp" #include "genericcreator.hpp"
class QLineEdit;
namespace CSMWorld namespace CSMWorld
{ {
class IdCompletionManager; class IdCompletionManager;
} }
namespace CSVWidget
{
class DropLineEdit;
}
namespace CSVWorld namespace CSVWorld
{ {
@ -17,7 +20,7 @@ namespace CSVWorld
{ {
Q_OBJECT Q_OBJECT
QLineEdit *mCell; CSVWidget::DropLineEdit *mCell;
std::string mId; std::string mId;
private: private:

View File

@ -170,6 +170,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Filter, manager.add (CSMWorld::UniversalId::Type_Filter,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
manager.add (CSMWorld::UniversalId::Type_MetaData,
new CSVDoc::SubViewFactory<SimpleDialogueSubView >);
//preview //preview
manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>); manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>);
} }

View File

@ -9,6 +9,8 @@
#include <QString> #include <QString>
#include <QtCore/qnamespace.h> #include <QtCore/qnamespace.h>
#include <components/misc/stringops.hpp>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
@ -128,17 +130,24 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
{ {
int row = mProxyModel->mapToSource ( int row = mProxyModel->mapToSource (
mProxyModel->index (selectedRows.begin()->row(), 0)).row(); mProxyModel->index (selectedRows.begin()->row(), 0)).row();
QString curData = mModel->data(mModel->index(row, column)).toString();
if (row>0 && mModel->data (mModel->index (row, column))== if (row > 0)
mModel->data (mModel->index (row-1, column)))
{ {
menu.addAction (mMoveUpAction); QString prevData = mModel->data(mModel->index(row - 1, column)).toString();
if (Misc::StringUtils::ciEqual(curData.toStdString(), prevData.toStdString()))
{
menu.addAction(mMoveUpAction);
}
} }
if (row<mModel->rowCount()-1 && mModel->data (mModel->index (row, column))== if (row < mModel->rowCount() - 1)
mModel->data (mModel->index (row+1, column)))
{ {
menu.addAction (mMoveDownAction); QString nextData = mModel->data(mModel->index(row + 1, column)).toString();
if (Misc::StringUtils::ciEqual(curData.toStdString(), nextData.toStdString()))
{
menu.addAction(mMoveDownAction);
}
} }
} }
} }

View File

@ -233,6 +233,14 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
return edit; return edit;
} }
case CSMWorld::ColumnBase::Display_LongString256:
{
/// \todo implement size limit. QPlainTextEdit does not support a size limit.
QPlainTextEdit *edit = new QPlainTextEdit(parent);
edit->setUndoRedoEnabled (false);
return edit;
}
case CSMWorld::ColumnBase::Display_Boolean: case CSMWorld::ColumnBase::Display_Boolean:
return new QCheckBox(parent); return new QCheckBox(parent);
@ -246,6 +254,14 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
return new CSVWidget::DropLineEdit(display, parent); return new CSVWidget::DropLineEdit(display, parent);
case CSMWorld::ColumnBase::Display_String32:
{
// For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used
CSVWidget::DropLineEdit *widget = new CSVWidget::DropLineEdit(display, parent);
widget->setMaxLength (32);
return widget;
}
default: default:
return QStyledItemDelegate::createEditor (parent, option, index); return QStyledItemDelegate::createEditor (parent, option, index);