1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-23 06:41:08 +00:00

Merge branch 'master' of https://github.com/OpenMW/openmw into osg

Conflicts:
	apps/opencs/CMakeLists.txt
	apps/opencs/main.cpp
	apps/openmw/mwworld/player.hpp
This commit is contained in:
scrawl 2015-06-22 20:09:02 +02:00
commit a5670b5133
67 changed files with 1069 additions and 250 deletions

View File

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

View File

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

View File

@ -70,11 +70,12 @@ opencs_units (view/world
opencs_units_noqt (view/world opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator idcompletiondelegate scripthighlighter idvalidator dialoguecreator idcompletiondelegate
colordelegate
) )
opencs_units (view/widget opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2 completerpopup scenetooltoggle2 completerpopup coloreditor colorpickerpopup
) )
opencs_units (view/render opencs_units (view/render

View File

@ -9,6 +9,8 @@
#include <QIcon> #include <QIcon>
#include <QMetaType> #include <QMetaType>
#include "model/doc/messages.hpp"
#include "model/world/universalid.hpp" #include "model/world/universalid.hpp"
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
@ -51,6 +53,7 @@ int main(int argc, char *argv[])
qRegisterMetaType<std::string> ("std::string"); qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId"); qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
Application application (argc, argv); Application application (argc, argv);

View File

@ -2302,8 +2302,8 @@ CSMDoc::Document::Document (const VFS::Manager* vfs, const Files::ConfigurationM
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect ( connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), &mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); this, SLOT (reportMessage (const CSMDoc::Message&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged())); connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
} }
@ -2404,11 +2404,10 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
const std::string& hint, int type)
{ {
/// \todo find a better way to get these messages to the user. /// \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) void CSMDoc::Document::operationDone (int type, bool failed)

View File

@ -160,8 +160,7 @@ namespace CSMDoc
void modificationStateChanged (bool clean); void modificationStateChanged (bool clean);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMDoc::Message& message, int type);
const std::string& hint, int type);
void operationDone (int type, bool failed); void operationDone (int type, bool failed);

View File

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

View File

@ -1,15 +1,25 @@
#include "messages.hpp" #include "messages.hpp"
void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message, CSMDoc::Message::Message() {}
const std::string& hint)
{
Message data;
data.mId = id;
data.mMessage = message;
data.mHint = hint;
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) void CSMDoc::Messages::push_back (const std::pair<CSMWorld::UniversalId, std::string>& data)

View File

@ -4,20 +4,41 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <QMetaType>
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
namespace CSMDoc 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 class Messages
{ {
public: public:
struct Message // \deprecated Use CSMDoc::Message directly instead.
{ typedef CSMDoc::Message Message;
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
typedef std::vector<Message> Collection; typedef std::vector<Message> Collection;
@ -26,11 +47,15 @@ namespace CSMDoc
private: private:
Collection mMessages; Collection mMessages;
Message::Severity mDefault;
public: public:
Messages (Message::Severity default_);
void add (const CSMWorld::UniversalId& id, const std::string& message, 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. /// \deprecated Use add instead.
void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data); void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data);
@ -41,4 +66,6 @@ namespace CSMDoc
}; };
} }
Q_DECLARE_METATYPE (CSMDoc::Message)
#endif #endif

View File

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

View File

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

View File

@ -1,6 +1,8 @@
#include "operationholder.hpp" #include "operationholder.hpp"
#include "../settings/usersettings.hpp"
#include "operation.hpp" #include "operation.hpp"
CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false)
@ -19,8 +21,8 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
this, SIGNAL (progress (int, int, int))); this, SIGNAL (progress (int, int, int)));
connect ( connect (
mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), mOperation, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); this, SIGNAL (reportMessage (const CSMDoc::Message&, int)));
connect ( connect (
mOperation, SIGNAL (done (int, bool)), mOperation, SIGNAL (done (int, bool)),
@ -29,6 +31,9 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort()));
connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); 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 bool CSMDoc::OperationHolder::isRunning() const

View File

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

View File

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

View File

@ -8,6 +8,8 @@
#include "messages.hpp" #include "messages.hpp"
class QString;
namespace CSMDoc namespace CSMDoc
{ {
class Stage class Stage
@ -21,6 +23,9 @@ namespace CSMDoc
virtual void perform (int stage, Messages& messages) = 0; virtual void perform (int stage, Messages& messages) = 0;
///< Messages resulting from this stage will be appended to \a messages. ///< 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

@ -217,6 +217,47 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
jumpToAdded->setDeclaredValues (jumpValues); jumpToAdded->setDeclaredValues (jumpValues);
} }
declareSection ("report-input", "Report Input");
{
QString none ("None");
QString edit ("Edit");
QString remove ("Remove");
QString editAndRemove ("Edit And Remove");
QStringList values;
values << none << edit << remove << editAndRemove;
QString toolTip = "<ul>"
"<li>None</li>"
"<li>Edit: Open a table or dialogue suitable for addressing the listed report</li>"
"<li>Remove: Remove the report from the report table</li>"
"<li>Edit and Remove: Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table</li>"
"</ul>";
Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click");
doubleClick->setDeclaredValues (values);
doubleClick->setDefaultValue (edit);
doubleClick->setToolTip ("Action on double click in report table:<p>" + toolTip);
Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s",
"Shift Double Click");
shiftDoubleClick->setDeclaredValues (values);
shiftDoubleClick->setDefaultValue (remove);
shiftDoubleClick->setToolTip ("Action on shift double click in report table:<p>" + toolTip);
Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c",
"Control Double Click");
ctrlDoubleClick->setDeclaredValues (values);
ctrlDoubleClick->setDefaultValue (editAndRemove);
ctrlDoubleClick->setToolTip ("Action on control double click in report table:<p>" + toolTip);
Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc",
"Shift Control Double Click");
shiftCtrlDoubleClick->setDeclaredValues (values);
shiftCtrlDoubleClick->setDefaultValue (none);
shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:<p>" + toolTip);
}
declareSection ("search", "Search & Replace"); declareSection ("search", "Search & Replace");
{ {
Setting *before = createSetting (Type_SpinBox, "char-before", Setting *before = createSetting (Type_SpinBox, "char-before",
@ -235,7 +276,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
autoDelete->setDefaultValue ("true"); autoDelete->setDefaultValue ("true");
} }
declareSection ("script-editor", "Script Editor"); declareSection ("script-editor", "Scripts");
{ {
Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers"); Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers");
lineNum->setDefaultValue ("true"); lineNum->setDefaultValue ("true");
@ -254,6 +295,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
"\nA name from the list of colors defined in the list of SVG color keyword names." "\nA name from the list of colors defined in the list of SVG color keyword names."
"\nX11 color names may also work."; "\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"); Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int");
formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setDefaultValues (QStringList() << "Dark magenta");
formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip);

View File

@ -6,24 +6,18 @@
#include "../world/columns.hpp" #include "../world/columns.hpp"
CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn)
const std::string& hint) : mColumnField (-1), mColumnSeverity (-1)
: mId (id), mMessage (message), mHint (hint)
{}
CSMTools::ReportModel::ReportModel (bool fieldColumn)
{ {
if (fieldColumn) int index = 3;
{
mColumnField = 3;
mColumnDescription = 4;
}
else
{
mColumnDescription = 3;
mColumnField = -1; if (severityColumn)
} mColumnSeverity = index++;
if (fieldColumn)
mColumnField = index++;
mColumnDescription = index;
} }
int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const 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()); 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(); return QVariant();
} }
@ -112,6 +118,9 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta
if (section==mColumnField) if (section==mColumnField)
return "Field"; return "Field";
if (section==mColumnSeverity)
return "Severity";
return "-"; return "-";
} }
@ -132,19 +141,18 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true; return true;
} }
void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message, void CSMTools::ReportModel::add (const CSMDoc::Message& message)
const std::string& hint)
{ {
beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (Line (id, message, hint)); mRows.push_back (message);
endInsertRows(); endInsertRows();
} }
void CSMTools::ReportModel::flagAsReplaced (int index) void CSMTools::ReportModel::flagAsReplaced (int index)
{ {
Line& line = mRows.at (index); CSMDoc::Message& line = mRows.at (index);
std::string hint = line.mHint; std::string hint = line.mHint;
if (hint.empty() || hint[0]!='R') if (hint.empty() || hint[0]!='R')
@ -176,3 +184,16 @@ void CSMTools::ReportModel::clear()
endRemoveRows(); 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 <QAbstractTableModel>
#include "../doc/messages.hpp"
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
namespace CSMTools namespace CSMTools
@ -14,17 +16,7 @@ namespace CSMTools
{ {
Q_OBJECT Q_OBJECT
struct Line std::vector<CSMDoc::Messages::Message> mRows;
{
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;
// Fixed columns // Fixed columns
enum Columns enum Columns
@ -35,10 +27,11 @@ namespace CSMTools
// Configurable columns // Configurable columns
int mColumnDescription; int mColumnDescription;
int mColumnField; int mColumnField;
int mColumnSeverity;
public: public:
ReportModel (bool fieldColumn = false); ReportModel (bool fieldColumn = false, bool severityColumn = true);
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; 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()); virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void add (const CSMWorld::UniversalId& id, const std::string& message, void add (const CSMDoc::Message& message);
const std::string& hint = "");
void flagAsReplaced (int index); void flagAsReplaced (int index);
@ -60,6 +52,9 @@ namespace CSMTools
std::string getHint (int row) const; std::string getHint (int row) const;
void clear(); void clear();
// Return number of messages with Error or SeriousError severity.
int countErrors() const;
}; };
} }

View File

@ -11,6 +11,17 @@
#include "../world/data.hpp" #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, void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
Type type) Type type)
{ {
@ -18,11 +29,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
if (type==ErrorMessage)
stream << "error ";
else
stream << "warning ";
stream stream
<< "script " << mFile << "script " << mFile
<< ", line " << loc.mLine << ", column " << loc.mColumn << ", 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; 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) void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
{ {
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
mMessages->push_back (std::make_pair (id, std::ostringstream stream;
(type==ErrorMessage ? "error: " : "warning: ") + message)); stream << "script " << mFile << ": " << message;
mMessages->add (id, stream.str(), "", getSeverity (type));
} }
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document) 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 /// \todo add an option to configure warning mode
setWarningsMode (0); setWarningsMode (0);
@ -58,6 +66,7 @@ int CSMTools::ScriptCheckStage::setup()
mContext.clear(); mContext.clear();
mMessages = 0; mMessages = 0;
mId.clear(); mId.clear();
Compiler::ErrorHandler::reset();
return mDocument.getData().getScripts().getSize(); return mDocument.getData().getScripts().getSize();
} }
@ -72,6 +81,13 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
mMessages = &messages; mMessages = &messages;
switch (mWarningMode)
{
case Mode_Ignore: setWarningsMode (0); break;
case Mode_Normal: setWarningsMode (1); break;
case Mode_Strict: setWarningsMode (2); break;
}
try try
{ {
const CSMWorld::Data& data = mDocument.getData(); 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); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
messages.push_back (std::make_pair (id, std::ostringstream stream;
std::string ("Critical compile error: ") + error.what())); stream << "script " << mFile << ": " << error.what();
messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError);
} }
mMessages = 0; mMessages = 0;
} }
void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value)
{
if (name=="script-editor/warnings")
{
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 /// \brief VerifyStage: make sure that scripts compile
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
{ {
enum WarningMode
{
Mode_Ignore,
Mode_Normal,
Mode_Strict
};
const CSMDoc::Document& mDocument; const CSMDoc::Document& mDocument;
Compiler::Extensions mExtensions; Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext; CSMWorld::ScriptContext mContext;
std::string mId; std::string mId;
std::string mFile; std::string mFile;
CSMDoc::Messages *mMessages; CSMDoc::Messages *mMessages;
WarningMode mWarningMode;
CSMDoc::Message::Severity getSeverity (Type type);
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user. ///< Report error to the user.
@ -40,6 +50,8 @@ namespace CSMTools
virtual void perform (int stage, CSMDoc::Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a 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, bool CSMTools::Search::verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model,
const CSMWorld::UniversalId& id, const std::string& messageHint) const 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(), int row = model->getModelIndex (id.getId(),
model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row(); model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row();

View File

@ -21,6 +21,8 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document)
iter!=types.end(); ++iter) iter!=types.end(); ++iter)
appendStage (new SearchStage (&dynamic_cast<CSMWorld::IdTableBase&> ( appendStage (new SearchStage (&dynamic_cast<CSMWorld::IdTableBase&> (
*document.getData().getTableModel (*iter)))); *document.getData().getTableModel (*iter))));
setDefaultSeverity (CSMDoc::Message::Severity_Info);
} }
void CSMTools::SearchOperation::configure (const Search& search) 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); 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 (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mVerifier, connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
std::vector<std::string> mandatoryIds; // I want C++11, damn it! std::vector<std::string> mandatoryIds; // I want C++11, damn it!
mandatoryIds.push_back ("Day"); 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 (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mSearch, connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
} }
CSMTools::Tools::~Tools() CSMTools::Tools::~Tools()
@ -155,7 +158,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier()
CSMWorld::UniversalId CSMTools::Tools::newSearch() 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); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1);
} }
@ -210,12 +213,11 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId&
return mReports.at (id.getIndex()); return mReports.at (id.getIndex());
} }
void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type)
const std::string& hint, int type)
{ {
std::map<int, int>::iterator iter = mActiveReports.find (type); std::map<int, int>::iterator iter = mActiveReports.find (type);
if (iter!=mActiveReports.end()) if (iter!=mActiveReports.end())
mReports[iter->second]->add (id, message, hint); mReports[iter->second]->add (message);
} }

View File

@ -75,8 +75,7 @@ namespace CSMTools
private slots: private slots:
void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, void verifierMessage (const CSMDoc::Message& message, int type);
const std::string& hint, int type);
signals: signals:

View File

@ -694,7 +694,7 @@ namespace CSMWorld
QColor colour = data.value<QColor>(); QColor colour = data.value<QColor>();
record2.mMapColor = colour.rgb() & 0xffffff; record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red();
record.setModified (record2); record.setModified (record2);
} }

View File

@ -933,7 +933,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
{ {
// log an error and continue loading the refs to the last loaded cell // log an error and continue loading the refs to the last loaded cell
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_None); 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; index = mCells.getSize()-1;
} }
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index)); std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index));
@ -994,7 +994,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
else else
{ {
messages.add (UniversalId::Type_None, 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 else
@ -1011,7 +1012,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (!mDialogue) if (!mDialogue)
{ {
messages.add (UniversalId::Type_None, 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(); mReader->skipRecord();
break; break;
@ -1054,7 +1055,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (unhandledRecord) 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(); mReader->skipRecord();
} }

View File

@ -24,6 +24,7 @@ namespace
types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction; types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction;
types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global; types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global;
types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon; 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_Mesh ] = CSMWorld::UniversalId::Type_Mesh;
types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Npc ] = 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_Spell ] = CSMWorld::UniversalId::Type_Spell;
types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable; types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture; 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; types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable;
return types; return types;

View File

@ -21,6 +21,7 @@
#include "../world/recordstatusdelegate.hpp" #include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp" #include "../world/idtypedelegate.hpp"
#include "../world/idcompletiondelegate.hpp" #include "../world/idcompletiondelegate.hpp"
#include "../world/colordelegate.hpp"
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
@ -61,6 +62,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
new CSVWorld::IdTypeDelegateFactory()); new CSVWorld::IdTypeDelegateFactory());
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Colour,
new CSVWorld::ColorDelegateFactory());
std::vector<CSMWorld::ColumnBase::Display> idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes(); std::vector<CSMWorld::ColumnBase::Display> idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes();
for (std::vector<CSMWorld::ColumnBase::Display>::const_iterator current = idCompletionColumns.begin(); for (std::vector<CSMWorld::ColumnBase::Display>::const_iterator current = idCompletionColumns.begin();
current != idCompletionColumns.end(); current != idCompletionColumns.end();

View File

@ -96,21 +96,35 @@ void CSVTools::ReportTable::mouseDoubleClickEvent (QMouseEvent *event)
selectionModel()->select (index, selectionModel()->select (index,
QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows); QItemSelectionModel::Clear | QItemSelectionModel::Select | QItemSelectionModel::Rows);
switch (modifiers) std::map<Qt::KeyboardModifiers, DoubleClickAction>::iterator iter =
mDoubleClickActions.find (modifiers);
if (iter==mDoubleClickActions.end())
{ {
case 0: event->accept();
return;
}
switch (iter->second)
{
case Action_None:
event->accept();
break;
case Action_Edit:
event->accept(); event->accept();
showSelection(); showSelection();
break; break;
case Qt::ShiftModifier: case Action_Remove:
event->accept(); event->accept();
removeSelection(); removeSelection();
break; break;
case Qt::ControlModifier: case Action_EditAndRemove:
event->accept(); event->accept();
showSelection(); showSelection();
@ -155,7 +169,11 @@ CSVTools::ReportTable::ReportTable (CSMDoc::Document& document,
mReplaceAction = new QAction (tr ("Replace"), this); mReplaceAction = new QAction (tr ("Replace"), this);
connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest())); connect (mReplaceAction, SIGNAL (triggered()), this, SIGNAL (replaceRequest()));
addAction (mReplaceAction); addAction (mReplaceAction);
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));
} }
std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() const
@ -176,6 +194,35 @@ std::vector<CSMWorld::UniversalId> CSVTools::ReportTable::getDraggedRecords() co
void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list) void CSVTools::ReportTable::updateUserSetting (const QString& name, const QStringList& list)
{ {
mIdTypeDelegate->updateUserSetting (name, list); mIdTypeDelegate->updateUserSetting (name, list);
QString base ("report-input/double");
if (name.startsWith (base))
{
QString modifierString = name.mid (base.size());
Qt::KeyboardModifiers modifiers = 0;
if (modifierString=="-s")
modifiers = Qt::ShiftModifier;
else if (modifierString=="-c")
modifiers = Qt::ControlModifier;
else if (modifierString=="-sc")
modifiers = Qt::ShiftModifier | Qt::ControlModifier;
DoubleClickAction action = Action_None;
QString value = list.at (0);
if (value=="Edit")
action = Action_Edit;
else if (value=="Remove")
action = Action_Remove;
else if (value=="Edit And Remove")
action = Action_EditAndRemove;
mDoubleClickActions[modifiers] = action;
return;
}
} }
std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const std::vector<int> CSVTools::ReportTable::getReplaceIndices (bool selection) const

View File

@ -1,6 +1,8 @@
#ifndef CSV_TOOLS_REPORTTABLE_H #ifndef CSV_TOOLS_REPORTTABLE_H
#define CSV_TOOLS_REPORTTABLE_H #define CSV_TOOLS_REPORTTABLE_H
#include <map>
#include "../world/dragrecordtable.hpp" #include "../world/dragrecordtable.hpp"
class QAction; class QAction;
@ -21,11 +23,20 @@ namespace CSVTools
{ {
Q_OBJECT Q_OBJECT
enum DoubleClickAction
{
Action_None,
Action_Edit,
Action_Remove,
Action_EditAndRemove
};
CSMTools::ReportModel *mModel; CSMTools::ReportModel *mModel;
CSVWorld::CommandDelegate *mIdTypeDelegate; CSVWorld::CommandDelegate *mIdTypeDelegate;
QAction *mShowAction; QAction *mShowAction;
QAction *mRemoveAction; QAction *mRemoveAction;
QAction *mReplaceAction; QAction *mReplaceAction;
std::map<Qt::KeyboardModifiers, DoubleClickAction> mDoubleClickActions;
private: private:

View File

@ -0,0 +1,113 @@
#include "coloreditor.hpp"
#include <QApplication>
#include <QColor>
#include <QColorDialog>
#include <QDesktopWidget>
#include <QPainter>
#include <QRect>
#include <QShowEvent>
#include "colorpickerpopup.hpp"
CSVWidget::ColorEditor::ColorEditor(const QColor &color, QWidget *parent, bool popupOnStart)
: QPushButton(parent),
mColor(color),
mColorPicker(new ColorPickerPopup(this)),
mPopupOnStart(popupOnStart)
{
setCheckable(true);
connect(this, SIGNAL(clicked()), this, SLOT(showPicker()));
connect(mColorPicker, SIGNAL(hid()), this, SLOT(pickerHid()));
connect(mColorPicker, SIGNAL(colorChanged(const QColor &)), this, SLOT(pickerColorChanged(const QColor &)));
}
void CSVWidget::ColorEditor::paintEvent(QPaintEvent *event)
{
QPushButton::paintEvent(event);
QRect buttonRect = rect();
QRect coloredRect(buttonRect.x() + qRound(buttonRect.width() / 4.0),
buttonRect.y() + qRound(buttonRect.height() / 4.0),
buttonRect.width() / 2,
buttonRect.height() / 2);
QPainter painter(this);
painter.fillRect(coloredRect, mColor);
painter.setPen(Qt::black);
painter.drawRect(coloredRect);
}
void CSVWidget::ColorEditor::showEvent(QShowEvent *event)
{
QPushButton::showEvent(event);
if (isVisible() && mPopupOnStart)
{
setChecked(true);
showPicker();
mPopupOnStart = false;
}
}
QColor CSVWidget::ColorEditor::color() const
{
return mColor;
}
void CSVWidget::ColorEditor::setColor(const QColor &color)
{
mColor = color;
update();
}
void CSVWidget::ColorEditor::showPicker()
{
if (isChecked())
{
mColorPicker->showPicker(calculatePopupPosition(), mColor);
}
else
{
mColorPicker->hide();
}
}
void CSVWidget::ColorEditor::pickerHid()
{
setChecked(false);
emit pickingFinished();
}
void CSVWidget::ColorEditor::pickerColorChanged(const QColor &color)
{
mColor = color;
update();
}
QPoint CSVWidget::ColorEditor::calculatePopupPosition()
{
QRect editorGeometry = geometry();
QRect popupGeometry = mColorPicker->geometry();
QRect screenGeometry = QApplication::desktop()->screenGeometry();
// Center the popup horizontally relative to the editor
int localPopupX = (editorGeometry.width() - popupGeometry.width()) / 2;
// Popup position need to be specified in global coords
QPoint popupPosition = mapToGlobal(QPoint(localPopupX, editorGeometry.height()));
// Make sure that the popup isn't out of the screen
if (popupPosition.x() < screenGeometry.left())
{
popupPosition.setX(screenGeometry.left() + 1);
}
else if (popupPosition.x() + popupGeometry.width() > screenGeometry.right())
{
popupPosition.setX(screenGeometry.right() - popupGeometry.width() - 1);
}
if (popupPosition.y() + popupGeometry.height() > screenGeometry.bottom())
{
// Place the popup above the editor
popupPosition.setY(popupPosition.y() - popupGeometry.height() - editorGeometry.height() - 1);
}
return popupPosition;
}

View File

@ -0,0 +1,44 @@
#ifndef CSV_WIDGET_COLOREDITOR_HPP
#define CSV_WIDGET_COLOREDITOR_HPP
#include <QPushButton>
class QColor;
class QPoint;
class QSize;
namespace CSVWidget
{
class ColorPickerPopup;
class ColorEditor : public QPushButton
{
Q_OBJECT
QColor mColor;
ColorPickerPopup *mColorPicker;
bool mPopupOnStart;
QPoint calculatePopupPosition();
public:
ColorEditor(const QColor &color, QWidget *parent = 0, bool popupOnStart = false);
QColor color() const;
void setColor(const QColor &color);
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void showEvent(QShowEvent *event);
private slots:
void showPicker();
void pickerHid();
void pickerColorChanged(const QColor &color);
signals:
void pickingFinished();
};
}
#endif

View File

@ -0,0 +1,86 @@
#include "colorpickerpopup.hpp"
#include <QColorDialog>
#include <QPushButton>
#include <QEvent>
#include <QKeyEvent>
#include <QMouseEvent>
#include <QLayout>
#include <QStyleOption>
CSVWidget::ColorPickerPopup::ColorPickerPopup(QWidget *parent)
: QFrame(parent)
{
setWindowFlags(Qt::Popup);
setFrameStyle(QFrame::Box | QFrame::Plain);
hide();
mColorPicker = new QColorDialog(this);
mColorPicker->setWindowFlags(Qt::Widget);
mColorPicker->setOptions(QColorDialog::NoButtons | QColorDialog::DontUseNativeDialog);
mColorPicker->installEventFilter(this);
mColorPicker->open();
connect(mColorPicker,
SIGNAL(currentColorChanged(const QColor &)),
this,
SIGNAL(colorChanged(const QColor &)));
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(mColorPicker);
layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
setFixedSize(mColorPicker->size());
}
void CSVWidget::ColorPickerPopup::showPicker(const QPoint &position, const QColor &initialColor)
{
QRect geometry = this->geometry();
geometry.moveTo(position);
setGeometry(geometry);
mColorPicker->setCurrentColor(initialColor);
show();
}
void CSVWidget::ColorPickerPopup::mousePressEvent(QMouseEvent *event)
{
QPushButton *button = qobject_cast<QPushButton *>(parentWidget());
if (button != NULL)
{
QStyleOptionButton option;
option.init(button);
QRect buttonRect = option.rect;
buttonRect.moveTo(button->mapToGlobal(buttonRect.topLeft()));
// If the mouse is pressed above the pop-up parent,
// the pop-up will be hidden and the pressed signal won't be repeated for the parent
if (buttonRect.contains(event->globalPos()) || buttonRect.contains(event->pos()))
{
setAttribute(Qt::WA_NoMouseReplay);
}
}
QFrame::mousePressEvent(event);
}
void CSVWidget::ColorPickerPopup::hideEvent(QHideEvent *event)
{
QFrame::hideEvent(event);
emit hid();
}
bool CSVWidget::ColorPickerPopup::eventFilter(QObject *object, QEvent *event)
{
if (object == mColorPicker && event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
// Prevent QColorDialog from closing when Escape is pressed.
// Instead, hide the popup.
if (keyEvent->key() == Qt::Key_Escape)
{
hide();
return true;
}
}
return QFrame::eventFilter(object, event);
}

View File

@ -0,0 +1,32 @@
#ifndef CSVWIDGET_COLORPICKERPOPUP_HPP
#define CSVWIDGET_COLORPICKERPOPUP_HPP
#include <QFrame>
class QColorDialog;
namespace CSVWidget
{
class ColorPickerPopup : public QFrame
{
Q_OBJECT
QColorDialog *mColorPicker;
public:
explicit ColorPickerPopup(QWidget *parent);
void showPicker(const QPoint &position, const QColor &initialColor);
protected:
virtual void mousePressEvent(QMouseEvent *event);
virtual void hideEvent(QHideEvent *event);
virtual bool eventFilter(QObject *object, QEvent *event);
signals:
void hid();
void colorChanged(const QColor &color);
};
}
#endif

View File

@ -0,0 +1,36 @@
#include "colordelegate.hpp"
#include <QPainter>
#include <QPushButton>
#include "../widget/coloreditor.hpp"
CSVWorld::ColorDelegate::ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent)
: CommandDelegate(dispatcher, document, parent)
{}
void CSVWorld::ColorDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
QRect coloredRect(option.rect.x() + qRound(option.rect.width() / 4.0),
option.rect.y() + qRound(option.rect.height() / 4.0),
option.rect.width() / 2,
option.rect.height() / 2);
painter->save();
painter->fillRect(coloredRect, index.data().value<QColor>());
painter->setPen(Qt::black);
painter->drawRect(coloredRect);
painter->restore();
}
CSVWorld::CommandDelegate *CSVWorld::ColorDelegateFactory::makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document &document,
QObject *parent) const
{
return new ColorDelegate(dispatcher, document, parent);
}

View File

@ -0,0 +1,37 @@
#ifndef CSV_WORLD_COLORDELEGATE_HPP
#define CSV_WORLD_COLORDELEGATE_HPP
#include "util.hpp"
class QRect;
namespace CSVWidget
{
class ColorEditButton;
}
namespace CSVWorld
{
class ColorDelegate : public CommandDelegate
{
public:
ColorDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document& document,
QObject *parent);
virtual void paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const;
};
class ColorDelegateFactory : public CommandDelegateFactory
{
public:
virtual CommandDelegate *makeDelegate(CSMWorld::CommandDispatcher *dispatcher,
CSMDoc::Document &document,
QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
};
}
#endif

View File

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

View File

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

View File

@ -3,6 +3,8 @@
#include <components/esm/loaddial.hpp> #include <components/esm/loaddial.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/columns.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) : GenericCreator (data, undoStack, id, true), mType (type)
{} {}
CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMWorld::Data& data, CSVWorld::Creator *CSVWorld::TopicCreatorFactory::makeCreator (CSMDoc::Document& document,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const 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, CSVWorld::Creator *CSVWorld::JournalCreatorFactory::makeCreator (CSMDoc::Document& document,
QUndoStack& undoStack, const CSMWorld::UniversalId& id) const 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: public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller. ///< The ownership of the returned Creator is transferred to the caller.
}; };
@ -32,8 +31,7 @@ namespace CSVWorld
{ {
public: public:
virtual Creator *makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, virtual Creator *makeCreator (CSMDoc::Document& document, const CSMWorld::UniversalId& id) const;
const CSMWorld::UniversalId& id) const;
///< The ownership of the returned Creator is transferred to the caller. ///< The ownership of the returned Creator is transferred to the caller.
}; };
} }

View File

@ -33,6 +33,8 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../widget/coloreditor.hpp"
#include "recordstatusdelegate.hpp" #include "recordstatusdelegate.hpp"
#include "util.hpp" #include "util.hpp"
#include "tablebottombox.hpp" #include "tablebottombox.hpp"
@ -331,6 +333,10 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
{ {
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
} }
else if (qobject_cast<CSVWidget::ColorEditor *>(editor))
{
connect(editor, SIGNAL(pickingFinished()), proxy, SLOT(editorDataCommited()));
}
else // throw an exception because this is a coding error else // throw an exception because this is a coding error
throw std::logic_error ("Dialogue editor type missing"); throw std::logic_error ("Dialogue editor type missing");
@ -679,8 +685,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
mMainLayout->addWidget(mEditWidget); mMainLayout->addWidget(mEditWidget);
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
mMainLayout->addWidget (mBottom = mMainLayout->addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this));
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this));
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);

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), mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0),
mScopeLabel (0), mCloneMode (false) 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 = new QHBoxLayout;
mLayout->setContentsMargins (0, 0, 0, 0); mLayout->setContentsMargins (0, 0, 0, 0);

View File

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

View File

@ -9,10 +9,13 @@
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp"
std::string CSVWorld::InfoCreator::getId() const std::string CSVWorld::InfoCreator::getId() const
{ {
@ -39,13 +42,19 @@ void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& com
} }
CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager)
: GenericCreator (data, undoStack, id) : GenericCreator (data, undoStack, id)
{ {
QLabel *label = new QLabel ("Topic", this); QLabel *label = new QLabel ("Topic", this);
insertBeforeButtons (label, false); insertBeforeButtons (label, false);
mTopic = new QLineEdit (this); 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->setCompleter(completionManager.getCompleter(displayType).get());
insertBeforeButtons (mTopic, true); insertBeforeButtons (mTopic, true);
setManualEditing (false); setManualEditing (false);
@ -100,3 +109,12 @@ void CSVWorld::InfoCreator::topicChanged()
{ {
update(); 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

@ -8,6 +8,7 @@ class QLineEdit;
namespace CSMWorld namespace CSMWorld
{ {
class InfoCollection; class InfoCollection;
class IdCompletionManager;
} }
namespace CSVWorld namespace CSVWorld
@ -25,7 +26,7 @@ namespace CSVWorld
public: public:
InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id); const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager& completionManager);
virtual void cloneMode (const std::string& originId, virtual void cloneMode (const std::string& originId,
const CSMWorld::UniversalId::Type type); const CSMWorld::UniversalId::Type type);
@ -43,6 +44,14 @@ namespace CSVWorld
void topicChanged(); 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 #endif

View File

@ -4,10 +4,13 @@
#include <QLabel> #include <QLabel>
#include <QLineEdit> #include <QLineEdit>
#include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/idcompletionmanager.hpp"
std::string CSVWorld::ReferenceCreator::getId() const std::string CSVWorld::ReferenceCreator::getId() const
{ {
@ -71,13 +74,14 @@ int CSVWorld::ReferenceCreator::getRefNumCount() const
} }
CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack, CSVWorld::ReferenceCreator::ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager)
: GenericCreator (data, undoStack, id) : GenericCreator (data, undoStack, id)
{ {
QLabel *label = new QLabel ("Cell", this); QLabel *label = new QLabel ("Cell", this);
insertBeforeButtons (label, false); insertBeforeButtons (label, false);
mCell = new QLineEdit (this); mCell = new QLineEdit (this);
mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get());
insertBeforeButtons (mCell, true); insertBeforeButtons (mCell, true);
setManualEditing (false); setManualEditing (false);
@ -142,3 +146,12 @@ void CSVWorld::ReferenceCreator::cloneMode(const std::string& originId,
CSVWorld::GenericCreator::cloneMode(originId, type); CSVWorld::GenericCreator::cloneMode(originId, type);
cellChanged(); //otherwise ok button will remain disabled 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

@ -5,8 +5,14 @@
class QLineEdit; class QLineEdit;
namespace CSMWorld
{
class IdCompletionManager;
}
namespace CSVWorld namespace CSVWorld
{ {
class ReferenceCreator : public GenericCreator class ReferenceCreator : public GenericCreator
{ {
Q_OBJECT Q_OBJECT
@ -28,7 +34,7 @@ namespace CSVWorld
public: public:
ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack, ReferenceCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id); const CSMWorld::UniversalId& id, CSMWorld::IdCompletionManager &completionManager);
virtual void cloneMode(const std::string& originId, virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type); const CSMWorld::UniversalId::Type type);
@ -46,6 +52,14 @@ namespace CSVWorld
void cellChanged(); 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 #endif

View File

@ -33,9 +33,7 @@ CSVWorld::SceneSubView::SceneSubView (const CSMWorld::UniversalId& id, CSMDoc::D
layout->setContentsMargins (QMargins (0, 0, 0, 0)); layout->setContentsMargins (QMargins (0, 0, 0, 0));
layout->addWidget (mBottom = layout->addWidget (mBottom = new TableBottomBox (NullCreatorFactory(), document, id, this), 0);
new TableBottomBox (NullCreatorFactory(), document.getData(), document.getUndoStack(), id,
this), 0);
mLayout->setContentsMargins (QMargins (0, 0, 0, 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> >); new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceableCreator> >);
manager.add (CSMWorld::UniversalId::Type_References, manager.add (CSMWorld::UniversalId::Type_References,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<ReferenceCreator> >); new CSVDoc::SubViewFactoryWithCreator<TableSubView, ReferenceCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_Topics, manager.add (CSMWorld::UniversalId::Type_Topics,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, TopicCreatorFactory>); new CSVDoc::SubViewFactoryWithCreator<TableSubView, TopicCreatorFactory>);
@ -68,10 +68,10 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>); new CSVDoc::SubViewFactoryWithCreator<TableSubView, JournalCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_TopicInfos, manager.add (CSMWorld::UniversalId::Type_TopicInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >); new CSVDoc::SubViewFactoryWithCreator<TableSubView, InfoCreatorFactory>);
manager.add (CSMWorld::UniversalId::Type_JournalInfos, manager.add (CSMWorld::UniversalId::Type_JournalInfos,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<InfoCreator> >); new CSVDoc::SubViewFactoryWithCreator<TableSubView, InfoCreatorFactory>);
// Subviews for resources tables // Subviews for resources tables
manager.add (CSMWorld::UniversalId::Type_Meshes, manager.add (CSMWorld::UniversalId::Type_Meshes,
@ -147,16 +147,16 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceableCreator> > (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<ReferenceableCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_Reference, 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, manager.add (CSMWorld::UniversalId::Type_Cell,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<CellCreator> > (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<CellCreator> > (false));
manager.add (CSMWorld::UniversalId::Type_JournalInfo, 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, 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, manager.add (CSMWorld::UniversalId::Type_Topic,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, TopicCreatorFactory> (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, TopicCreatorFactory> (false));

View File

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

View File

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

View File

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

View File

@ -17,6 +17,7 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "../../model/world/commanddispatcher.hpp" #include "../../model/world/commanddispatcher.hpp"
#include "../widget/coloreditor.hpp"
#include "dialoguespinbox.hpp" #include "dialoguespinbox.hpp"
#include "scriptedit.hpp" #include "scriptedit.hpp"
@ -123,10 +124,19 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM
if (!mCommandDispatcher) if (!mCommandDispatcher)
return; return;
NastyTableModelHack hack (*model); QVariant new_;
QStyledItemDelegate::setModelData (editor, &hack, index); // Color columns use a custom editor, so we need explicitly extract a data from it
CSVWidget::ColorEditor *colorEditor = qobject_cast<CSVWidget::ColorEditor *>(editor);
QVariant new_ = hack.getData(); if (colorEditor != NULL)
{
new_ = colorEditor->color();
}
else
{
NastyTableModelHack hack (*model);
QStyledItemDelegate::setModelData (editor, &hack, index);
new_ = hack.getData();
}
if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable)) if ((model->data (index)!=new_) && (model->flags(index) & Qt::ItemIsEditable))
mCommandDispatcher->executeModify (model, index, new_); mCommandDispatcher->executeModify (model, index, new_);
@ -162,6 +172,12 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
{ {
return QStyledItemDelegate::createEditor(parent, option, index); return QStyledItemDelegate::createEditor(parent, option, index);
} }
// For tables the pop-up of the color editor should appear immediately after the editor creation
// (the third parameter of ColorEditor's constructor)
else if (display == CSMWorld::ColumnBase::Display_Colour)
{
return new CSVWidget::ColorEditor(index.data().value<QColor>(), parent, true);
}
return createEditor (parent, option, index, display); return createEditor (parent, option, index, display);
} }
@ -184,7 +200,7 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
{ {
case CSMWorld::ColumnBase::Display_Colour: case CSMWorld::ColumnBase::Display_Colour:
return new QLineEdit(parent); return new CSVWidget::ColorEditor(index.data().value<QColor>(), parent);
case CSMWorld::ColumnBase::Display_Integer: case CSMWorld::ColumnBase::Display_Integer:
{ {
@ -284,6 +300,14 @@ void CSVWorld::CommandDelegate::setEditorData (QWidget *editor, const QModelInde
} }
} }
// Color columns use a custom editor, so we need explicitly set a data for it
CSVWidget::ColorEditor *colorEditor = qobject_cast<CSVWidget::ColorEditor *>(editor);
if (colorEditor != NULL)
{
colorEditor->setColor(index.data().value<QColor>());
return;
}
QByteArray n = editor->metaObject()->userProperty().name(); QByteArray n = editor->metaObject()->userProperty().name();
if (n == "dateTime") { if (n == "dateTime") {

View File

@ -641,9 +641,6 @@ namespace MWMechanics
if (mAllowedNodes.empty()) if (mAllowedNodes.empty())
return; return;
if (actor.getClass().isPureWaterCreature(actor))
return;
state.moveIn(new AiWanderStorage()); state.moveIn(new AiWanderStorage());
int index = Misc::Rng::rollDice(mAllowedNodes.size()); int index = Misc::Rng::rollDice(mAllowedNodes.size());
@ -690,7 +687,8 @@ namespace MWMechanics
// actor can wander from the spawn position. AiWander assumes that // actor can wander from the spawn position. AiWander assumes that
// pathgrid points are available, and uses them to randomly select wander // pathgrid points are available, and uses them to randomly select wander
// destinations within the allowed set of pathgrid points (nodes). // 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 cellXOffset = 0;
float cellYOffset = 0; float cellYOffset = 0;

View File

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

View File

@ -77,10 +77,6 @@ namespace MWMechanics
std::vector<int> mSummonGraveyard; std::vector<int> mSummonGraveyard;
protected: 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; int mLevel;
public: public:

View File

@ -32,6 +32,7 @@ MWMechanics::NpcStats::NpcStats()
, mWerewolfKills (0) , mWerewolfKills (0)
, mLevelProgress(0) , mLevelProgress(0)
, mTimeToStartDrowning(20.0) , mTimeToStartDrowning(20.0)
, mIsWerewolf(false)
{ {
mSkillIncreases.resize (ESM::Attribute::Length, 0); 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) if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range"); 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) 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) if (index<0 || index>=ESM::Skill::Length)
throw std::runtime_error ("skill index out of range"); 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 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) 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 = const ESM::Skill *skill =
MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex); MWBase::Environment::get().getWorld()->getStore().get<ESM::Skill>().find (skillIndex);
float skillGain = 1; float skillGain = 1;
@ -403,34 +408,12 @@ bool MWMechanics::NpcStats::isWerewolf() const
void MWMechanics::NpcStats::setWerewolf (bool set) void MWMechanics::NpcStats::setWerewolf (bool set)
{ {
if (mIsWerewolf == set)
return;
if(set != false) if(set != false)
{ {
const MWWorld::Store<ESM::GameSetting> &gmst = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>();
mWerewolfKills = 0; 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; mIsWerewolf = set;
} }
@ -464,14 +447,8 @@ void MWMechanics::NpcStats::writeState (ESM::NpcStats& state) const
state.mDisposition = mDisposition; state.mDisposition = mDisposition;
for (int i=0; i<ESM::Skill::Length; ++i) for (int i=0; i<ESM::Skill::Length; ++i)
{ mSkill[i].writeState (state.mSkills[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]);
}
state.mIsWerewolf = mIsWerewolf; state.mIsWerewolf = mIsWerewolf;
state.mCrimeId = mCrimeId; state.mCrimeId = mCrimeId;
@ -519,14 +496,7 @@ void MWMechanics::NpcStats::readState (const ESM::NpcStats& state)
mDisposition = state.mDisposition; mDisposition = state.mDisposition;
for (int i=0; i<ESM::Skill::Length; ++i) for (int i=0; i<ESM::Skill::Length; ++i)
{ mSkill[i].readState (state.mSkills[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]);
}
mIsWerewolf = state.mIsWerewolf; mIsWerewolf = state.mIsWerewolf;

View File

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

View File

@ -48,6 +48,55 @@ namespace MWWorld
mPlayer.mData.setPosition(playerPos); 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) void Player::set(const ESM::NPC *player)
{ {
mPlayer.mBase = player; mPlayer.mBase = player;
@ -221,6 +270,11 @@ namespace MWWorld
player.mAutoMove = mAutoMove ? 1 : 0; 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); writer.startRecord (ESM::REC_PLAY);
player.save (writer); player.save (writer);
writer.endRecord (ESM::REC_PLAY); writer.endRecord (ESM::REC_PLAY);
@ -241,6 +295,17 @@ namespace MWWorld
mPlayer.load (player.mObject); 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(); getPlayer().getClass().getCreatureStats(getPlayer()).getAiSequence().clear();
MWBase::World& world = *MWBase::Environment::get().getWorld(); MWBase::World& world = *MWBase::Environment::get().getWorld();

View File

@ -5,6 +5,10 @@
#include "../mwworld/livecellref.hpp" #include "../mwworld/livecellref.hpp"
#include "../mwmechanics/drawstate.hpp" #include "../mwmechanics/drawstate.hpp"
#include "../mwmechanics/stat.hpp"
#include <components/esm/loadskil.hpp>
#include <components/esm/attr.hpp>
namespace ESM namespace ESM
{ {
@ -48,10 +52,18 @@ namespace MWWorld
int mCurrentCrimeId; // the id assigned witnesses int mCurrentCrimeId; // the id assigned witnesses
int mPaidCrimeId; // the last id paid off (0 bounty) 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: public:
Player(const ESM::NPC *player, const MWBase::World& world); Player(const ESM::NPC *player, const MWBase::World& world);
void saveSkillsAttributes();
void restoreSkillsAttributes();
void setWerewolfSkillsAttributes();
// For mark/recall magic effects // For mark/recall magic effects
void markPosition (CellStore* markedCell, ESM::Position markedPosition); void markPosition (CellStore* markedCell, ESM::Position markedPosition);
void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const; void getMarkedPosition (CellStore*& markedCell, ESM::Position& markedPosition) const;

View File

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

View File

@ -176,6 +176,17 @@ bool ESMReader::isNextSub(const char* name)
return !mCtx.subCached; 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 // Read subrecord name. This gets called a LOT, so I've optimized it
// slightly. // slightly.
void ESMReader::getSubName() void ESMReader::getSubName()

View File

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

View File

@ -1,4 +1,3 @@
#include "npcstats.hpp" #include "npcstats.hpp"
#include "esmreader.hpp" #include "esmreader.hpp"
@ -31,18 +30,43 @@ void ESM::NpcStats::load (ESMReader &esm)
esm.getHNOT (mDisposition, "DISP"); esm.getHNOT (mDisposition, "DISP");
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
mSkills[i].load (esm);
if (esm.peekNextSub("STBA"))
{ {
mSkills[i].mRegular.load (esm); // we have deprecated werewolf skills, stored interleaved
mSkills[i].mWerewolf.load (esm); // 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; bool hasWerewolfAttributes = false;
esm.getHNOT (hasWerewolfAttributes, "HWAT"); esm.getHNOT (hasWerewolfAttributes, "HWAT");
if (hasWerewolfAttributes) if (hasWerewolfAttributes)
{ {
ESM::StatState<int> dummy;
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
mWerewolfAttributes[i].load (esm); dummy.load(esm);
mWerewolfDeprecatedData = true;
} }
mIsWerewolf = false; mIsWerewolf = false;
@ -112,14 +136,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
esm.writeHNT ("DISP", mDisposition); esm.writeHNT ("DISP", mDisposition);
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
{ mSkills[i].save (esm);
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);
if (mIsWerewolf) if (mIsWerewolf)
esm.writeHNT ("WOLF", mIsWerewolf); esm.writeHNT ("WOLF", mIsWerewolf);
@ -151,6 +168,7 @@ void ESM::NpcStats::save (ESMWriter &esm) const
void ESM::NpcStats::blank() void ESM::NpcStats::blank()
{ {
mWerewolfDeprecatedData = false;
mIsWerewolf = false; mIsWerewolf = false;
mDisposition = 0; mDisposition = 0;
mBounty = 0; mBounty = 0;

View File

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

View File

@ -31,6 +31,14 @@ void ESM::Player::load (ESMReader &esm)
esm.getHNOT (mCurrentCrimeId, "CURD"); esm.getHNOT (mCurrentCrimeId, "CURD");
mPaidCrimeId = -1; mPaidCrimeId = -1;
esm.getHNOT (mPaidCrimeId, "PAYD"); 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 void ESM::Player::save (ESMWriter &esm) const
@ -54,4 +62,9 @@ void ESM::Player::save (ESMWriter &esm) const
esm.writeHNT ("CURD", mCurrentCrimeId); esm.writeHNT ("CURD", mCurrentCrimeId);
esm.writeHNT ("PAYD", mPaidCrimeId); 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 "cellid.hpp"
#include "defs.hpp" #include "defs.hpp"
#include "loadskil.hpp"
#include "attr.hpp"
namespace ESM namespace ESM
{ {
class ESMReader; class ESMReader;
@ -28,6 +31,9 @@ namespace ESM
int mCurrentCrimeId; int mCurrentCrimeId;
int mPaidCrimeId; int mPaidCrimeId;
StatState<int> mSaveAttributes[ESM::Attribute::Length];
StatState<int> mSaveSkills[ESM::Skill::Length];
void load (ESMReader &esm); void load (ESMReader &esm);
void save (ESMWriter &esm) const; void save (ESMWriter &esm) const;
}; };