1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-06-22 20:11:33 +00:00

Merge branch 'master' into cc9cii

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

View file

@ -41,9 +41,9 @@ namespace ESSImport
{ {
for (int i=0; i<ESM::Skill::Length; ++i) 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

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

View file

@ -13,6 +13,8 @@
#include <components/ogreinit/ogreinit.hpp> #include <components/ogreinit/ogreinit.hpp>
#include "model/doc/messages.hpp"
#include "model/world/universalid.hpp" #include "model/world/universalid.hpp"
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
@ -52,6 +54,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");
OgreInit::OgreInit ogreInit; OgreInit::OgreInit ogreInit;

View file

@ -2282,9 +2282,6 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (mNew) if (mNew)
{ {
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1) if (mContentFiles.size()==1)
createBase(); createBase();
} }
@ -2304,8 +2301,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); connect (&mSaving, SIGNAL (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()));
} }
@ -2369,9 +2366,9 @@ void CSMDoc::Document::save()
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
CSMWorld::UniversalId CSMDoc::Document::verify() CSMWorld::UniversalId CSMDoc::Document::verify (const CSMWorld::UniversalId& reportId)
{ {
CSMWorld::UniversalId id = mTools.runVerifier(); CSMWorld::UniversalId id = mTools.runVerifier (reportId);
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
return id; return id;
} }
@ -2401,11 +2398,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

@ -120,7 +120,7 @@ namespace CSMDoc
void save(); void save();
CSMWorld::UniversalId verify(); CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
CSMWorld::UniversalId newSearch(); CSMWorld::UniversalId newSearch();
@ -158,8 +158,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

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

View file

@ -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

@ -303,7 +303,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");
@ -322,6 +322,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

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

View file

@ -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" && !value.isEmpty())
{
if (value.at (0)=="Ignore")
mWarningMode = Mode_Ignore;
else if (value.at (0)=="Normal")
mWarningMode = Mode_Normal;
else if (value.at (0)=="Strict")
mWarningMode = Mode_Strict;
}
}

View file

@ -18,13 +18,23 @@ namespace CSMTools
/// \brief VerifyStage: make sure that scripts compile /// \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()
@ -143,19 +146,24 @@ CSMTools::Tools::~Tools()
delete iter->second; delete iter->second;
} }
CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& reportId)
{ {
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); int reportNumber = reportId.getType()==CSMWorld::UniversalId::Type_VerificationResults ?
mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; reportId.getIndex() : mNextReportNumber++;
if (mReports.find (reportNumber)==mReports.end())
mReports.insert (std::make_pair (reportNumber, new ReportModel));
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
getVerifier()->start(); getVerifier()->start();
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, reportNumber);
} }
CSMWorld::UniversalId CSMTools::Tools::newSearch() CSMWorld::UniversalId CSMTools::Tools::newSearch()
{ {
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 +218,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

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

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

View file

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

View file

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

View file

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

View file

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

View file

@ -475,6 +475,14 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> ( mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
ScriptColumn<ESM::DebugProfile>::Type_Lines)); ScriptColumn<ESM::DebugProfile>::Type_Lines));
mMetaData.appendBlankRecord ("sys::meta");
mMetaData.addColumn (new StringIdColumn<MetaData> (true));
mMetaData.addColumn (new RecordStateColumn<MetaData>);
mMetaData.addColumn (new FormatColumn<MetaData>);
mMetaData.addColumn (new AuthorColumn<MetaData>);
mMetaData.addColumn (new FileDescriptionColumn<MetaData>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
@ -515,6 +523,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
UniversalId::Type_Texture); UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)), addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video); UniversalId::Type_Video);
addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData);
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
} }
@ -803,6 +812,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id)
return mResourcesManager.get (id.getType()); return mResourcesManager.get (id.getType());
} }
const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const
{
return mMetaData.getRecord (0).get();
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
{ {
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType()); std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -847,9 +861,15 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
mBase = base; mBase = base;
mProject = project; mProject = project;
mAuthor = mReader->getAuthor(); if (!mProject && !mBase)
mDescription = mReader->getDesc(); {
MetaData metaData;
metaData.mId = "sys::meta";
metaData.load (*mReader);
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
}
return mReader->getRecordCount(); return mReader->getRecordCount();
} }
@ -923,7 +943,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));
@ -984,7 +1004,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
@ -1001,7 +1022,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;
@ -1044,7 +1065,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();
} }
@ -1101,26 +1123,6 @@ int CSMWorld::Data::count (RecordBase::State state) const
count (state, mPathgrids); count (state, mPathgrids);
} }
void CSMWorld::Data::setDescription (const std::string& description)
{
mDescription = description;
}
std::string CSMWorld::Data::getDescription() const
{
return mDescription;
}
void CSMWorld::Data::setAuthor (const std::string& author)
{
mAuthor = author;
}
std::string CSMWorld::Data::getAuthor() const
{
return mAuthor;
}
std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
{ {
std::vector<std::string> ids; std::vector<std::string> ids;

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,8 +15,8 @@ void CSVWorld::Creator::setScope (unsigned int scope)
CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {} CSVWorld::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

@ -34,6 +34,7 @@
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../widget/coloreditor.hpp" #include "../widget/coloreditor.hpp"
#include "../widget/droplineedit.hpp"
#include "recordstatusdelegate.hpp" #include "recordstatusdelegate.hpp"
#include "util.hpp" #include "util.hpp"
@ -63,16 +64,24 @@ void CSVWorld::NotEditableSubDelegate::setEditorData (QWidget* editor, const QMo
} }
} }
CSMWorld::Columns::ColumnId columnId = static_cast<CSMWorld::Columns::ColumnId> (
mTable->getColumnId (index.column()));
if (QVariant::String == v.type()) if (QVariant::String == v.type())
{ {
label->setText(v.toString()); label->setText(v.toString());
} }
else //else we are facing enums else if (CSMWorld::Columns::hasEnums (columnId))
{ {
int data = v.toInt(); int data = v.toInt();
std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (static_cast<CSMWorld::Columns::ColumnId> (mTable->getColumnId (index.column())))); std::vector<std::string> enumNames (CSMWorld::Columns::getEnums (columnId));
label->setText(QString::fromUtf8(enumNames.at(data).c_str())); label->setText(QString::fromUtf8(enumNames.at(data).c_str()));
} }
else
{
label->setText (v.toString());
}
} }
void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const void CSVWorld::NotEditableSubDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
@ -129,52 +138,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcherProxy::getEditor() const
return mEditor; return mEditor;
} }
void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>& data, const CSMDoc::Document* document)
{
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(mEditor);
{
if (!lineEdit || !mIndexWrapper.get())
{
return;
}
}
for (unsigned i = 0; i < data.size(); ++i)
{
CSMWorld::UniversalId::Type type = data[i].getType();
if (mDisplay == CSMWorld::ColumnBase::Display_Referenceable)
{
if (type == CSMWorld::UniversalId::Type_Activator
|| type == CSMWorld::UniversalId::Type_Potion
|| type == CSMWorld::UniversalId::Type_Apparatus
|| type == CSMWorld::UniversalId::Type_Armor
|| type == CSMWorld::UniversalId::Type_Book
|| type == CSMWorld::UniversalId::Type_Clothing
|| type == CSMWorld::UniversalId::Type_Container
|| type == CSMWorld::UniversalId::Type_Creature
|| type == CSMWorld::UniversalId::Type_Door
|| type == CSMWorld::UniversalId::Type_Ingredient
|| type == CSMWorld::UniversalId::Type_CreatureLevelledList
|| type == CSMWorld::UniversalId::Type_ItemLevelledList
|| type == CSMWorld::UniversalId::Type_Light
|| type == CSMWorld::UniversalId::Type_Lockpick
|| type == CSMWorld::UniversalId::Type_Miscellaneous
|| type == CSMWorld::UniversalId::Type_Npc
|| type == CSMWorld::UniversalId::Type_Probe
|| type == CSMWorld::UniversalId::Type_Repair
|| type == CSMWorld::UniversalId::Type_Static
|| type == CSMWorld::UniversalId::Type_Weapon)
{
type = CSMWorld::UniversalId::Type_Referenceable;
}
}
if (mDisplay == CSMWorld::TableMimeData::convertEnums(type))
{
emit tableMimeDataDropped(mEditor, mIndexWrapper->mIndex, data[i], document);
emit editorDataCommited(mEditor, mIndexWrapper->mIndex, mDisplay);
break;
}
}
}
/* /*
==============================DialogueDelegateDispatcher========================================== ==============================DialogueDelegateDispatcher==========================================
*/ */
@ -306,16 +269,12 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
// NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry // NOTE: For each entry in CSVWorld::CommandDelegate::createEditor() a corresponding entry
// is required here // is required here
if (qobject_cast<DropLineEdit*>(editor)) if (qobject_cast<CSVWidget::DropLineEdit*>(editor))
{ {
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
connect(editor, SIGNAL(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)), connect(editor, SIGNAL(tableMimeDataDropped(const CSMWorld::UniversalId&, const CSMDoc::Document*)),
proxy, SLOT(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*))); proxy, SLOT(editorDataCommited()));
connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
} }
else if (qobject_cast<QCheckBox*>(editor)) else if (qobject_cast<QCheckBox*>(editor))
{ {
@ -386,9 +345,6 @@ mCommandDispatcher (commandDispatcher),
mDocument (document) mDocument (document)
{ {
remake (row); remake (row);
connect(mDispatcher, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
} }
void CSVWorld::EditWidget::remake(int row) void CSVWorld::EditWidget::remake(int row)
@ -600,12 +556,38 @@ void CSVWorld::EditWidget::remake(int row)
this->setWidgetResizable(true); this->setWidgetResizable(true);
} }
/*
==============================DialogueSubView==========================================
*/
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document, QVBoxLayout& CSVWorld::SimpleDialogueSubView::getMainLayout()
const CreatorFactoryBase& creatorFactory, bool sorting) : {
return *mMainLayout;
}
CSMWorld::IdTable& CSVWorld::SimpleDialogueSubView::getTable()
{
return *mTable;
}
CSMWorld::CommandDispatcher& CSVWorld::SimpleDialogueSubView::getCommandDispatcher()
{
return mCommandDispatcher;
}
std::string CSVWorld::SimpleDialogueSubView::getCurrentId() const
{
return mCurrentId;
}
CSVWorld::EditWidget& CSVWorld::SimpleDialogueSubView::getEditWidget()
{
return *mEditWidget;
}
bool CSVWorld::SimpleDialogueSubView::isLocked() const
{
return mLocked;
}
CSVWorld::SimpleDialogueSubView::SimpleDialogueSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) :
SubView (id), SubView (id),
mEditWidget(0), mEditWidget(0),
mMainLayout(NULL), mMainLayout(NULL),
@ -622,162 +604,19 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
QWidget *mainWidget = new QWidget(this); QWidget *mainWidget = new QWidget(this);
QHBoxLayout *buttonsLayout = new QHBoxLayout;
QToolButton* prevButton = new QToolButton(mainWidget);
prevButton->setIcon(QIcon(":/go-previous.png"));
prevButton->setToolTip ("Switch to previous record");
QToolButton* nextButton = new QToolButton(mainWidget);
nextButton->setIcon(QIcon(":/go-next.png"));
nextButton->setToolTip ("Switch to next record");
buttonsLayout->addWidget(prevButton, 0);
buttonsLayout->addWidget(nextButton, 1);
buttonsLayout->addStretch(2);
QToolButton* cloneButton = new QToolButton(mainWidget);
cloneButton->setIcon(QIcon(":/edit-clone.png"));
cloneButton->setToolTip ("Clone record");
QToolButton* addButton = new QToolButton(mainWidget);
addButton->setIcon(QIcon(":/add.png"));
addButton->setToolTip ("Add new record");
QToolButton* deleteButton = new QToolButton(mainWidget);
deleteButton->setIcon(QIcon(":/edit-delete.png"));
deleteButton->setToolTip ("Delete record");
QToolButton* revertButton = new QToolButton(mainWidget);
revertButton->setIcon(QIcon(":/edit-undo.png"));
revertButton->setToolTip ("Revert record");
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview)
{
QToolButton* previewButton = new QToolButton(mainWidget);
previewButton->setIcon(QIcon(":/edit-preview.png"));
previewButton->setToolTip ("Open a preview of this record");
buttonsLayout->addWidget(previewButton);
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
}
if (mTable->getFeatures() & CSMWorld::IdTable::Feature_View)
{
QToolButton* viewButton = new QToolButton(mainWidget);
viewButton->setIcon(QIcon(":/cell.png"));
viewButton->setToolTip ("Open a scene view of the cell this record is located in");
buttonsLayout->addWidget(viewButton);
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
}
buttonsLayout->addWidget(cloneButton);
buttonsLayout->addWidget(addButton);
buttonsLayout->addWidget(deleteButton);
buttonsLayout->addWidget(revertButton);
connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId()));
connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId()));
connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest()));
connect(revertButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeRevert()));
connect(deleteButton, SIGNAL(clicked()), &mCommandDispatcher, SLOT(executeDelete()));
mMainLayout = new QVBoxLayout(mainWidget); mMainLayout = new QVBoxLayout(mainWidget);
setWidget (mainWidget);
mEditWidget = new EditWidget(mainWidget, mEditWidget = new EditWidget(mainWidget,
mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false); mTable->getModelIndex(mCurrentId, 0).row(), mTable, mCommandDispatcher, document, false);
connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
mMainLayout->addWidget(mEditWidget); mMainLayout->addWidget(mEditWidget);
mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); mEditWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
mMainLayout->addWidget (mBottom =
new TableBottomBox (creatorFactory, document.getData(), document.getUndoStack(), id, this));
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&)));
connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest()));
if(!mBottom->canCreateAndDelete())
{
cloneButton->setDisabled (true);
addButton->setDisabled (true);
deleteButton->setDisabled (true);
}
dataChanged(mTable->getModelIndex (mCurrentId, 0)); dataChanged(mTable->getModelIndex (mCurrentId, 0));
mMainLayout->addLayout (buttonsLayout);
setWidget (mainWidget);
} }
void CSVWorld::DialogueSubView::prevId () void CSVWorld::SimpleDialogueSubView::setEditLock (bool locked)
{
int newRow = mTable->getModelIndex(mCurrentId, 0).row() - 1;
if (newRow < 0)
{
return;
}
while (newRow >= 0)
{
QModelIndex newIndex(mTable->index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased))
{
mEditWidget->remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
mEditWidget->setDisabled(mLocked);
return;
}
--newRow;
}
}
void CSVWorld::DialogueSubView::nextId ()
{
int newRow = mTable->getModelIndex(mCurrentId, 0).row() + 1;
if (newRow >= mTable->rowCount())
{
return;
}
while (newRow < mTable->rowCount())
{
QModelIndex newIndex(mTable->index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State>(mTable->data (mTable->index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted))
{
mEditWidget->remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (mTable->data (mTable->index (newRow, 2)).toInt()),
mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string(mTable->data (mTable->index (newRow, 0)).toString().toUtf8().constData()));
mEditWidget->setDisabled(mLocked);
return;
}
++newRow;
}
}
void CSVWorld::DialogueSubView::setEditLock (bool locked)
{ {
if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid if (!mEditWidget) // hack to indicate that mCurrentId is no longer valid
return; return;
@ -796,7 +635,7 @@ void CSVWorld::DialogueSubView::setEditLock (bool locked)
} }
void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index) void CSVWorld::SimpleDialogueSubView::dataChanged (const QModelIndex & index)
{ {
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0));
@ -829,7 +668,7 @@ void CSVWorld::DialogueSubView::dataChanged (const QModelIndex & index)
} }
} }
void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) void CSVWorld::SimpleDialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{ {
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0)); QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0));
@ -844,56 +683,14 @@ void CSVWorld::DialogueSubView::rowsAboutToBeRemoved(const QModelIndex &parent,
} }
} }
void CSVWorld::DialogueSubView::tableMimeDataDropped (QWidget* editor, void CSVWorld::SimpleDialogueSubView::requestFocus (const std::string& id)
const QModelIndex& index,
const CSMWorld::UniversalId& id,
const CSMDoc::Document* document)
{
if (document == &mDocument)
{
qobject_cast<DropLineEdit*>(editor)->setText(id.getId().c_str());
}
}
void CSVWorld::DialogueSubView::requestFocus (const std::string& id)
{ {
changeCurrentId(id); changeCurrentId(id);
mEditWidget->remake(mTable->getModelIndex (id, 0).row()); mEditWidget->remake(mTable->getModelIndex (id, 0).row());
} }
void CSVWorld::DialogueSubView::cloneRequest () void CSVWorld::SimpleDialogueSubView::changeCurrentId (const std::string& newId)
{
mBottom->cloneRequest(mCurrentId, static_cast<CSMWorld::UniversalId::Type>(mTable->data(mTable->getModelIndex(mCurrentId, 2)).toInt()));
}
void CSVWorld::DialogueSubView::showPreview ()
{
QModelIndex currentIndex(mTable->getModelIndex(mCurrentId, 0));
if (currentIndex.isValid() &&
mTable->getFeatures() & CSMWorld::IdTable::Feature_Preview &&
currentIndex.row() < mTable->rowCount())
{
emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, mCurrentId), "");
}
}
void CSVWorld::DialogueSubView::viewRecord ()
{
QModelIndex currentIndex(mTable->getModelIndex (mCurrentId, 0));
if (currentIndex.isValid() &&
currentIndex.row() < mTable->rowCount())
{
std::pair<CSMWorld::UniversalId, std::string> params = mTable->view (currentIndex.row());
if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
emit focusId (params.first, params.second);
}
}
void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId)
{ {
std::vector<std::string> selection; std::vector<std::string> selection;
mCurrentId = std::string(newId); mCurrentId = std::string(newId);
@ -901,3 +698,186 @@ void CSVWorld::DialogueSubView::changeCurrentId (const std::string& newId)
selection.push_back(mCurrentId); selection.push_back(mCurrentId);
mCommandDispatcher.setSelection(selection); mCommandDispatcher.setSelection(selection);
} }
CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document, const CreatorFactoryBase& creatorFactory, bool sorting)
: SimpleDialogueSubView (id, document)
{
// bottom box
getMainLayout().addWidget (mBottom = new TableBottomBox (creatorFactory, document, id, this));
mBottom->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
connect(mBottom, SIGNAL(requestFocus(const std::string&)), this, SLOT(requestFocus(const std::string&)));
// buttons
QHBoxLayout *buttonsLayout = new QHBoxLayout;
QToolButton* prevButton = new QToolButton (this);
prevButton->setIcon(QIcon(":/go-previous.png"));
prevButton->setToolTip ("Switch to previous record");
QToolButton* nextButton = new QToolButton (this);
nextButton->setIcon(QIcon(":/go-next.png"));
nextButton->setToolTip ("Switch to next record");
buttonsLayout->addWidget(prevButton, 0);
buttonsLayout->addWidget(nextButton, 1);
buttonsLayout->addStretch(2);
QToolButton* cloneButton = new QToolButton (this);
cloneButton->setIcon(QIcon(":/edit-clone.png"));
cloneButton->setToolTip ("Clone record");
QToolButton* addButton = new QToolButton (this);
addButton->setIcon(QIcon(":/add.png"));
addButton->setToolTip ("Add new record");
QToolButton* deleteButton = new QToolButton (this);
deleteButton->setIcon(QIcon(":/edit-delete.png"));
deleteButton->setToolTip ("Delete record");
QToolButton* revertButton = new QToolButton (this);
revertButton->setIcon(QIcon(":/edit-undo.png"));
revertButton->setToolTip ("Revert record");
if (getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview)
{
QToolButton* previewButton = new QToolButton (this);
previewButton->setIcon(QIcon(":/edit-preview.png"));
previewButton->setToolTip ("Open a preview of this record");
buttonsLayout->addWidget(previewButton);
connect(previewButton, SIGNAL(clicked()), this, SLOT(showPreview()));
}
if (getTable().getFeatures() & CSMWorld::IdTable::Feature_View)
{
QToolButton* viewButton = new QToolButton (this);
viewButton->setIcon(QIcon(":/cell.png"));
viewButton->setToolTip ("Open a scene view of the cell this record is located in");
buttonsLayout->addWidget(viewButton);
connect(viewButton, SIGNAL(clicked()), this, SLOT(viewRecord()));
}
buttonsLayout->addWidget(cloneButton);
buttonsLayout->addWidget(addButton);
buttonsLayout->addWidget(deleteButton);
buttonsLayout->addWidget(revertButton);
connect(nextButton, SIGNAL(clicked()), this, SLOT(nextId()));
connect(prevButton, SIGNAL(clicked()), this, SLOT(prevId()));
connect(cloneButton, SIGNAL(clicked()), this, SLOT(cloneRequest()));
connect(revertButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeRevert()));
connect(deleteButton, SIGNAL(clicked()), &getCommandDispatcher(), SLOT(executeDelete()));
connect(addButton, SIGNAL(clicked()), mBottom, SLOT(createRequest()));
if(!mBottom->canCreateAndDelete())
{
cloneButton->setDisabled (true);
addButton->setDisabled (true);
deleteButton->setDisabled (true);
}
getMainLayout().addLayout (buttonsLayout);
}
void CSVWorld::DialogueSubView::cloneRequest()
{
mBottom->cloneRequest (getCurrentId(),
static_cast<CSMWorld::UniversalId::Type> (getTable().
data (getTable().getModelIndex(getCurrentId(), 2)).toInt()));
}
void CSVWorld::DialogueSubView::prevId()
{
int newRow = getTable().getModelIndex (getCurrentId(), 0).row() - 1;
if (newRow < 0)
{
return;
}
while (newRow >= 0)
{
QModelIndex newIndex (getTable().index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> (getTable().data (getTable().index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted || state == CSMWorld::RecordBase::State_Erased))
{
getEditWidget().remake (newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (getTable().data (getTable().index (newRow, 2)).toInt()),
getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
getEditWidget().setDisabled (isLocked());
return;
}
--newRow;
}
}
void CSVWorld::DialogueSubView::nextId ()
{
int newRow = getTable().getModelIndex (getCurrentId(), 0).row() + 1;
if (newRow >= getTable().rowCount())
{
return;
}
while (newRow < getTable().rowCount())
{
QModelIndex newIndex (getTable().index(newRow, 0));
if (!newIndex.isValid())
{
return;
}
CSMWorld::RecordBase::State state = static_cast<CSMWorld::RecordBase::State> (getTable().data (getTable().index (newRow, 1)).toInt());
if (!(state == CSMWorld::RecordBase::State_Deleted))
{
getEditWidget().remake(newRow);
setUniversalId(CSMWorld::UniversalId (static_cast<CSMWorld::UniversalId::Type> (getTable().data (getTable().index (newRow, 2)).toInt()),
getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
changeCurrentId(std::string (getTable().data (getTable().index (newRow, 0)).toString().toUtf8().constData()));
getEditWidget().setDisabled (isLocked());
return;
}
++newRow;
}
}
void CSVWorld::DialogueSubView::showPreview ()
{
QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0));
if (currentIndex.isValid() &&
getTable().getFeatures() & CSMWorld::IdTable::Feature_Preview &&
currentIndex.row() < getTable().rowCount())
{
emit focusId(CSMWorld::UniversalId(CSMWorld::UniversalId::Type_Preview, getCurrentId()), "");
}
}
void CSVWorld::DialogueSubView::viewRecord ()
{
QModelIndex currentIndex (getTable().getModelIndex (getCurrentId(), 0));
if (currentIndex.isValid() &&
currentIndex.row() < getTable().rowCount())
{
std::pair<CSMWorld::UniversalId, std::string> params = getTable().view (currentIndex.row());
if (params.first.getType()!=CSMWorld::UniversalId::Type_None)
emit focusId (params.first, params.second);
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -133,6 +133,15 @@ CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undo
mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0), 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

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

View file

@ -4,15 +4,19 @@
#include <algorithm> #include <algorithm>
#include <QLabel> #include <QLabel>
#include <QLineEdit>
#include <QUuid> #include <QUuid>
#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"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::InfoCreator::getId() const std::string CSVWorld::InfoCreator::getId() const
{ {
@ -39,13 +43,19 @@ void CSVWorld::InfoCreator::configureCreateCommand (CSMWorld::CreateCommand& com
} }
CSVWorld::InfoCreator::InfoCreator (CSMWorld::Data& data, QUndoStack& undoStack, 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); CSMWorld::ColumnBase::Display displayType = CSMWorld::ColumnBase::Display_Topic;
if (getCollectionId().getType() == CSMWorld::UniversalId::Type_JournalInfos)
{
displayType = CSMWorld::ColumnBase::Display_Journal;
}
mTopic = new CSVWidget::DropLineEdit(displayType, this);
mTopic->setCompleter(completionManager.getCompleter(displayType).get());
insertBeforeButtons (mTopic, true); insertBeforeButtons (mTopic, true);
setManualEditing (false); setManualEditing (false);
@ -100,3 +110,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

@ -3,11 +3,15 @@
#include "genericcreator.hpp" #include "genericcreator.hpp"
class QLineEdit;
namespace CSMWorld namespace CSMWorld
{ {
class InfoCollection; class InfoCollection;
class IdCompletionManager;
}
namespace CSVWidget
{
class DropLineEdit;
} }
namespace CSVWorld namespace CSVWorld
@ -16,7 +20,7 @@ namespace CSVWorld
{ {
Q_OBJECT Q_OBJECT
QLineEdit *mTopic; CSVWidget::DropLineEdit *mTopic;
virtual std::string getId() const; virtual std::string getId() const;
@ -25,7 +29,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 +47,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

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

View file

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

View file

@ -2,12 +2,16 @@
#include "referencecreator.hpp" #include "referencecreator.hpp"
#include <QLabel> #include <QLabel>
#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"
#include "../widget/droplineedit.hpp"
std::string CSVWorld::ReferenceCreator::getId() const std::string CSVWorld::ReferenceCreator::getId() const
{ {
@ -71,13 +75,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 CSVWidget::DropLineEdit(CSMWorld::ColumnBase::Display_Cell, this);
mCell->setCompleter(completionManager.getCompleter(CSMWorld::ColumnBase::Display_Cell).get());
insertBeforeButtons (mCell, true); insertBeforeButtons (mCell, true);
setManualEditing (false); setManualEditing (false);
@ -142,3 +147,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

@ -3,15 +3,24 @@
#include "genericcreator.hpp" #include "genericcreator.hpp"
class QLineEdit; namespace CSMWorld
{
class IdCompletionManager;
}
namespace CSVWidget
{
class DropLineEdit;
}
namespace CSVWorld namespace CSVWorld
{ {
class ReferenceCreator : public GenericCreator class ReferenceCreator : public GenericCreator
{ {
Q_OBJECT Q_OBJECT
QLineEdit *mCell; CSVWidget::DropLineEdit *mCell;
std::string mId; std::string mId;
private: private:
@ -28,7 +37,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 +55,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));
@ -170,6 +170,9 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Filter, manager.add (CSMWorld::UniversalId::Type_Filter,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
manager.add (CSMWorld::UniversalId::Type_MetaData,
new CSVDoc::SubViewFactory<SimpleDialogueSubView >);
//preview //preview
manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>); manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>);
} }

View file

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

View file

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

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

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

View file

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

View file

@ -651,9 +651,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 = OEngine::Misc::Rng::rollDice(mAllowedNodes.size()); int index = OEngine::Misc::Rng::rollDice(mAllowedNodes.size());
@ -700,7 +697,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

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

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

@ -49,6 +49,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;
@ -222,6 +271,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);
@ -242,6 +296,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

@ -6,6 +6,11 @@
#include "../mwmechanics/drawstate.hpp" #include "../mwmechanics/drawstate.hpp"
#include "../mwmechanics/stat.hpp"
#include <components/esm/loadskil.hpp>
#include <components/esm/attr.hpp>
#include <OgreVector3.h> #include <OgreVector3.h>
namespace ESM namespace ESM
@ -50,10 +55,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

@ -2485,6 +2485,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

@ -174,6 +174,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

@ -185,6 +185,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,44 @@ 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);
mWerewolfDeprecatedData = false;
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 +137,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 +169,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;
}; };