1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-31 06:45:35 +00:00

Merge branch 'master' into cc9cii

This commit is contained in:
cc9cii 2015-06-27 09:29:41 +10:00
commit 2076acec10
94 changed files with 1471 additions and 757 deletions

View file

@ -41,9 +41,9 @@ namespace ESSImport
{
for (int i=0; i<ESM::Skill::Length; ++i)
{
npcStats.mSkills[i].mRegular.mMod = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0];
npcStats.mSkills[i].mMod = actorData.mSkills[i][1];
npcStats.mSkills[i].mCurrent = actorData.mSkills[i][1];
npcStats.mSkills[i].mBase = actorData.mSkills[i][0];
}
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter;

View file

@ -18,7 +18,7 @@ namespace ESSImport
for (int i=0; i<8; ++i)
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
for (int i=0; i<27; ++i)
out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)

View file

@ -26,7 +26,7 @@ opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
idcompletionmanager
idcompletionmanager metadata
)
opencs_hdrs_noqt (model/world
@ -70,12 +70,12 @@ opencs_units (view/world
opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator physicssystem idcompletiondelegate
colordelegate
colordelegate dragdroputils
)
opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2 completerpopup coloreditor colorpickerpopup
scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit
)
opencs_units (view/render

View file

@ -13,6 +13,8 @@
#include <components/ogreinit/ogreinit.hpp>
#include "model/doc/messages.hpp"
#include "model/world/universalid.hpp"
#ifdef Q_OS_MAC
@ -52,6 +54,7 @@ int main(int argc, char *argv[])
qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
OgreInit::OgreInit ogreInit;

View file

@ -2282,9 +2282,6 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (mNew)
{
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1)
createBase();
}
@ -2304,8 +2301,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
&mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (reportMessage (const CSMDoc::Message&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
}
@ -2369,9 +2366,9 @@ void CSMDoc::Document::save()
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);
return id;
}
@ -2401,11 +2398,10 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
emit stateChanged (getState(), this);
}
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type)
void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
{
/// \todo find a better way to get these messages to the user.
std::cout << message << std::endl;
std::cout << message.mMessage << std::endl;
}
void CSMDoc::Document::operationDone (int type, bool failed)

View file

@ -120,7 +120,7 @@ namespace CSMDoc
void save();
CSMWorld::UniversalId verify();
CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
CSMWorld::UniversalId newSearch();
@ -158,8 +158,7 @@ namespace CSMDoc
void modificationStateChanged (bool clean);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void reportMessage (const CSMDoc::Message& message, int type);
void operationDone (int type, bool failed);

View file

@ -52,7 +52,7 @@ void CSMDoc::Loader::load()
{
if (iter->second.mRecordsLeft)
{
CSMDoc::Messages messages;
Messages messages (Message::Severity_Error);
for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals
if (document->getData().continueLoading (messages))
{
@ -68,7 +68,7 @@ void CSMDoc::Loader::load()
for (CSMDoc::Messages::Iterator iter (messages.begin());
iter!=messages.end(); ++iter)
{
document->getReport (log)->add (iter->mId, iter->mMessage);
document->getReport (log)->add (*iter);
emit loadMessage (document, iter->mMessage);
}
}

View file

@ -1,15 +1,25 @@
#include "messages.hpp"
void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
{
Message data;
data.mId = id;
data.mMessage = message;
data.mHint = hint;
CSMDoc::Message::Message() {}
mMessages.push_back (data);
CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, Severity severity)
: mId (id), mMessage (message), mHint (hint), mSeverity (severity)
{}
CSMDoc::Messages::Messages (Message::Severity default_)
: mDefault (default_)
{}
void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, Message::Severity severity)
{
if (severity==Message::Severity_Default)
severity = mDefault;
mMessages.push_back (Message (id, message, hint, severity));
}
void CSMDoc::Messages::push_back (const std::pair<CSMWorld::UniversalId, std::string>& data)

View file

@ -4,20 +4,41 @@
#include <string>
#include <vector>
#include <QMetaType>
#include "../world/universalid.hpp"
namespace CSMDoc
{
struct Message
{
enum Severity
{
Severity_Info = 0, // no problem
Severity_Warning = 1, // a potential problem, but we are probably fine
Severity_Error = 2, // an error; we are not fine
Severity_SeriousError = 3, // an error so bad we can't even be sure if we are
// reporting it correctly
Severity_Default = 4
};
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
Severity mSeverity;
Message();
Message (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, Severity severity);
};
class Messages
{
public:
struct Message
{
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
// \deprecated Use CSMDoc::Message directly instead.
typedef CSMDoc::Message Message;
typedef std::vector<Message> Collection;
@ -26,11 +47,15 @@ namespace CSMDoc
private:
Collection mMessages;
Message::Severity mDefault;
public:
Messages (Message::Severity default_);
void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = "");
const std::string& hint = "",
Message::Severity severity = Message::Severity_Default);
/// \deprecated Use add instead.
void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data);
@ -41,4 +66,6 @@ namespace CSMDoc
};
}
Q_DECLARE_METATYPE (CSMDoc::Message)
#endif

View file

@ -7,6 +7,7 @@
#include <QTimer>
#include "../world/universalid.hpp"
#include "../settings/usersettings.hpp"
#include "state.hpp"
#include "stage.hpp"
@ -23,13 +24,17 @@ void CSMDoc::Operation::prepareStages()
{
iter->second = iter->first->setup();
mTotalSteps += iter->second;
for (std::map<QString, QStringList>::const_iterator iter2 (mSettings.begin()); iter2!=mSettings.end(); ++iter2)
iter->first->updateUserSetting (iter2->first, iter2->second);
}
}
CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways)
: mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()),
mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered),
mFinalAlways (finalAlways), mError(false), mConnected (false)
mFinalAlways (finalAlways), mError(false), mConnected (false), mPrepared (false),
mDefaultSeverity (Message::Severity_Error)
{
mTimer = new QTimer (this);
}
@ -49,8 +54,8 @@ void CSMDoc::Operation::run()
connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage()));
mConnected = true;
}
prepareStages();
mPrepared = false;
mTimer->start (0);
}
@ -60,6 +65,19 @@ void CSMDoc::Operation::appendStage (Stage *stage)
mStages.push_back (std::make_pair (stage, 0));
}
void CSMDoc::Operation::configureSettings (const std::vector<QString>& settings)
{
for (std::vector<QString>::const_iterator iter (settings.begin()); iter!=settings.end(); ++iter)
{
mSettings.insert (std::make_pair (*iter, CSMSettings::UserSettings::instance().definitions (*iter)));
}
}
void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity)
{
mDefaultSeverity = severity;
}
bool CSMDoc::Operation::hasError() const
{
return mError;
@ -84,9 +102,23 @@ void CSMDoc::Operation::abort()
mCurrentStage = mStages.end();
}
void CSMDoc::Operation::updateUserSetting (const QString& name, const QStringList& value)
{
std::map<QString, QStringList>::iterator iter = mSettings.find (name);
if (iter!=mSettings.end())
iter->second = value;
}
void CSMDoc::Operation::executeStage()
{
Messages messages;
if (!mPrepared)
{
prepareStages();
mPrepared = true;
}
Messages messages (mDefaultSeverity);
while (mCurrentStage!=mStages.end())
{
@ -103,7 +135,7 @@ void CSMDoc::Operation::executeStage()
}
catch (const std::exception& e)
{
emit reportMessage (CSMWorld::UniversalId(), e.what(), "", mType);
emit reportMessage (Message (CSMWorld::UniversalId(), e.what(), "", Message::Severity_SeriousError), mType);
abort();
}
@ -115,7 +147,7 @@ void CSMDoc::Operation::executeStage()
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter)
emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType);
emit reportMessage (*iter, mType);
if (mCurrentStage==mStages.end())
operationDone();

View file

@ -2,9 +2,13 @@
#define CSM_DOC_OPERATION_H
#include <vector>
#include <map>
#include <QObject>
#include <QTimer>
#include <QStringList>
#include "messages.hpp"
namespace CSMWorld
{
@ -30,6 +34,9 @@ namespace CSMDoc
bool mError;
bool mConnected;
QTimer *mTimer;
std::map<QString, QStringList> mSettings;
bool mPrepared;
Message::Severity mDefaultSeverity;
void prepareStages();
@ -46,14 +53,21 @@ namespace CSMDoc
///
/// \attention Do no call this function while this Operation is running.
/// Specify settings to be passed on to stages.
///
/// \attention Do no call this function while this Operation is running.
void configureSettings (const std::vector<QString>& settings);
/// \attention Do no call this function while this Operation is running.
void setDefaultSeverity (Message::Severity severity);
bool hasError() const;
signals:
void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void reportMessage (const CSMDoc::Message& message, int type);
void done (int type, bool failed);
@ -63,6 +77,8 @@ namespace CSMDoc
void run();
void updateUserSetting (const QString& name, const QStringList& value);
private slots:
void executeStage();

View file

@ -1,6 +1,8 @@
#include "operationholder.hpp"
#include "../settings/usersettings.hpp"
#include "operation.hpp"
CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false)
@ -19,8 +21,8 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
this, SIGNAL (progress (int, int, int)));
connect (
mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
mOperation, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SIGNAL (reportMessage (const CSMDoc::Message&, int)));
connect (
mOperation, SIGNAL (done (int, bool)),
@ -29,6 +31,9 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort()));
connect (&mThread, SIGNAL (started()), mOperation, SLOT (run()));
connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated (const QString&, const QStringList&)),
mOperation, SLOT (updateUserSetting (const QString&, const QStringList&)));
}
bool CSMDoc::OperationHolder::isRunning() const

View file

@ -4,6 +4,8 @@
#include <QObject>
#include <QThread>
#include "messages.hpp"
namespace CSMWorld
{
class UniversalId;
@ -44,8 +46,7 @@ namespace CSMDoc
void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void reportMessage (const CSMDoc::Message& message, int type);
void done (int type, bool failed);

View file

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

View file

@ -2,3 +2,5 @@
#include "stage.hpp"
CSMDoc::Stage::~Stage() {}
void CSMDoc::Stage::updateUserSetting (const QString& name, const QStringList& value) {}

View file

@ -8,6 +8,8 @@
#include "messages.hpp"
class QString;
namespace CSMDoc
{
class Stage
@ -21,6 +23,9 @@ namespace CSMDoc
virtual void perform (int stage, Messages& messages) = 0;
///< Messages resulting from this stage will be appended to \a messages.
/// Default-implementation: ignore
virtual void updateUserSetting (const QString& name, const QStringList& value);
};
}

View file

@ -303,7 +303,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
autoDelete->setDefaultValue ("true");
}
declareSection ("script-editor", "Script Editor");
declareSection ("script-editor", "Scripts");
{
Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers");
lineNum->setDefaultValue ("true");
@ -322,6 +322,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
"\nA name from the list of colors defined in the list of SVG color keyword names."
"\nX11 color names may also work.";
QString modeNormal ("Normal");
QStringList modes;
modes << "Ignore" << modeNormal << "Strict";
Setting *warnings = createSetting (Type_ComboBox, "warnings",
"Warning Mode");
warnings->setDeclaredValues (modes);
warnings->setDefaultValue (modeNormal);
warnings->setToolTip ("<ul>How to handle warning messages during compilation:<p>"
"<li>Ignore: Do not report warning</li>"
"<li>Normal: Report warning as a warning</li>"
"<li>Strict: Promote warning to an error</li>"
"</ul>");
Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int");
formatInt->setDefaultValues (QStringList() << "Dark magenta");
formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip);

View file

@ -30,9 +30,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
// check the number of pathgrid points
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()))
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<int> duplList;
@ -51,7 +51,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
std::ostringstream ss;
ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0
<< " 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;
}
}
@ -64,7 +64,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{
std::ostringstream ss;
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;
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)
{
std::ostringstream ss;
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
@ -101,7 +101,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{
std::ostringstream ss;
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
<< ", y=" << pathgrid.mPoints[i].mY
<< ", 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);
break;
@ -143,7 +143,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY
<< ", 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

@ -6,24 +6,18 @@
#include "../world/columns.hpp"
CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
: mId (id), mMessage (message), mHint (hint)
{}
CSMTools::ReportModel::ReportModel (bool fieldColumn)
CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn)
: mColumnField (-1), mColumnSeverity (-1)
{
if (fieldColumn)
{
mColumnField = 3;
mColumnDescription = 4;
}
else
{
mColumnDescription = 3;
int index = 3;
mColumnField = -1;
}
if (severityColumn)
mColumnSeverity = index++;
if (fieldColumn)
mColumnField = index++;
mColumnDescription = index;
}
int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const
@ -88,6 +82,18 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
return QString::fromUtf8 (field.c_str());
}
if (index.column()==mColumnSeverity)
{
switch (mRows.at (index.row()).mSeverity)
{
case CSMDoc::Message::Severity_Info: return "Information";
case CSMDoc::Message::Severity_Warning: return "Warning";
case CSMDoc::Message::Severity_Error: return "Error";
case CSMDoc::Message::Severity_SeriousError: return "Serious Error";
case CSMDoc::Message::Severity_Default: break;
}
}
return QVariant();
}
@ -112,6 +118,9 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta
if (section==mColumnField)
return "Field";
if (section==mColumnSeverity)
return "Severity";
return "-";
}
@ -132,19 +141,18 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true;
}
void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
void CSMTools::ReportModel::add (const CSMDoc::Message& message)
{
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (Line (id, message, hint));
mRows.push_back (message);
endInsertRows();
}
void CSMTools::ReportModel::flagAsReplaced (int index)
{
Line& line = mRows.at (index);
CSMDoc::Message& line = mRows.at (index);
std::string hint = line.mHint;
if (hint.empty() || hint[0]!='R')
@ -176,3 +184,16 @@ void CSMTools::ReportModel::clear()
endRemoveRows();
}
}
int CSMTools::ReportModel::countErrors() const
{
int count = 0;
for (std::vector<CSMDoc::Messages::Message>::const_iterator iter (mRows.begin());
iter!=mRows.end(); ++iter)
if (iter->mSeverity==CSMDoc::Message::Severity_Error ||
iter->mSeverity==CSMDoc::Message::Severity_SeriousError)
++count;
return count;
}

View file

@ -6,6 +6,8 @@
#include <QAbstractTableModel>
#include "../doc/messages.hpp"
#include "../world/universalid.hpp"
namespace CSMTools
@ -14,17 +16,7 @@ namespace CSMTools
{
Q_OBJECT
struct Line
{
Line (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint);
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
std::vector<Line> mRows;
std::vector<CSMDoc::Messages::Message> mRows;
// Fixed columns
enum Columns
@ -35,10 +27,11 @@ namespace CSMTools
// Configurable columns
int mColumnDescription;
int mColumnField;
int mColumnSeverity;
public:
ReportModel (bool fieldColumn = false);
ReportModel (bool fieldColumn = false, bool severityColumn = true);
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
@ -50,8 +43,7 @@ namespace CSMTools
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = "");
void add (const CSMDoc::Message& message);
void flagAsReplaced (int index);
@ -60,6 +52,9 @@ namespace CSMTools
std::string getHint (int row) const;
void clear();
// Return number of messages with Error or SeriousError severity.
int countErrors() const;
};
}

View file

@ -11,6 +11,17 @@
#include "../world/data.hpp"
CSMDoc::Message::Severity CSMTools::ScriptCheckStage::getSeverity (Type type)
{
switch (type)
{
case WarningMessage: return CSMDoc::Message::Severity_Warning;
case ErrorMessage: return CSMDoc::Message::Severity_Error;
}
return CSMDoc::Message::Severity_SeriousError;
}
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
Type type)
{
@ -18,11 +29,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
if (type==ErrorMessage)
stream << "error ";
else
stream << "warning ";
stream
<< "script " << mFile
<< ", line " << loc.mLine << ", column " << loc.mColumn
@ -32,19 +38,21 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
hintStream << "l:" << loc.mLine << " " << loc.mColumn;
mMessages->add (id, stream.str(), hintStream.str());
mMessages->add (id, stream.str(), hintStream.str(), getSeverity (type));
}
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
mMessages->push_back (std::make_pair (id,
(type==ErrorMessage ? "error: " : "warning: ") + message));
std::ostringstream stream;
stream << "script " << mFile << ": " << message;
mMessages->add (id, stream.str(), "", getSeverity (type));
}
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document)
: mDocument (document), mContext (document.getData()), mMessages (0)
: mDocument (document), mContext (document.getData()), mMessages (0), mWarningMode (Mode_Ignore)
{
/// \todo add an option to configure warning mode
setWarningsMode (0);
@ -58,6 +66,7 @@ int CSMTools::ScriptCheckStage::setup()
mContext.clear();
mMessages = 0;
mId.clear();
Compiler::ErrorHandler::reset();
return mDocument.getData().getScripts().getSize();
}
@ -72,6 +81,13 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
mMessages = &messages;
switch (mWarningMode)
{
case Mode_Ignore: setWarningsMode (0); break;
case Mode_Normal: setWarningsMode (1); break;
case Mode_Strict: setWarningsMode (2); break;
}
try
{
const CSMWorld::Data& data = mDocument.getData();
@ -93,9 +109,24 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
messages.push_back (std::make_pair (id,
std::string ("Critical compile error: ") + error.what()));
std::ostringstream stream;
stream << "script " << mFile << ": " << error.what();
messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError);
}
mMessages = 0;
}
void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value)
{
if (name=="script-editor/warnings" && !value.isEmpty())
{
if (value.at (0)=="Ignore")
mWarningMode = Mode_Ignore;
else if (value.at (0)=="Normal")
mWarningMode = Mode_Normal;
else if (value.at (0)=="Strict")
mWarningMode = Mode_Strict;
}
}

View file

@ -18,13 +18,23 @@ namespace CSMTools
/// \brief VerifyStage: make sure that scripts compile
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
{
enum WarningMode
{
Mode_Ignore,
Mode_Normal,
Mode_Strict
};
const CSMDoc::Document& mDocument;
Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext;
std::string mId;
std::string mFile;
CSMDoc::Messages *mMessages;
WarningMode mWarningMode;
CSMDoc::Message::Severity getSeverity (Type type);
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user.
@ -40,6 +50,8 @@ namespace CSMTools
virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
virtual void updateUserSetting (const QString& name, const QStringList& value);
};
}

View file

@ -280,7 +280,7 @@ void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBas
bool CSMTools::Search::verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model,
const CSMWorld::UniversalId& id, const std::string& messageHint) const
{
CSMDoc::Messages messages;
CSMDoc::Messages messages (CSMDoc::Message::Severity_Info);
int row = model->getModelIndex (id.getId(),
model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row();

View file

@ -21,6 +21,8 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document)
iter!=types.end(); ++iter)
appendStage (new SearchStage (&dynamic_cast<CSMWorld::IdTableBase&> (
*document.getData().getTableModel (*iter))));
setDefaultSeverity (CSMDoc::Message::Severity_Info);
}
void CSMTools::SearchOperation::configure (const Search& search)

View file

@ -51,11 +51,15 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
{
mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
std::vector<QString> settings;
settings.push_back ("script-editor/warnings");
mVerifierOperation->configureSettings (settings);
connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
std::vector<std::string> mandatoryIds; // I want C++11, damn it!
mandatoryIds.push_back ("Day");
@ -120,9 +124,8 @@ CSMTools::Tools::Tools (CSMDoc::Document& document)
connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mSearch,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
}
CSMTools::Tools::~Tools()
@ -143,19 +146,24 @@ CSMTools::Tools::~Tools()
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));
mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1;
int reportNumber = reportId.getType()==CSMWorld::UniversalId::Type_VerificationResults ?
reportId.getIndex() : mNextReportNumber++;
if (mReports.find (reportNumber)==mReports.end())
mReports.insert (std::make_pair (reportNumber, new ReportModel));
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
getVerifier()->start();
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1);
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, reportNumber);
}
CSMWorld::UniversalId CSMTools::Tools::newSearch()
{
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true)));
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true, false)));
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1);
}
@ -210,12 +218,11 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId&
return mReports.at (id.getIndex());
}
void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type)
void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type)
{
std::map<int, int>::iterator iter = mActiveReports.find (type);
if (iter!=mActiveReports.end())
mReports[iter->second]->add (id, message, hint);
mReports[iter->second]->add (message);
}

View file

@ -57,8 +57,11 @@ namespace CSMTools
virtual ~Tools();
CSMWorld::UniversalId runVerifier();
///< \return ID of the report for this verification run
/// \param reportId If a valid VerificationResults ID, run verifier for the
/// 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.
CSMWorld::UniversalId newSearch();
@ -75,8 +78,7 @@ namespace CSMTools
private slots:
void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void verifierMessage (const CSMDoc::Message& message, int type);
signals:

View file

@ -100,7 +100,8 @@ bool CSMWorld::ColumnBase::isId (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)

View file

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

View file

@ -2308,6 +2308,78 @@ namespace CSMWorld
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

View file

@ -311,6 +311,10 @@ namespace CSMWorld
{ ColumnId_WaterLevel, "Water Level" },
{ ColumnId_MapColor, "Map Color" },
{ ColumnId_FileFormat, "File Format" },
{ ColumnId_FileDescription, "File Description" },
{ ColumnId_Author, "Author" },
{ ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" },
{ ColumnId_UseValue3, "Use value 3" },

View file

@ -302,6 +302,10 @@ namespace CSMWorld
ColumnId_WaterLevel = 273,
ColumnId_MapColor = 274,
ColumnId_FileFormat = 275,
ColumnId_FileDescription = 276,
ColumnId_Author = 277,
// Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values.
ColumnId_UseValue1 = 0x10000,

View file

@ -475,6 +475,14 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
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 (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
@ -515,6 +523,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video);
addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData);
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
}
@ -803,6 +812,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id)
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)
{
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -847,9 +861,15 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
mBase = base;
mProject = project;
mAuthor = mReader->getAuthor();
mDescription = mReader->getDesc();
if (!mProject && !mBase)
{
MetaData metaData;
metaData.mId = "sys::meta";
metaData.load (*mReader);
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
}
return mReader->getRecordCount();
}
@ -923,7 +943,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& 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");
messages.add (id, "Logic error: cell index out of bounds", "", CSMDoc::Message::Severity_Error);
index = mCells.getSize()-1;
}
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index));
@ -984,7 +1004,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
else
{
messages.add (UniversalId::Type_None,
"Trying to delete dialogue record " + id + " which does not exist");
"Trying to delete dialogue record " + id + " which does not exist",
"", CSMDoc::Message::Severity_Warning);
}
}
else
@ -1001,7 +1022,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (!mDialogue)
{
messages.add (UniversalId::Type_None,
"Found info record not following a dialogue record");
"Found info record not following a dialogue record", "", CSMDoc::Message::Severity_Error);
mReader->skipRecord();
break;
@ -1044,7 +1065,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (unhandledRecord)
{
messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString());
messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString(), "",
CSMDoc::Message::Severity_Error);
mReader->skipRecord();
}
@ -1101,26 +1123,6 @@ int CSMWorld::Data::count (RecordBase::State state) const
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> ids;

View file

@ -44,6 +44,7 @@
#include "infocollection.hpp"
#include "nestedinfocollection.hpp"
#include "pathgrid.hpp"
#include "metadata.hpp"
#ifndef Q_MOC_RUN
#include "subcellcollection.hpp"
#endif
@ -94,11 +95,10 @@ namespace CSMWorld
RefIdCollection mReferenceables;
RefCollection mRefs;
IdCollection<ESM::Filter> mFilters;
Collection<MetaData> mMetaData;
const ResourcesManager& mResourcesManager;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
std::string mAuthor;
std::string mDescription;
ESM::ESMReader *mReader;
const ESM::Dialogue *mDialogue; // last loaded dialogue
bool mBase;
@ -238,6 +238,8 @@ namespace CSMWorld
/// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const;
const MetaData& getMetaData() const;
QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown.
///
@ -267,14 +269,6 @@ namespace CSMWorld
int count (RecordBase::State state) const;
///< 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;
signals:
void idListChanged();

View file

@ -24,6 +24,7 @@ namespace
types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction;
types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global;
types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon;
types[CSMWorld::ColumnBase::Display_Journal ] = CSMWorld::UniversalId::Type_Journal;
types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh;
types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable;
@ -37,6 +38,7 @@ namespace
types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell;
types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture;
types[CSMWorld::ColumnBase::Display_Topic ] = CSMWorld::UniversalId::Type_Topic;
types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable;
return types;

View file

@ -97,7 +97,8 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int
return false;
// 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;
// reorder

View file

@ -1,12 +1,24 @@
#include "infotableproxymodel.hpp"
#include <components/misc/stringops.hpp>
#include "idtablebase.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)
: IdTableProxyModel(parent),
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);
}
@ -15,44 +27,53 @@ void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceMod
{
IdTableProxyModel::setSourceModel(sourceModel);
mSourceModel = dynamic_cast<IdTableBase *>(sourceModel);
connect(mSourceModel,
SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)),
this,
SLOT(modelDataChanged(const QModelIndex &, const QModelIndex &)));
mFirstRowCache.clear();
if (mSourceModel != NULL)
{
connect(mSourceModel,
SIGNAL(rowsInserted(const QModelIndex &, int, int)),
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
{
QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.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);
}
int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
{
Columns::ColumnId columnId = Columns::ColumnId_Topic;
if (mType == UniversalId::Type_JournalInfos)
{
columnId = Columns::ColumnId_Journal;
}
int column = mSourceModel->findColumnIndex(columnId);
QString info = mSourceModel->data(mSourceModel->index(currentRow, column)).toString();
int row = currentRow;
int column = mSourceModel->findColumnIndex(mInfoColumnId);
QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString());
if (mFirstRowCache.contains(info))
{
return mFirstRowCache[info];
}
while (--currentRow >= 0 &&
mSourceModel->data(mSourceModel->index(currentRow, column)) == info);
while (--row >= 0 &&
toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()) == info);
++row;
mFirstRowCache[info] = currentRow + 1;
return currentRow + 1;
mFirstRowCache[info] = row;
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();
}

View file

@ -4,6 +4,7 @@
#include <QHash>
#include "idtableproxymodel.hpp"
#include "columns.hpp"
#include "universalid.hpp"
namespace CSMWorld
@ -16,6 +17,8 @@ namespace CSMWorld
UniversalId::Type mType;
IdTableBase *mSourceModel;
Columns::ColumnId mInfoColumnId;
///< Contains ID for Topic or Journal ID
mutable QHash<QString, int> mFirstRowCache;
@ -31,7 +34,7 @@ namespace CSMWorld
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
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

@ -192,4 +192,8 @@ void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& top
emit dataChanged(index(0,0),
index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1));
}
else if (topLeft.parent() == parent && bottomRight.parent() == parent)
{
emit dataChanged(index(topLeft.row(), topLeft.column()), index(bottomRight.row(), bottomRight.column()));
}
}

View file

@ -264,6 +264,8 @@ namespace
{ CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture },
{ CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video },
{ CSMWorld::UniversalId::Type_Global, CSMWorld::ColumnBase::Display_GlobalVariable },
{ CSMWorld::UniversalId::Type_BodyPart, CSMWorld::ColumnBase::Display_BodyPart },
{ CSMWorld::UniversalId::Type_Enchantment, CSMWorld::ColumnBase::Display_Enchantment },
{ CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker
};

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_Pathgrids, "Pathgrids", 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
};
@ -120,6 +121,7 @@ namespace
{ 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_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
};

View file

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

View file

@ -87,6 +87,10 @@ void CSVDoc::View::setupFileMenu()
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
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);
connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close);
@ -844,6 +848,11 @@ void CSVDoc::View::addSearchSubView()
addSubView (mDocument->newSearch());
}
void CSVDoc::View::addMetaDataSubView()
{
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta"));
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);

View file

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

View file

@ -4,12 +4,23 @@
#include "reporttable.hpp"
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&)),
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)
@ -21,3 +32,15 @@ void CSVTools::ReportSubView::updateUserSetting (const QString &name, const QStr
{
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
ReportTable *mTable;
CSMDoc::Document& mDocument;
int mRefreshState;
public:
@ -28,6 +30,10 @@ namespace CSVTools
virtual void setEditLock (bool locked);
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)
menu.addAction (mReplaceAction);
}
if (mRefreshAction)
menu.addAction (mRefreshAction);
menu.exec (event->globalPos());
}
@ -134,8 +136,10 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
}
CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
const CSMWorld::UniversalId& id, bool richTextDescription, QWidget *parent)
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id))
const CSMWorld::UniversalId& id, bool richTextDescription, int refreshState,
QWidget *parent)
: CSVWorld::DragRecordTable (document, parent), mModel (document.getReport (id)),
mRefreshAction (0), mRefreshState (refreshState)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
horizontalHeader()->setSectionResizeMode (QHeaderView::Interactive);
@ -171,6 +175,14 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest()));
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::ShiftModifier, Action_Remove));
mDoubleClickActions.insert (std::make_pair (Qt::ControlModifier, Action_EditAndRemove));
@ -287,3 +299,9 @@ void CSVTools::ReportTable::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 *mRemoveAction;
QAction *mReplaceAction;
QAction *mRefreshAction;
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
int mRefreshState;
private:
@ -49,8 +51,11 @@ namespace CSVTools
public:
/// \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,
bool richTextDescription, QWidget *parent = 0);
bool richTextDescription, int refreshState = 0, QWidget *parent = 0);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
@ -71,11 +76,17 @@ namespace CSVTools
void removeSelection();
public slots:
void stateChanged (int state, CSMDoc::Document *document);
signals:
void editRequest (const CSMWorld::UniversalId& id, const std::string& hint);
void replaceRequest();
void refreshRequest();
};
}

View file

@ -0,0 +1,41 @@
#include "droplineedit.hpp"
#include <QDropEvent>
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/universalid.hpp"
#include "../world/dragdroputils.hpp"
CSVWidget::DropLineEdit::DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent)
: QLineEdit(parent),
mDropType(type)
{
setAcceptDrops(true);
}
void CSVWidget::DropLineEdit::dragEnterEvent(QDragEnterEvent *event)
{
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{
event->acceptProposedAction();
}
}
void CSVWidget::DropLineEdit::dragMoveEvent(QDragMoveEvent *event)
{
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{
event->accept();
}
}
void CSVWidget::DropLineEdit::dropEvent(QDropEvent *event)
{
if (CSVWorld::DragDropUtils::canAcceptData(*event, mDropType))
{
CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, mDropType);
setText(QString::fromUtf8(id.getId().c_str()));
emit tableMimeDataDropped(id, CSVWorld::DragDropUtils::getTableMimeData(*event)->getDocumentPtr());
}
}

View file

@ -0,0 +1,41 @@
#ifndef CSV_WIDGET_DROPLINEEDIT_HPP
#define CSV_WIDGET_DROPLINEEDIT_HPP
#include <QLineEdit>
#include "../../model/world/columnbase.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
class TableMimeData;
class UniversalId;
}
namespace CSVWidget
{
class DropLineEdit : public QLineEdit
{
Q_OBJECT
CSMWorld::ColumnBase::Display mDropType;
///< The accepted Display type for this LineEdit.
public:
DropLineEdit(CSMWorld::ColumnBase::Display type, QWidget *parent = 0);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
signals:
void tableMimeDataDropped(const CSMWorld::UniversalId &id, const CSMDoc::Document *document);
};
}
#endif

View file

@ -15,8 +15,8 @@ void CSVWorld::Creator::setScope (unsigned int scope)
CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {}
CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
CSVWorld::Creator *CSVWorld::NullCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return 0;
}

View file

@ -5,16 +5,14 @@
#include <QWidget>
#include "../../model/world/universalid.hpp"
#include "../../model/doc/document.hpp"
#include "../../model/world/scope.hpp"
#include "../../model/world/universalid.hpp"
class QUndoStack;
namespace CSMWorld
namespace CSMDoc
{
class Data;
class UniversalId;
class Document;
}
namespace CSVWorld
@ -59,8 +57,7 @@ namespace CSVWorld
virtual ~CreatorFactoryBase();
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const = 0;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const = 0;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function can return a 0-pointer, which means no UI for creating/deleting
@ -72,8 +69,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function always returns 0.
@ -84,8 +80,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
///
/// \note The function can return a 0-pointer, which means no UI for creating/deleting
@ -93,10 +88,10 @@ namespace CSVWorld
};
template<class CreatorT, unsigned int scope>
Creator *CreatorFactory<CreatorT, scope>::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const
Creator *CreatorFactory<CreatorT, scope>::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
std::auto_ptr<CreatorT> creator (new CreatorT (data, undoStack, id));
std::auto_ptr<CreatorT> creator (new CreatorT (document.getData(), document.getUndoStack(), id));
creator->setScope (scope);

View file

@ -3,6 +3,8 @@
#include <components/esm/loaddial.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
@ -22,14 +24,14 @@ CSVWorld::DialogueCreator::DialogueCreator (CSMWorld::Data& data, QUndoStack& un
: GenericCreator (data, undoStack, id, true), mType (type)
{}
CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Topic);
return new DialogueCreator (document.getData(), document.getUndoStack(), id, ESM::Dialogue::Topic);
}
CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const
CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new DialogueCreator (data, undoStack, id, ESM::Dialogue::Journal);
return new DialogueCreator (document.getData(), document.getUndoStack(), id, ESM::Dialogue::Journal);
}

View file

@ -23,8 +23,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
@ -32,8 +31,7 @@ namespace CSVWorld
{
public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const;
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
}

View file

@ -34,6 +34,7 @@
#include "../../model/doc/document.hpp"
#include "../widget/coloreditor.hpp"
#include "../widget/droplineedit.hpp"
#include "recordstatusdelegate.hpp"
#include "util.hpp"
@ -63,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())
{
label->setText(v.toString());
}
else //else we are facing enums
else if (CSMWorld::Columns::hasEnums (columnId))
{
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()));
}
else
{
label->setText (v.toString());
}
}
void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
@ -129,52 +138,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcherProxy::getEditor() const
return mEditor;
}
void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document)
{
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(mEditor);
{
if (!lineEdit || !mIndexWrapper.get())
{
return;
}
}
for (unsigned i = 0; i < data.size(); ++i)
{
CSMWorld::UniversalId::Type type = data[i].getType();
if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable)
{
if (type == CSMWorld::UniversalId::Type_Activator
|| type == CSMWorld::UniversalId::Type_Potion
|| type == CSMWorld::UniversalId::Type_Apparatus
|| type == CSMWorld::UniversalId::Type_Armor
|| type == CSMWorld::UniversalId::Type_Book
|| type == CSMWorld::UniversalId::Type_Clothing
|| type == CSMWorld::UniversalId::Type_Container
|| type == CSMWorld::UniversalId::Type_Creature
|| type == CSMWorld::UniversalId::Type_Door
|| type == CSMWorld::UniversalId::Type_Ingredient
|| type == CSMWorld::UniversalId::Type_CreatureLevelledList
|| type == CSMWorld::UniversalId::Type_ItemLevelledList
|| type == CSMWorld::UniversalId::Type_Light
|| type == CSMWorld::UniversalId::Type_Lockpick
|| type == CSMWorld::UniversalId::Type_Miscellaneous
|| type == CSMWorld::UniversalId::Type_Npc
|| type == CSMWorld::UniversalId::Type_Probe
|| type == CSMWorld::UniversalId::Type_Repair
|| type == CSMWorld::UniversalId::Type_Static
|| type == CSMWorld::UniversalId::Type_Weapon)
{
type = CSMWorld::UniversalId::Type_Referenceable;
}
}
if (mDisplay == CSMWorld::TableMimeData::convertEnums(type))
{
emit tableMimeDataDropped(mEditor, mIndexWrapper->mIndex, data[i], document);
emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay);
break;
}
}
}
/*
==============================DialogueDelegateDispatcher==========================================
*/
@ -306,16 +269,12 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
// NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry
// is required here
if (qobject_cast<DropLineEdit*>(editor))
if (qobject_cast<CSVWidget::DropLineEdit*>(editor))
{
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
connect(editor, SIGNAL(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)),
proxy, SLOT(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)));
connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
connect(editor, SIGNAL(tableMimeDataDropped(const CSMWorld::UniversalId&, const CSMDoc::Document*)),
proxy, SLOT(editorDataCommited()));
}
else if (qobject_cast<QCheckBox*>(editor))
{
@ -386,9 +345,6 @@ mCommandDispatcher (commandDispatcher),
mDocument (document)
{
remake (row);
connect(mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
}
void CSVWorld::EditWidget::remake(int row)
@ -600,12 +556,38 @@ void CSVWorld::EditWidget::remake(int row)
this->setWidgetResizable(true);
}
/*
==============================DialogueSubView==========================================
*/
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory, bool sorting) :
QVBoxLayout& CSVWorld::SimpleDialogueSubView::getMainLayout()
{
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),
mEditWidget(0),
mMainLayout(NULL),
@ -622,162 +604,19 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
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);
setWidget (mainWidget);
mEditWidget = new EditWidget(mainWidget,
mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false);
connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
mMainLayout->addWidget(mEditWidget);
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
mMainLayout->addWidget (mBottom =
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), 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));
mMainLayout->addLayout (buttonsLayout);
setWidget (mainWidget);
}
void CSVWorld::DialogueSubView::prevId ()
{
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)
void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked)
{
if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid
return;
@ -796,7 +635,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));
@ -829,7 +668,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));
@ -844,56 +683,14 @@ void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent,
}
}
void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor,
const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document)
{
if (document == &mDocument)
{
qobject_cast<DropLineEdit*>(editor)->setText(id.getId().c_str());
}
}
void CSVWorld::DialogueSubView::requestFocus (const std::string& id)
void CSVWorld::SimpleDialogueSubView::requestFocus (const std::string& id)
{
changeCurrentId(id);
mEditWidget->remake(mTable->getModelIndex (id, 0).row());
}
void CSVWorld::DialogueSubView::cloneRequest ()
{
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)
void CSVWorld::SimpleDialogueSubView::changeCurrentId (const std::string& newId)
{
std::vector<std::string> selection;
mCurrentId = std::string(newId);
@ -901,3 +698,186 @@ void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId)
selection.push_back(mCurrentId);
mCommandDispatcher.setSelection(selection);
}
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting)
: SimpleDialogueSubView (id, document)
{
// bottom box
getMainLayout().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&)));
// 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;
}
while (newRow < getTable().rowCount())
{
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))
{
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

@ -86,18 +86,12 @@ namespace CSVWorld
public slots:
void editorDataCommited();
void setIndex(const QModelIndex& index);
void tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data,
const CSMDoc::Document* document);
signals:
void editorDataCommited(QWidget* editor,
const QModelIndex& index,
CSMWorld::ColumnBase::Display display);
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document);
};
class DialogueDelegateDispatcher : public QAbstractItemDelegate
@ -153,11 +147,6 @@ namespace CSVWorld
private slots:
void editorDataCommited(QWidget* editor, const QModelIndex& index,
CSMWorld::ColumnBase::Display display);
signals:
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document);
};
class EditWidget : public QScrollArea
@ -182,14 +171,9 @@ namespace CSVWorld
virtual ~EditWidget();
void remake(int row);
signals:
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document);
};
class DialogueSubView : public CSVDoc::SubView
class SimpleDialogueSubView : public CSVDoc::SubView
{
Q_OBJECT
@ -200,23 +184,55 @@ namespace CSVWorld
std::string mCurrentId;
bool mLocked;
const CSMDoc::Document& mDocument;
TableBottomBox* mBottom;
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:
DialogueSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document,
const CreatorFactoryBase& creatorFactory,
bool sorting = false);
SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
virtual void setEditLock (bool locked);
private:
void changeCurrentId(const std::string& newCurrent);
private slots:
void dataChanged(const QModelIndex & index);
///\brief we need to care for deleting currently edited record
void requestFocus (const std::string& id);
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
};
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();
@ -224,19 +240,6 @@ namespace CSVWorld
void showPreview();
void viewRecord();
void cloneRequest();
void dataChanged(const QModelIndex & index);
///\brief we need to care for deleting currently edited record
void tableMimeDataDropped(QWidget* editor, const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document);
void requestFocus (const std::string& id);
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end);
};
}

View file

@ -0,0 +1,26 @@
#include "dragdroputils.hpp"
#include <QDropEvent>
#include "../../model/world/tablemimedata.hpp"
const CSMWorld::TableMimeData *CSVWorld::DragDropUtils::getTableMimeData(const QDropEvent &event)
{
return dynamic_cast<const CSMWorld::TableMimeData *>(event.mimeData());
}
bool CSVWorld::DragDropUtils::canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type)
{
const CSMWorld::TableMimeData *data = getTableMimeData(event);
return data != NULL && data->holdsType(type);
}
CSMWorld::UniversalId CSVWorld::DragDropUtils::getAcceptedData(const QDropEvent &event,
CSMWorld::ColumnBase::Display type)
{
if (canAcceptData(event, type))
{
return getTableMimeData(event)->returnMatching(type);
}
return CSMWorld::UniversalId::Type_None;
}

View file

@ -0,0 +1,29 @@
#ifndef CSV_WORLD_DRAGDROPUTILS_HPP
#define CSV_WORLD_DRAGDROPUTILS_HPP
#include "../../model/world/columnbase.hpp"
class QDropEvent;
namespace CSMWorld
{
class TableMimeData;
class UniversalId;
}
namespace CSVWorld
{
namespace DragDropUtils
{
const CSMWorld::TableMimeData *getTableMimeData(const QDropEvent &event);
bool canAcceptData(const QDropEvent &event, CSMWorld::ColumnBase::Display type);
///< Checks whether the \a event contains a valid CSMWorld::TableMimeData that holds the \a type
CSMWorld::UniversalId getAcceptedData(const QDropEvent &event, CSMWorld::ColumnBase::Display type);
///< Gets the accepted data from the \a event using the \a type
///< \return Type_None if the \a event data doesn't holds the \a type
}
}
#endif

View file

@ -1,12 +1,24 @@
#include "dragrecordtable.hpp"
#include <QDrag>
#include <QDragEnterEvent>
#include "../../model/doc/document.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "dragrecordtable.hpp"
#include "../../model/world/commands.hpp"
#include "dragdroputils.hpp"
void CSVWorld::DragRecordTable::startDragFromTable (const CSVWorld::DragRecordTable& table)
{
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument);
std::vector<CSMWorld::UniversalId> records = table.getDraggedRecords();
if (records.empty())
{
return;
}
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (records, mDocument);
if (mime)
{
@ -21,7 +33,9 @@ CSVWorld::DragRecordTable::DragRecordTable (CSMDoc::Document& document, QWidget*
QTableView(parent),
mDocument(document),
mEditLock(false)
{}
{
setAcceptDrops(true);
}
void CSVWorld::DragRecordTable::setEditLock (bool locked)
{
@ -35,5 +49,51 @@ void CSVWorld::DragRecordTable::dragEnterEvent(QDragEnterEvent *event)
void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
QModelIndex index = indexAt(event->pos());
if (CSVWorld::DragDropUtils::canAcceptData(*event, getIndexDisplayType(index)))
{
if (index.flags() & Qt::ItemIsEditable)
{
event->accept();
}
}
else
{
event->ignore();
}
}
void CSVWorld::DragRecordTable::dropEvent(QDropEvent *event)
{
QModelIndex index = indexAt(event->pos());
CSMWorld::ColumnBase::Display display = getIndexDisplayType(index);
if (CSVWorld::DragDropUtils::canAcceptData(*event, display))
{
const CSMWorld::TableMimeData *data = CSVWorld::DragDropUtils::getTableMimeData(*event);
if (data->fromDocument(mDocument))
{
CSMWorld::UniversalId id = CSVWorld::DragDropUtils::getAcceptedData(*event, display);
QVariant newIndexData = QString::fromUtf8(id.getId().c_str());
QVariant oldIndexData = index.data(Qt::EditRole);
if (newIndexData != oldIndexData)
{
mDocument.getUndoStack().push(new CSMWorld::ModifyCommand(*model(), index, newIndexData));
}
}
}
}
CSMWorld::ColumnBase::Display CSVWorld::DragRecordTable::getIndexDisplayType(const QModelIndex &index) const
{
Q_ASSERT(model() != NULL);
if (index.isValid())
{
QVariant display = model()->headerData(index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display);
if (display.isValid())
{
return static_cast<CSMWorld::ColumnBase::Display>(display.toInt());
}
}
return CSMWorld::ColumnBase::Display_None;
}

View file

@ -4,6 +4,8 @@
#include <QTableView>
#include <QEvent>
#include "../../model/world/columnbase.hpp"
class QWidget;
class QAction;
@ -38,6 +40,11 @@ namespace CSVWorld
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
private:
CSMWorld::ColumnBase::Display getIndexDisplayType(const QModelIndex &index) const;
};
}

View file

@ -133,6 +133,15 @@ CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undo
mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0),
mScopeLabel (0), mCloneMode (false)
{
// If the collection ID has a parent type, use it instead.
// It will change IDs with Record/SubRecord class (used for creators in Dialogue subviews)
// to IDs with general RecordList class (used for creators in Table subviews).
CSMWorld::UniversalId::Type listParentType = CSMWorld::UniversalId::getParentType(mListId.getType());
if (listParentType != CSMWorld::UniversalId::Type_None)
{
mListId = listParentType;
}
mLayout = new QHBoxLayout;
mLayout->setContentsMargins (0, 0, 0, 0);

View file

@ -13,10 +13,12 @@ class QLineEdit;
class QHBoxLayout;
class QComboBox;
class QLabel;
class QUndoStack;
namespace CSMWorld
{
class CreateCommand;
class Data;
}
namespace CSVWorld

View file

@ -2,6 +2,8 @@
#include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
CSVWorld::IdCompletionDelegate::IdCompletionDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent)
@ -26,7 +28,7 @@ QWidget *CSVWorld::IdCompletionDelegate::createEditor(QWidget *parent,
}
CSMWorld::IdCompletionManager &completionManager = getDocument().getIdCompletionManager();
DropLineEdit *editor = new DropLineEdit(parent);
CSVWidget::DropLineEdit *editor = new CSVWidget::DropLineEdit(display, parent);
editor->setCompleter(completionManager.getCompleter(display).get());
return editor;
}

View file

@ -4,15 +4,19 @@
#include <algorithm>
#include <QLabel>
#include <QLineEdit>
#include <QUuid>
#include <components/misc/stringops.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::InfoCreator::getId() const
{
@ -39,13 +43,19 @@ void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& com
}
CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager)
: GenericCreator (data, undoStack, id)
{
QLabel *label = new QLabel ("Topic", this);
insertBeforeButtons (label, false);
mTopic = new QLineEdit (this);
CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic;
if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos)
{
displayType = CSMWorld::ColumnBase::Display_Journal;
}
mTopic = new CSVWidget::DropLineEdit(displayType, this);
mTopic->setCompleter(completionManager.getCompleter(displayType).get());
insertBeforeButtons (mTopic, true);
setManualEditing (false);
@ -100,3 +110,12 @@ void CSVWorld::InfoCreator::topicChanged()
{
update();
}
CSVWorld::Creator *CSVWorld::InfoCreatorFactory::makeCreator(CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new InfoCreator(document.getData(),
document.getUndoStack(),
id,
document.getIdCompletionManager());
}

View file

@ -3,11 +3,15 @@
#include "genericcreator.hpp"
class QLineEdit;
namespace CSMWorld
{
class InfoCollection;
class IdCompletionManager;
}
namespace CSVWidget
{
class DropLineEdit;
}
namespace CSVWorld
@ -16,7 +20,7 @@ namespace CSVWorld
{
Q_OBJECT
QLineEdit *mTopic;
CSVWidget::DropLineEdit *mTopic;
virtual std::string getId() const;
@ -25,7 +29,7 @@ namespace CSVWorld
public:
InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager);
virtual void cloneMode (const std::string& originId,
const CSMWorld::UniversalId::Type type);
@ -43,6 +47,14 @@ namespace CSVWorld
void topicChanged();
};
class InfoCreatorFactory : public CreatorFactoryBase
{
public:
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
}
#endif

View file

@ -14,8 +14,7 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
CSMWorld::UniversalId id,
CSMWorld::NestedTableProxyModel* model,
QWidget* parent)
: QTableView(parent),
mUndoStack(document.getUndoStack()),
: DragRecordTable(document, parent),
mModel(model)
{
mDispatcher = new CSMWorld::CommandDispatcher (document, id, this);
@ -47,8 +46,6 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
setModel(model);
setAcceptDrops(true);
mAddNewRowAction = new QAction (tr ("Add new row"), this);
connect(mAddNewRowAction, SIGNAL(triggered()),
@ -60,12 +57,10 @@ CSVWorld::NestedTable::NestedTable(CSMDoc::Document& document,
this, SLOT(removeRowActionTriggered()));
}
void CSVWorld::NestedTable::dragEnterEvent(QDragEnterEvent *event)
{
}
void CSVWorld::NestedTable::dragMoveEvent(QDragMoveEvent *event)
std::vector<CSMWorld::UniversalId> CSVWorld::NestedTable::getDraggedRecords() const
{
// No drag support for nested tables
return std::vector<CSMWorld::UniversalId>();
}
void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event)
@ -84,16 +79,16 @@ void CSVWorld::NestedTable::contextMenuEvent (QContextMenuEvent *event)
void CSVWorld::NestedTable::removeRowActionTriggered()
{
mUndoStack.push(new CSMWorld::DeleteNestedCommand(*(mModel->model()),
mModel->getParentId(),
selectionModel()->selectedRows().begin()->row(),
mModel->getParentColumn()));
mDocument.getUndoStack().push(new CSMWorld::DeleteNestedCommand(*(mModel->model()),
mModel->getParentId(),
selectionModel()->selectedRows().begin()->row(),
mModel->getParentColumn()));
}
void CSVWorld::NestedTable::addNewRowActionTriggered()
{
mUndoStack.push(new CSMWorld::AddNestedCommand(*(mModel->model()),
mModel->getParentId(),
selectionModel()->selectedRows().size(),
mModel->getParentColumn()));
mDocument.getUndoStack().push(new CSMWorld::AddNestedCommand(*(mModel->model()),
mModel->getParentId(),
selectionModel()->selectedRows().size(),
mModel->getParentColumn()));
}

View file

@ -1,10 +1,10 @@
#ifndef CSV_WORLD_NESTEDTABLE_H
#define CSV_WORLD_NESTEDTABLE_H
#include <QTableView>
#include <QEvent>
class QUndoStack;
#include "dragrecordtable.hpp"
class QAction;
class QContextMenuEvent;
@ -22,13 +22,12 @@ namespace CSMDoc
namespace CSVWorld
{
class NestedTable : public QTableView
class NestedTable : public DragRecordTable
{
Q_OBJECT
QAction *mAddNewRowAction;
QAction *mRemoveRowAction;
QUndoStack& mUndoStack;
CSMWorld::NestedTableProxyModel* mModel;
CSMWorld::CommandDispatcher *mDispatcher;
@ -38,10 +37,7 @@ namespace CSVWorld
CSMWorld::NestedTableProxyModel* model,
QWidget* parent = NULL);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
virtual std::vector<CSMWorld::UniversalId> getDraggedRecords() const;
private:
void contextMenuEvent (QContextMenuEvent *event);

View file

@ -2,12 +2,16 @@
#include "referencecreator.hpp"
#include <QLabel>
#include <QLineEdit>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::ReferenceCreator::getId() const
{
@ -71,13 +75,14 @@ int CSVWorld::ReferenceCreator::getRefNumCount() const
}
CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager)
: GenericCreator (data, undoStack, id)
{
QLabel *label = new QLabel ("Cell", this);
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());
insertBeforeButtons (mCell, true);
setManualEditing (false);
@ -142,3 +147,12 @@ void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId,
CSVWorld::GenericCreator::cloneMode(originId, type);
cellChanged(); //otherwise ok button will remain disabled
}
CSVWorld::Creator *CSVWorld::ReferenceCreatorFactory::makeCreator (CSMDoc::Document& document,
const CSMWorld::UniversalId& id) const
{
return new ReferenceCreator(document.getData(),
document.getUndoStack(),
id,
document.getIdCompletionManager());
}

View file

@ -3,15 +3,24 @@
#include "genericcreator.hpp"
class QLineEdit;
namespace CSMWorld
{
class IdCompletionManager;
}
namespace CSVWidget
{
class DropLineEdit;
}
namespace CSVWorld
{
class ReferenceCreator : public GenericCreator
{
Q_OBJECT
QLineEdit *mCell;
CSVWidget::DropLineEdit *mCell;
std::string mId;
private:
@ -28,7 +37,7 @@ namespace CSVWorld
public:
ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager);
virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type);
@ -46,6 +55,14 @@ namespace CSVWorld
void cellChanged();
};
class ReferenceCreatorFactory : public CreatorFactoryBase
{
public:
virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller.
};
}
#endif

View file

@ -33,9 +33,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
layout->setContentsMargins (QMargins (0, 0, 0, 0));
layout->addWidget (mBottom =
new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id,
this), 0);
layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0);
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));

View file

@ -59,7 +59,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceableCreator> >);
manager.add (CSMWorld::UniversalId::Type_References,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceCreator> >);
new CSVDoc::SubViewFactoryWithCreator<TableSubView, ReferenceCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_Topics,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, TopicCreatorFactory>);
@ -68,10 +68,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_TopicInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >);
new CSVDoc::SubViewFactoryWithCreator<TableSubView, InfoCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_JournalInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >);
new CSVDoc::SubViewFactoryWithCreator<TableSubView, InfoCreatorFactory>);
// Subviews for resources tables
manager.add (CSMWorld::UniversalId::Type_Meshes,
@ -147,16 +147,16 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceableCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Reference,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceCreator> > (false));
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, ReferenceCreatorFactory> (false));
manager.add (CSMWorld::UniversalId::Type_Cell,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<CellCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_JournalInfo,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<InfoCreator> > (false));
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, InfoCreatorFactory> (false));
manager.add (CSMWorld::UniversalId::Type_TopicInfo,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<InfoCreator> >(false));
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, InfoCreatorFactory>(false));
manager.add (CSMWorld::UniversalId::Type_Topic,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, TopicCreatorFactory> (false));
@ -170,6 +170,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Filter,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
manager.add (CSMWorld::UniversalId::Type_MetaData,
new CSVDoc::SubViewFactory<SimpleDialogueSubView >);
//preview
manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>);
}

View file

@ -9,6 +9,8 @@
#include <QString>
#include <QtCore/qnamespace.h>
#include <components/misc/stringops.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp"
@ -131,17 +133,24 @@ void CSVWorld::Table::contextMenuEvent (QContextMenuEvent *event)
{
int row = mProxyModel->mapToSource (
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))==
mModel->data (mModel->index (row-1, column)))
if (row > 0)
{
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))==
mModel->data (mModel->index (row+1, column)))
if (row < mModel->rowCount() - 1)
{
menu.addAction (mMoveDownAction);
QString nextData = mModel->data(mModel->index(row + 1, column)).toString();
if (Misc::StringUtils::ciEqual(curData.toStdString(), nextData.toStdString()))
{
menu.addAction(mMoveDownAction);
}
}
}
}
@ -748,36 +757,6 @@ void CSVWorld::Table::mouseMoveEvent (QMouseEvent* event)
}
}
void CSVWorld::Table::dropEvent(QDropEvent *event)
{
QModelIndex index = indexAt (event->pos());
if (!index.isValid())
{
return;
}
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
if (mime->fromDocument (mDocument))
{
CSMWorld::ColumnBase::Display display = static_cast<CSMWorld::ColumnBase::Display>
(mModel->headerData (index.column(), Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
if (mime->holdsType (display))
{
CSMWorld::UniversalId record (mime->returnMatching (display));
std::auto_ptr<CSMWorld::ModifyCommand> command (new CSMWorld::ModifyCommand
(*mProxyModel, index, QVariant (QString::fromUtf8 (record.getId().c_str()))));
mDocument.getUndoStack().push (command.release());
}
} //TODO handle drops from different document
}
std::vector<std::string> CSVWorld::Table::getColumnsWithDisplay(CSMWorld::ColumnBase::Display display) const
{
const int count = mModel->columnCount();

View file

@ -80,8 +80,6 @@ namespace CSVWorld
void mouseMoveEvent(QMouseEvent *event);
void dropEvent(QDropEvent *event);
protected:
virtual void mouseDoubleClickEvent (QMouseEvent *event);

View file

@ -39,8 +39,10 @@ void CSVWorld::TableBottomBox::updateStatus()
}
}
CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory,
CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent)
CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFactory,
CSMDoc::Document& document,
const CSMWorld::UniversalId& id,
QWidget *parent)
: QWidget (parent), mShowStatusBar (false), mCreating (false)
{
for (int i=0; i<4; ++i)
@ -61,7 +63,7 @@ CSVWorld::TableBottomBox::TableBottomBox (const CreatorFactoryBase& creatorFacto
setLayout (mLayout);
mCreator = creatorFactory.makeCreator (data, undoStack, id);
mCreator = creatorFactory.makeCreator (document, id);
if (mCreator)
{

View file

@ -9,10 +9,9 @@ class QStackedLayout;
class QStatusBar;
class QUndoStack;
namespace CSMWorld
namespace CSMDoc
{
class Data;
class UniversalId;
class Document;
}
namespace CSVWorld
@ -42,8 +41,10 @@ namespace CSVWorld
public:
TableBottomBox (const CreatorFactoryBase& creatorFactory, CSMWorld::Data& data,
QUndoStack& undoStack, const CSMWorld::UniversalId& id, QWidget *parent = 0);
TableBottomBox (const CreatorFactoryBase& creatorFactory,
CSMDoc::Document& document,
const CSMWorld::UniversalId& id,
QWidget *parent = 0);
virtual ~TableBottomBox();

View file

@ -29,7 +29,7 @@ CSVWorld::TableSubView::TableSubView (const CSMWorld::UniversalId& id, CSMDoc::D
layout->setContentsMargins (QMargins (0, 0, 0, 0));
layout->addWidget (mBottom =
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this), 0);
new TableBottomBox (creatorFactory, document, id, this), 0);
layout->insertWidget (0, mTable =
new Table (id, mBottom->canCreateAndDelete(), sorting, document), 2);

View file

@ -17,7 +17,10 @@
#include "../../model/world/commands.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commanddispatcher.hpp"
#include "../widget/coloreditor.hpp"
#include "../widget/droplineedit.hpp"
#include "dialoguespinbox.hpp"
#include "scriptedit.hpp"
@ -229,33 +232,35 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
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:
return new QCheckBox(parent);
case CSMWorld::ColumnBase::Display_String:
case CSMWorld::ColumnBase::Display_Skill:
case CSMWorld::ColumnBase::Display_Script:
case CSMWorld::ColumnBase::Display_Race:
case CSMWorld::ColumnBase::Display_Region:
case CSMWorld::ColumnBase::Display_Class:
case CSMWorld::ColumnBase::Display_Faction:
case CSMWorld::ColumnBase::Display_Miscellaneous:
case CSMWorld::ColumnBase::Display_Sound:
case CSMWorld::ColumnBase::Display_Mesh:
case CSMWorld::ColumnBase::Display_Icon:
case CSMWorld::ColumnBase::Display_Music:
case CSMWorld::ColumnBase::Display_SoundRes:
case CSMWorld::ColumnBase::Display_Texture:
case CSMWorld::ColumnBase::Display_Video:
case CSMWorld::ColumnBase::Display_GlobalVariable:
return new DropLineEdit(parent);
case CSMWorld::ColumnBase::Display_ScriptLines:
return new ScriptEdit (mDocument, ScriptHighlighter::Mode_Console, parent);
case CSMWorld::ColumnBase::Display_String:
// For other Display types (that represent record IDs) with drop support IdCompletionDelegate is used
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:
return QStyledItemDelegate::createEditor (parent, option, index);
@ -324,29 +329,3 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde
}
}
CSVWorld::DropLineEdit::DropLineEdit(QWidget* parent) :
QLineEdit(parent)
{
setAcceptDrops(true);
}
void CSVWorld::DropLineEdit::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void CSVWorld::DropLineEdit::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}
void CSVWorld::DropLineEdit::dropEvent(QDropEvent *event)
{
const CSMWorld::TableMimeData* data(dynamic_cast<const CSMWorld::TableMimeData*>(event->mimeData()));
if (!data) // May happen when non-records (e.g. plain text) are dragged and dropped
return;
emit tableMimeDataDropped(data->getData(), data->getDocumentPtr());
//WIP
}

View file

@ -5,7 +5,6 @@
#include <QAbstractTableModel>
#include <QStyledItemDelegate>
#include <QLineEdit>
#include "../../model/world/columnbase.hpp"
#include "../../model/doc/document.hpp"
@ -91,24 +90,6 @@ namespace CSVWorld
};
class DropLineEdit : public QLineEdit
{
Q_OBJECT
public:
DropLineEdit(QWidget *parent);
private:
void dragEnterEvent(QDragEnterEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void dropEvent(QDropEvent *event);
signals:
void tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document);
};
///< \brief Use commands instead of manipulating the model directly
class CommandDelegate : public QStyledItemDelegate
{

View file

@ -651,9 +651,6 @@ namespace MWMechanics
if (mAllowedNodes.empty())
return;
if (actor.getClass().isPureWaterCreature(actor))
return;
state.moveIn(new AiWanderStorage());
int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size());
@ -700,7 +697,8 @@ namespace MWMechanics
// actor can wander from the spawn position. AiWander assumes that
// pathgrid points are available, and uses them to randomly select wander
// destinations within the allowed set of pathgrid points (nodes).
if(mDistance)
// ... pathgrids don't usually include water, so swimmers ignore them
if (mDistance && !actor.getClass().isPureWaterCreature(actor))
{
float cellXOffset = 0;
float cellYOffset = 0;

View file

@ -44,6 +44,8 @@ std::set<MWMechanics::EffectKey> MWMechanics::Alchemy::listEffects() const
{
const MWWorld::LiveCellRef<ESM::Ingredient> *ingredient = iter->get<ESM::Ingredient>();
std::set<EffectKey> seenEffects;
for (int i=0; i<4; ++i)
if (ingredient->mBase->mData.mEffectID[i]!=-1)
{
@ -51,7 +53,8 @@ std::set<MWMechanics::EffectKey> MWMechanics::Alchemy::listEffects() const
ingredient->mBase->mData.mEffectID[i], ingredient->mBase->mData.mSkills[i]!=-1 ?
ingredient->mBase->mData.mSkills[i] : ingredient->mBase->mData.mAttributes[i]);
++effects[key];
if (seenEffects.insert(key).second)
++effects[key];
}
}
}
@ -460,7 +463,10 @@ MWMechanics::Alchemy::Result MWMechanics::Alchemy::create (const std::string& na
return Result_NoName;
if (listEffects().empty())
{
removeIngredients();
return Result_NoEffects;
}
if (beginEffects() == endEffects())
{

View file

@ -20,7 +20,7 @@ namespace MWMechanics
mKnockdown(false), mKnockdownOneFrame(false), mKnockdownOverOneFrame(false),
mHitRecovery(false), mBlock(false), mMovementFlags(0), mAttackStrength(0.f),
mFallHeight(0), mRecalcMagicka(false), mLastRestock(0,0), mGoldPool(0), mActorId(-1),
mDeathAnimation(0), mIsWerewolf(false), mLevel (0)
mDeathAnimation(0), mLevel (0)
{
for (int i=0; i<4; ++i)
mAiSettings[i] = 0;
@ -55,7 +55,7 @@ namespace MWMechanics
if (index < 0 || index > 7) {
throw std::runtime_error("attribute index is out of range");
}
return (!mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index]);
return mAttributes[index];
}
const DynamicStat<float> &CreatureStats::getHealth() const
@ -139,14 +139,11 @@ namespace MWMechanics
throw std::runtime_error("attribute index is out of range");
}
const AttributeValue& currentValue = !mIsWerewolf ? mAttributes[index] : mWerewolfAttributes[index];
const AttributeValue& currentValue = mAttributes[index];
if (value != currentValue)
{
if(!mIsWerewolf)
mAttributes[index] = value;
else
mWerewolfAttributes[index] = value;
mAttributes[index] = value;
if (index == ESM::Attribute::Intelligence)
mRecalcMagicka = true;

View file

@ -77,10 +77,6 @@ namespace MWMechanics
std::vector<int> mSummonGraveyard;
protected:
// These two are only set by NpcStats, but they are declared in CreatureStats to prevent using virtual methods.
bool mIsWerewolf;
AttributeValue mWerewolfAttributes[8];
int mLevel;
public:

View file

@ -32,6 +32,7 @@ MWMechanics::NpcStats::NpcStats()
, mWerewolfKills (0)
, mLevelProgress(0)
, mTimeToStartDrowning(20.0)
, mIsWerewolf(false)
{
mSkillIncreases.resize (ESM::Attribute::Length, 0);
}
@ -51,7 +52,7 @@ const MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index) const
if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range");
return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]);
return mSkill[index];
}
MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index)
@ -59,7 +60,15 @@ MWMechanics::SkillValue& MWMechanics::NpcStats::getSkill (int index)
if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range");
return (!mIsWerewolf ? mSkill[index] : mWerewolfSkill[index]);
return mSkill[index];
}
void MWMechanics::NpcStats::setSkill(int index, const MWMechanics::SkillValue &value)
{
if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range");
mSkill[index] = value;
}
const std::map<std::string, int>& MWMechanics::NpcStats::getFactionRanks() const
@ -188,10 +197,6 @@ float MWMechanics::NpcStats::getSkillProgressRequirement (int skillIndex, const
void MWMechanics::NpcStats::useSkill (int skillIndex, const ESM::Class& class_, int usageType, float extraFactor)
{
// Don't increase skills as a werewolf
if(mIsWerewolf)
return;
const ESM::Skill *skill =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
float skillGain = 1;
@ -403,34 +408,12 @@ bool MWMechanics::NpcStats::isWerewolf() const
void MWMechanics::NpcStats::setWerewolf (bool set)
{
if (mIsWerewolf == set)
return;
if(set != false)
{
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
mWerewolfKills = 0;
for(size_t i = 0;i < ESM::Attribute::Length;i++)
{
mWerewolfAttributes[i] = getAttribute(i);
// Oh, Bethesda. It's "Intelligence".
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
ESM::Attribute::sAttributeNames[i]);
mWerewolfAttributes[i].setBase(int(gmst.find(name)->getFloat()));
}
for(size_t i = 0;i < ESM::Skill::Length;i++)
{
mWerewolfSkill[i] = getSkill(i);
// Acrobatics is set separately for some reason.
if(i == ESM::Skill::Acrobatics)
continue;
// "Mercantile"! >_<
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
ESM::Skill::sSkillNames[i]);
mWerewolfSkill[i].setBase(int(gmst.find(name)->getFloat()));
}
}
mIsWerewolf = set;
}
@ -464,14 +447,8 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const
state.mDisposition = mDisposition;
for (int i=0; i<ESM::Skill::Length; ++i)
{
mSkill[i].writeState (state.mSkills[i].mRegular);
mWerewolfSkill[i].writeState (state.mSkills[i].mWerewolf);
}
for (int i=0; i<ESM::Attribute::Length; ++i)
{
mWerewolfAttributes[i].writeState (state.mWerewolfAttributes[i]);
}
mSkill[i].writeState (state.mSkills[i]);
state.mIsWerewolf = mIsWerewolf;
state.mCrimeId = mCrimeId;
@ -519,14 +496,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
mDisposition = state.mDisposition;
for (int i=0; i<ESM::Skill::Length; ++i)
{
mSkill[i].readState (state.mSkills[i].mRegular);
mWerewolfSkill[i].readState (state.mSkills[i].mWerewolf);
}
for (int i=0; i<ESM::Attribute::Length; ++i)
{
mWerewolfAttributes[i].readState (state.mWerewolfAttributes[i]);
}
mSkill[i].readState (state.mSkills[i]);
mIsWerewolf = state.mIsWerewolf;

View file

@ -22,7 +22,7 @@ namespace MWMechanics
{
int mDisposition;
SkillValue mSkill[ESM::Skill::Length]; // SkillValue.mProgress used by the player only
SkillValue mWerewolfSkill[ESM::Skill::Length];
int mReputation;
int mCrimeId;
@ -41,6 +41,8 @@ namespace MWMechanics
/// Countdown to getting damage while underwater
float mTimeToStartDrowning;
bool mIsWerewolf;
public:
NpcStats();
@ -56,6 +58,7 @@ namespace MWMechanics
const SkillValue& getSkill (int index) const;
SkillValue& getSkill (int index);
void setSkill(int index, const SkillValue& value);
const std::map<std::string, int>& getFactionRanks() const;
/// Increase the rank in this faction by 1, if such a rank exists.

View file

@ -49,6 +49,55 @@ namespace MWWorld
mPlayer.mData.setPosition(playerPos);
}
void Player::saveSkillsAttributes()
{
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i] = stats.getSkill(i);
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i] = stats.getAttribute(i);
}
void Player::restoreSkillsAttributes()
{
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
for (int i=0; i<ESM::Skill::Length; ++i)
stats.setSkill(i, mSaveSkills[i]);
for (int i=0; i<ESM::Attribute::Length; ++i)
stats.setAttribute(i, mSaveAttributes[i]);
}
void Player::setWerewolfSkillsAttributes()
{
const MWWorld::Store<ESM::GameSetting>& gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
MWMechanics::NpcStats& stats = getPlayer().getClass().getNpcStats(getPlayer());
for(size_t i = 0;i < ESM::Attribute::Length;++i)
{
// Oh, Bethesda. It's "Intelligence".
std::string name = "fWerewolf"+((i==ESM::Attribute::Intelligence) ? std::string("Intellegence") :
ESM::Attribute::sAttributeNames[i]);
MWMechanics::AttributeValue value = stats.getAttribute(i);
value.setBase(int(gmst.find(name)->getFloat()));
stats.setAttribute(i, value);
}
for(size_t i = 0;i < ESM::Skill::Length;i++)
{
// Acrobatics is set separately for some reason.
if(i == ESM::Skill::Acrobatics)
continue;
// "Mercantile"! >_<
std::string name = "fWerewolf"+((i==ESM::Skill::Mercantile) ? std::string("Merchantile") :
ESM::Skill::sSkillNames[i]);
MWMechanics::SkillValue value = stats.getSkill(i);
value.setBase(int(gmst.find(name)->getFloat()));
stats.setSkill(i, value);
}
}
void Player::set(const ESM::NPC *player)
{
mPlayer.mBase = player;
@ -222,6 +271,11 @@ namespace MWWorld
player.mAutoMove = mAutoMove ? 1 : 0;
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].writeState(player.mSaveAttributes[i]);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].writeState(player.mSaveSkills[i]);
writer.startRecord (ESM::REC_PLAY);
player.save (writer);
writer.endRecord (ESM::REC_PLAY);
@ -242,6 +296,17 @@ namespace MWWorld
mPlayer.load (player.mObject);
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].readState(player.mSaveAttributes[i]);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].readState(player.mSaveSkills[i]);
if (player.mObject.mNpcStats.mWerewolfDeprecatedData && player.mObject.mNpcStats.mIsWerewolf)
{
saveSkillsAttributes();
setWerewolfSkillsAttributes();
}
getPlayer().getClass().getCreatureStats(getPlayer()).getAiSequence().clear();
MWBase::World& world = *MWBase::Environment::get().getWorld();

View file

@ -6,6 +6,11 @@
#include "../mwmechanics/drawstate.hpp"
#include "../mwmechanics/stat.hpp"
#include <components/esm/loadskil.hpp>
#include <components/esm/attr.hpp>
#include <OgreVector3.h>
namespace ESM
@ -50,10 +55,18 @@ namespace MWWorld
int mCurrentCrimeId; // the id assigned witnesses
int mPaidCrimeId; // the last id paid off (0 bounty)
// Saved skills and attributes prior to becoming a werewolf
MWMechanics::SkillValue mSaveSkills[ESM::Skill::Length];
MWMechanics::AttributeValue mSaveAttributes[ESM::Attribute::Length];
public:
Player(const ESM::NPC *player, const MWBase::World& world);
void saveSkillsAttributes();
void restoreSkillsAttributes();
void setWerewolfSkillsAttributes();
// For mark/recall magic effects
void markPosition (CellStore* markedCell, ESM::Position markedPosition);
void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const;

View file

@ -2485,6 +2485,17 @@ namespace MWWorld
if (npcStats.isWerewolf() == werewolf)
return;
if (actor == getPlayerPtr())
{
if (werewolf)
{
mPlayer->saveSkillsAttributes();
mPlayer->setWerewolfSkillsAttributes();
}
else
mPlayer->restoreSkillsAttributes();
}
npcStats.setWerewolf(werewolf);
// This is a bit dangerous. Equipped items other than WerewolfRobe may reference

View file

@ -174,6 +174,17 @@ bool ESMReader::isNextSub(const char* name)
return !mCtx.subCached;
}
bool ESMReader::peekNextSub(const char *name)
{
if (!mCtx.leftRec)
return false;
getSubName();
mCtx.subCached = true;
return mCtx.subName == name;
}
// Read subrecord name. This gets called a LOT, so I've optimized it
// slightly.
void ESMReader::getSubName()

View file

@ -185,6 +185,8 @@ public:
*/
bool isNextSub(const char* name);
bool peekNextSub(const char* name);
// Read subrecord name. This gets called a LOT, so I've optimized it
// slightly.
void getSubName();

View file

@ -1,4 +1,3 @@
#include "npcstats.hpp"
#include "esmreader.hpp"
@ -31,18 +30,44 @@ void ESM::NpcStats::load (ESMReader &esm)
esm.getHNOT (mDisposition, "DISP");
for (int i=0; i<27; ++i)
mSkills[i].load (esm);
mWerewolfDeprecatedData = false;
if (esm.peekNextSub("STBA"))
{
mSkills[i].mRegular.load (esm);
mSkills[i].mWerewolf.load (esm);
// we have deprecated werewolf skills, stored interleaved
// Load into one big vector, then remove every 2nd value
mWerewolfDeprecatedData = true;
std::vector<ESM::StatState<int> > skills(mSkills, mSkills + sizeof(mSkills)/sizeof(mSkills[0]));
for (int i=0; i<27; ++i)
{
ESM::StatState<int> skill;
skill.load(esm);
skills.push_back(skill);
}
int i=0;
for (std::vector<ESM::StatState<int> >::iterator it = skills.begin(); it != skills.end(); ++i)
{
if (i%2 == 1)
it = skills.erase(it);
else
++it;
}
assert(skills.size() == 27);
std::copy(skills.begin(), skills.end(), mSkills);
}
// No longer used
bool hasWerewolfAttributes = false;
esm.getHNOT (hasWerewolfAttributes, "HWAT");
if (hasWerewolfAttributes)
{
ESM::StatState<int> dummy;
for (int i=0; i<8; ++i)
mWerewolfAttributes[i].load (esm);
dummy.load(esm);
mWerewolfDeprecatedData = true;
}
mIsWerewolf = false;
@ -112,14 +137,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
esm.writeHNT ("DISP", mDisposition);
for (int i=0; i<27; ++i)
{
mSkills[i].mRegular.save (esm);
mSkills[i].mWerewolf.save (esm);
}
esm.writeHNT ("HWAT", true);
for (int i=0; i<8; ++i)
mWerewolfAttributes[i].save (esm);
mSkills[i].save (esm);
if (mIsWerewolf)
esm.writeHNT ("WOLF", mIsWerewolf);
@ -151,6 +169,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
void ESM::NpcStats::blank()
{
mWerewolfDeprecatedData = false;
mIsWerewolf = false;
mDisposition = 0;
mBounty = 0;

View file

@ -16,12 +16,6 @@ namespace ESM
struct NpcStats
{
struct Skill
{
StatState<int> mRegular;
StatState<int> mWerewolf;
};
struct Faction
{
bool mExpelled;
@ -31,12 +25,13 @@ namespace ESM
Faction();
};
StatState<int> mWerewolfAttributes[8];
bool mIsWerewolf;
bool mWerewolfDeprecatedData;
std::map<std::string, Faction> mFactions; // lower case IDs
int mDisposition;
Skill mSkills[27];
StatState<int> mSkills[27];
int mBounty;
int mReputation;
int mWerewolfKills;

View file

@ -31,6 +31,14 @@ void ESM::Player::load (ESMReader &esm)
esm.getHNOT (mCurrentCrimeId, "CURD");
mPaidCrimeId = -1;
esm.getHNOT (mPaidCrimeId, "PAYD");
if (esm.hasMoreSubs())
{
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].load(esm);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].load(esm);
}
}
void ESM::Player::save (ESMWriter &esm) const
@ -54,4 +62,9 @@ void ESM::Player::save (ESMWriter &esm) const
esm.writeHNT ("CURD", mCurrentCrimeId);
esm.writeHNT ("PAYD", mPaidCrimeId);
for (int i=0; i<ESM::Attribute::Length; ++i)
mSaveAttributes[i].save(esm);
for (int i=0; i<ESM::Skill::Length; ++i)
mSaveSkills[i].save(esm);
}

View file

@ -7,6 +7,9 @@
#include "cellid.hpp"
#include "defs.hpp"
#include "loadskil.hpp"
#include "attr.hpp"
namespace ESM
{
class ESMReader;
@ -28,6 +31,9 @@ namespace ESM
int mCurrentCrimeId;
int mPaidCrimeId;
StatState<int> mSaveAttributes[ESM::Attribute::Length];
StatState<int> mSaveSkills[ESM::Skill::Length];
void load (ESMReader &esm);
void save (ESMWriter &esm) const;
};