Fixed editor operation multi-threading (Fixes #923)

celladd
Marc Zinnschlag 10 years ago
parent 491f44869e
commit c0dfad23b3

@ -5,7 +5,7 @@ set (OPENCS_SRC main.cpp
opencs_units (. editor)
opencs_units (model/doc
document operation saving documentmanager loader runner
document operation saving documentmanager loader runner operationholder
)
opencs_units_noqt (model/doc

@ -2254,7 +2254,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
mTools (*this), mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding),
mSavingOperation (*this, mProjectPath, encoding),
mSaving (&mSavingOperation),
mRunner (mProjectPath), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>())
{
if (mContentFiles.empty())

@ -20,6 +20,7 @@
#include "saving.hpp"
#include "blacklist.hpp"
#include "runner.hpp"
#include "operationholder.hpp"
class QAbstractItemModel;
@ -59,7 +60,8 @@ namespace CSMDoc
CSMWorld::Data mData;
CSMTools::Tools mTools;
boost::filesystem::path mProjectPath;
Saving mSaving;
Saving mSavingOperation;
OperationHolder mSaving;
boost::filesystem::path mResDir;
Blacklist mBlacklist;
Runner mRunner;

@ -29,9 +29,9 @@ void CSMDoc::Operation::prepareStages()
CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways)
: mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()),
mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered),
mFinalAlways (finalAlways), mError(false)
mFinalAlways (finalAlways), mError(false), mConnected (false)
{
connect (this, SIGNAL (finished()), this, SLOT (operationDone()));
mTimer = new QTimer (this);
}
CSMDoc::Operation::~Operation()
@ -42,15 +42,17 @@ CSMDoc::Operation::~Operation()
void CSMDoc::Operation::run()
{
prepareStages();
QTimer timer;
mTimer->stop();
timer.connect (&timer, SIGNAL (timeout()), this, SLOT (executeStage()));
if (!mConnected)
{
connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage()));
mConnected = true;
}
timer.start (0);
prepareStages();
exec();
mTimer->start (0);
}
void CSMDoc::Operation::appendStage (Stage *stage)
@ -65,7 +67,7 @@ bool CSMDoc::Operation::hasError() const
void CSMDoc::Operation::abort()
{
if (!isRunning())
if (!mTimer->isActive())
return;
mError = true;
@ -116,10 +118,11 @@ void CSMDoc::Operation::executeStage()
emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType);
if (mCurrentStage==mStages.end())
exit();
operationDone();
}
void CSMDoc::Operation::operationDone()
{
mTimer->stop();
emit done (mType, mError);
}

@ -3,7 +3,8 @@
#include <vector>
#include <QThread>
#include <QObject>
#include <QTimer>
namespace CSMWorld
{
@ -14,7 +15,7 @@ namespace CSMDoc
{
class Stage;
class Operation : public QThread
class Operation : public QObject
{
Q_OBJECT
@ -27,6 +28,8 @@ namespace CSMDoc
int mOrdered;
bool mFinalAlways;
bool mError;
bool mConnected;
QTimer *mTimer;
void prepareStages();
@ -38,8 +41,6 @@ namespace CSMDoc
virtual ~Operation();
virtual void run();
void appendStage (Stage *stage);
///< The ownership of \a stage is transferred to *this.
///
@ -60,6 +61,8 @@ namespace CSMDoc
void abort();
void run();
private slots:
void executeStage();

@ -0,0 +1,65 @@
#include "operationholder.hpp"
#include "operation.hpp"
CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false)
{
if (operation)
setOperation (operation);
}
void CSMDoc::OperationHolder::setOperation (Operation *operation)
{
mOperation = operation;
mOperation->moveToThread (&mThread);
connect (
mOperation, SIGNAL (progress (int, int, int)),
this, SIGNAL (progress (int, int, int)));
connect (
mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
connect (
mOperation, SIGNAL (done (int, bool)),
this, SLOT (doneSlot (int, bool)));
connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort()));
connect (&mThread, SIGNAL (started()), mOperation, SLOT (run()));
}
bool CSMDoc::OperationHolder::isRunning() const
{
return mRunning;
}
void CSMDoc::OperationHolder::start()
{
mRunning = true;
mThread.start();
}
void CSMDoc::OperationHolder::abort()
{
mRunning = false;
emit abortSignal();
}
void CSMDoc::OperationHolder::abortAndWait()
{
if (mRunning)
{
mThread.quit();
mThread.wait();
}
}
void CSMDoc::OperationHolder::doneSlot (int type, bool failed)
{
mRunning = false;
mThread.quit();
emit done (type, failed);
}

@ -0,0 +1,56 @@
#ifndef CSM_DOC_OPERATIONHOLDER_H
#define CSM_DOC_OPERATIONHOLDER_H
#include <QObject>
#include <QThread>
namespace CSMWorld
{
class UniversalId;
}
namespace CSMDoc
{
class Operation;
class OperationHolder : public QObject
{
Q_OBJECT
QThread mThread;
Operation *mOperation;
bool mRunning;
public:
OperationHolder (Operation *operation = 0);
void setOperation (Operation *operation);
bool isRunning() const;
void start();
void abort();
// Abort and wait until thread has finished.
void abortAndWait();
private slots:
void doneSlot (int type, bool failed);
signals:
void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void done (int type, bool failed);
void abortSignal();
};
}
#endif

@ -6,7 +6,7 @@
#include <QTemporaryFile>
#include <QTextStream>
#include "operation.hpp"
#include "operationholder.hpp"
CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath)
: mRunning (false), mStartup (0), mProjectPath (projectPath)
@ -145,7 +145,7 @@ void CSMDoc::Runner::readyReadStandardOutput()
}
CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation)
CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, OperationHolder *operation)
: QObject (runner), mRunner (runner)
{
connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool)));

@ -16,6 +16,8 @@ class QTemporaryFile;
namespace CSMDoc
{
class OperationHolder;
class Runner : public QObject
{
Q_OBJECT
@ -74,7 +76,7 @@ namespace CSMDoc
public:
/// *this attaches itself to runner
SaveWatcher (Runner *runner, Operation *operation);
SaveWatcher (Runner *runner, OperationHolder *operation);
private slots:

@ -26,30 +26,30 @@
#include "referencecheck.hpp"
#include "startscriptcheck.hpp"
CSMDoc::Operation *CSMTools::Tools::get (int type)
CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
{
switch (type)
{
case CSMDoc::State_Verifying: return mVerifier;
case CSMDoc::State_Verifying: return &mVerifier;
}
return 0;
}
const CSMDoc::Operation *CSMTools::Tools::get (int type) const
const CSMDoc::OperationHolder *CSMTools::Tools::get (int type) const
{
return const_cast<Tools *> (this)->get (type);
}
CSMDoc::Operation *CSMTools::Tools::getVerifier()
CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
{
if (!mVerifier)
if (!mVerifierOperation)
{
mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
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,
connect (&mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
@ -60,46 +60,48 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
mandatoryIds.push_back ("Month");
mandatoryIds.push_back ("PCRace");
mVerifier->appendStage (new MandatoryIdStage (mData.getGlobals(),
mVerifierOperation->appendStage (new MandatoryIdStage (mData.getGlobals(),
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Globals), mandatoryIds));
mVerifier->appendStage (new SkillCheckStage (mData.getSkills()));
mVerifierOperation->appendStage (new SkillCheckStage (mData.getSkills()));
mVerifier->appendStage (new ClassCheckStage (mData.getClasses()));
mVerifierOperation->appendStage (new ClassCheckStage (mData.getClasses()));
mVerifier->appendStage (new FactionCheckStage (mData.getFactions()));
mVerifierOperation->appendStage (new FactionCheckStage (mData.getFactions()));
mVerifier->appendStage (new RaceCheckStage (mData.getRaces()));
mVerifierOperation->appendStage (new RaceCheckStage (mData.getRaces()));
mVerifier->appendStage (new SoundCheckStage (mData.getSounds()));
mVerifierOperation->appendStage (new SoundCheckStage (mData.getSounds()));
mVerifier->appendStage (new RegionCheckStage (mData.getRegions()));
mVerifierOperation->appendStage (new RegionCheckStage (mData.getRegions()));
mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
mVerifierOperation->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
mVerifierOperation->appendStage (new SpellCheckStage (mData.getSpells()));
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifierOperation->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifier->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions()));
mVerifierOperation->appendStage (new ReferenceCheckStage(mData.getReferences(), mData.getReferenceables(), mData.getCells(), mData.getFactions()));
mVerifier->appendStage (new ScriptCheckStage (mDocument));
mVerifierOperation->appendStage (new ScriptCheckStage (mDocument));
mVerifier->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts()));
mVerifierOperation->appendStage (new StartScriptCheckStage (mData.getStartScripts(), mData.getScripts()));
mVerifier->appendStage(
mVerifierOperation->appendStage(
new BodyPartCheckStage(
mData.getBodyParts(),
mData.getResources(
CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )),
mData.getRaces() ));
mVerifier.setOperation (mVerifierOperation);
}
return mVerifier;
return &mVerifier;
}
CSMTools::Tools::Tools (CSMDoc::Document& document)
: mDocument (document), mData (document.getData()), mVerifier (0), mNextReportNumber (0)
: mDocument (document), mData (document.getData()), mVerifierOperation (0), mNextReportNumber (0)
{
// index 0: load error log
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
@ -108,7 +110,11 @@ CSMTools::Tools::Tools (CSMDoc::Document& document)
CSMTools::Tools::~Tools()
{
delete mVerifier;
if (mVerifierOperation)
{
mVerifier.abortAndWait();
delete mVerifierOperation;
}
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
delete iter->second;
@ -126,7 +132,7 @@ CSMWorld::UniversalId CSMTools::Tools::runVerifier()
void CSMTools::Tools::abortOperation (int type)
{
if (CSMDoc::Operation *operation = get (type))
if (CSMDoc::OperationHolder *operation = get (type))
operation->abort();
}
@ -141,7 +147,7 @@ int CSMTools::Tools::getRunningOperations() const
int result = 0;
for (int i=0; sOperations[i]!=-1; ++i)
if (const CSMDoc::Operation *operation = get (sOperations[i]))
if (const CSMDoc::OperationHolder *operation = get (sOperations[i]))
if (operation->isRunning())
result |= sOperations[i];

@ -5,6 +5,8 @@
#include <map>
#include "../doc/operationholder.hpp"
namespace CSMWorld
{
class Data;
@ -27,7 +29,8 @@ namespace CSMTools
CSMDoc::Document& mDocument;
CSMWorld::Data& mData;
CSMDoc::Operation *mVerifier;
CSMDoc::Operation *mVerifierOperation;
CSMDoc::OperationHolder mVerifier;
std::map<int, ReportModel *> mReports;
int mNextReportNumber;
std::map<int, int> mActiveReports; // type, report number
@ -36,12 +39,12 @@ namespace CSMTools
Tools (const Tools&);
Tools& operator= (const Tools&);
CSMDoc::Operation *getVerifier();
CSMDoc::OperationHolder *getVerifier();
CSMDoc::Operation *get (int type);
CSMDoc::OperationHolder *get (int type);
///< Returns a 0-pointer, if operation hasn't been used yet.
const CSMDoc::Operation *get (int type) const;
const CSMDoc::OperationHolder *get (int type) const;
///< Returns a 0-pointer, if operation hasn't been used yet.
public:

Loading…
Cancel
Save