Merge branch 'run'

Conflicts:
	apps/opencs/model/world/columns.cpp
	apps/opencs/model/world/columns.hpp
	apps/opencs/model/world/data.cpp
	components/CMakeLists.txt
deque
Marc Zinnschlag 10 years ago
commit d1d861e1be

@ -7,7 +7,7 @@ opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG) set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc opencs_units (model/doc
document operation saving documentmanager loader document operation saving documentmanager loader runner
) )
opencs_units_noqt (model/doc opencs_units_noqt (model/doc
@ -26,7 +26,7 @@ opencs_units (model/world
opencs_units_noqt (model/world 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 refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world
@ -46,7 +46,7 @@ opencs_units_noqt (model/tools
opencs_units (view/doc opencs_units (view/doc
viewmanager view operations operation subview startup filedialog newgame viewmanager view operations operation subview startup filedialog newgame
filewidget adjusterwidget loader filewidget adjusterwidget loader globaldebugprofilemenu runlogsubview
) )
@ -71,7 +71,7 @@ opencs_units_noqt (view/world
) )
opencs_units (view/widget opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun
) )
opencs_units (view/render opencs_units (view/render
@ -128,12 +128,8 @@ opencs_units_noqt (model/filter
node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode
) )
opencs_hdrs_noqt (model/filter
filter
)
opencs_units (view/filter opencs_units (view/filter
filtercreator filterbox recordfilterbox editwidget filterbox recordfilterbox editwidget
) )
set (OPENCS_US set (OPENCS_US

@ -80,7 +80,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options"); boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
desc.add_options() desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()) ("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()->composing())
("data-local", boost::program_options::value<std::string>()->default_value("")) ("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false)) ("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252")) ("encoding", boost::program_options::value<std::string>()->default_value("win1252"))

@ -2212,7 +2212,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
mTools (*this), mResDir(resDir), mTools (*this), mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") / mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")), (savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding) mSaving (*this, mProjectPath, encoding),
mRunner (mProjectPath)
{ {
if (mContentFiles.empty()) if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence"); throw std::runtime_error ("Empty content file sequence");
@ -2251,14 +2252,16 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int))); connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mSaving, SIGNAL (done (int)), this, SLOT (operationDone (int))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect ( connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), &mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int))); this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
} }
CSMDoc::Document::~Document() CSMDoc::Document::~Document()
@ -2280,6 +2283,9 @@ int CSMDoc::Document::getState() const
if (mSaving.isRunning()) if (mSaving.isRunning())
state |= State_Locked | State_Saving | State_Operation; state |= State_Locked | State_Saving | State_Operation;
if (mRunner.isRunning())
state |= State_Locked | State_Running;
if (int operations = mTools.getRunningOperations()) if (int operations = mTools.getRunningOperations())
state |= State_Locked | State_Operation | operations; state |= State_Locked | State_Operation | operations;
@ -2344,7 +2350,7 @@ void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std
std::cout << message << std::endl; std::cout << message << std::endl;
} }
void CSMDoc::Document::operationDone (int type) void CSMDoc::Document::operationDone (int type, bool failed)
{ {
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
@ -2370,6 +2376,48 @@ bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id)
return mBlacklist.isBlacklisted (id); return mBlacklist.isBlacklisted (id);
} }
void CSMDoc::Document::startRunning (const std::string& profile,
const std::string& startupInstruction)
{
std::vector<std::string> contentFiles;
for (std::vector<boost::filesystem::path>::const_iterator iter (mContentFiles.begin());
iter!=mContentFiles.end(); ++iter)
contentFiles.push_back (iter->filename().string());
mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles,
startupInstruction);
int state = getState();
if (state & State_Modified)
{
// need to save first
mRunner.start (true);
new SaveWatcher (&mRunner, &mSaving); // no, that is not a memory leak. Qt is weird.
if (!(state & State_Saving))
save();
}
else
mRunner.start();
}
void CSMDoc::Document::stopRunning()
{
mRunner.stop();
}
QTextDocument *CSMDoc::Document::getRunLog()
{
return mRunner.getLog();
}
void CSMDoc::Document::runStateChanged()
{
emit stateChanged (getState(), this);
}
void CSMDoc::Document::progress (int current, int max, int type) void CSMDoc::Document::progress (int current, int max, int type)
{ {

@ -18,6 +18,7 @@
#include "state.hpp" #include "state.hpp"
#include "saving.hpp" #include "saving.hpp"
#include "blacklist.hpp" #include "blacklist.hpp"
#include "runner.hpp"
class QAbstractItemModel; class QAbstractItemModel;
@ -54,6 +55,7 @@ namespace CSMDoc
Saving mSaving; Saving mSaving;
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
Blacklist mBlacklist; Blacklist mBlacklist;
Runner mRunner;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is // It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late. // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
@ -115,6 +117,13 @@ namespace CSMDoc
bool isBlacklisted (const CSMWorld::UniversalId& id) const; bool isBlacklisted (const CSMWorld::UniversalId& id) const;
void startRunning (const std::string& profile,
const std::string& startupInstruction = "");
void stopRunning();
QTextDocument *getRunLog();
signals: signals:
void stateChanged (int state, CSMDoc::Document *document); void stateChanged (int state, CSMDoc::Document *document);
@ -128,7 +137,9 @@ namespace CSMDoc
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type); int type);
void operationDone (int type); void operationDone (int type, bool failed);
void runStateChanged();
public slots: public slots:

@ -119,5 +119,5 @@ void CSMDoc::Operation::executeStage()
void CSMDoc::Operation::operationDone() void CSMDoc::Operation::operationDone()
{ {
emit done (mType); emit done (mType, mError);
} }

@ -54,7 +54,7 @@ namespace CSMDoc
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type); int type);
void done (int type); void done (int type, bool failed);
public slots: public slots:

@ -0,0 +1,157 @@
#include "runner.hpp"
#include <QTemporaryFile>
#include <QTextStream>
#include "operation.hpp"
CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath)
: mRunning (false), mStartup (0), mProjectPath (projectPath)
{
connect (&mProcess, SIGNAL (finished (int, QProcess::ExitStatus)),
this, SLOT (finished (int, QProcess::ExitStatus)));
connect (&mProcess, SIGNAL (readyReadStandardOutput()),
this, SLOT (readyReadStandardOutput()));
mProcess.setProcessChannelMode (QProcess::MergedChannels);
mProfile.blank();
}
CSMDoc::Runner::~Runner()
{
if (mRunning)
{
disconnect (&mProcess, 0, this, 0);
mProcess.kill();
mProcess.waitForFinished();
}
}
void CSMDoc::Runner::start (bool delayed)
{
if (mStartup)
{
delete mStartup;
mStartup = 0;
}
if (!delayed)
{
mLog.clear();
QString path = "openmw";
#ifdef Q_OS_WIN
path.append(QString(".exe"));
#elif defined(Q_OS_MAC)
QDir dir(QCoreApplication::applicationDirPath());
path = dir.absoluteFilePath(name);
#else
path.prepend(QString("./"));
#endif
mStartup = new QTemporaryFile (this);
mStartup->open();
{
QTextStream stream (mStartup);
if (!mStartupInstruction.empty())
stream << QString::fromUtf8 (mStartupInstruction.c_str()) << '\n';
stream << QString::fromUtf8 (mProfile.mScriptText.c_str());
}
mStartup->close();
QStringList arguments;
arguments << "--skip-menu";
if (mProfile.mFlags & ESM::DebugProfile::Flag_BypassNewGame)
arguments << "--new-game=0";
else
arguments << "--new-game=1";
arguments << ("--script-run="+mStartup->fileName());;
arguments <<
QString::fromUtf8 (("--data="+mProjectPath.parent_path().string()).c_str());
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin());
iter!=mContentFiles.end(); ++iter)
{
arguments << QString::fromUtf8 (("--content="+*iter).c_str());
}
arguments
<< QString::fromUtf8 (("--content="+mProjectPath.filename().string()).c_str());
mProcess.start (path, arguments);
}
mRunning = true;
emit runStateChanged();
}
void CSMDoc::Runner::stop()
{
delete mStartup;
mStartup = 0;
if (mProcess.state()==QProcess::NotRunning)
{
mRunning = false;
emit runStateChanged();
}
else
mProcess.kill();
}
bool CSMDoc::Runner::isRunning() const
{
return mRunning;
}
void CSMDoc::Runner::configure (const ESM::DebugProfile& profile,
const std::vector<std::string>& contentFiles, const std::string& startupInstruction)
{
mProfile = profile;
mContentFiles = contentFiles;
mStartupInstruction = startupInstruction;
}
void CSMDoc::Runner::finished (int exitCode, QProcess::ExitStatus exitStatus)
{
mRunning = false;
emit runStateChanged();
}
QTextDocument *CSMDoc::Runner::getLog()
{
return &mLog;
}
void CSMDoc::Runner::readyReadStandardOutput()
{
mLog.setPlainText (
mLog.toPlainText() + QString::fromUtf8 (mProcess.readAllStandardOutput()));
}
CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation)
: QObject (runner), mRunner (runner)
{
connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool)));
}
void CSMDoc::SaveWatcher::saveDone (int type, bool failed)
{
if (failed)
mRunner->stop();
else
mRunner->start();
deleteLater();
}

@ -0,0 +1,85 @@
#ifndef CSM_DOC_RUNNER_H
#define CSM_DOC_RUNNER_H
#include <vector>
#include <string>
#include <boost/filesystem/path.hpp>
#include <QObject>
#include <QProcess>
#include <QTextDocument>
#include <components/esm/debugprofile.hpp>
class QTemporaryFile;
namespace CSMDoc
{
class Runner : public QObject
{
Q_OBJECT
QProcess mProcess;
bool mRunning;
ESM::DebugProfile mProfile;
std::vector<std::string> mContentFiles;
std::string mStartupInstruction;
QTemporaryFile *mStartup;
QTextDocument mLog;
boost::filesystem::path mProjectPath;
public:
Runner (const boost::filesystem::path& projectPath);
~Runner();
/// \param delayed Flag as running but do not start the OpenMW process yet (the
/// process must be started by another call of start with delayed==false)
void start (bool delayed = false);
void stop();
/// \note Running state is entered when the start function is called. This
/// is not necessarily identical to the moment the child process is started.
bool isRunning() const;
void configure (const ESM::DebugProfile& profile,
const std::vector<std::string>& contentFiles,
const std::string& startupInstruction);
QTextDocument *getLog();
signals:
void runStateChanged();
private slots:
void finished (int exitCode, QProcess::ExitStatus exitStatus);
void readyReadStandardOutput();
};
class Operation;
/// \brief Watch for end of save operation and restart or stop runner
class SaveWatcher : public QObject
{
Q_OBJECT
Runner *mRunner;
public:
/// *this attaches itself to runner
SaveWatcher (Runner *runner, Operation *operation);
private slots:
void saveDone (int type, bool failed);
};
}
#endif

@ -17,7 +17,14 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
appendStage (new WriteHeaderStage (mDocument, mState, true)); appendStage (new WriteHeaderStage (mDocument, mState, true));
appendStage (new WriteFilterStage (mDocument, mState, CSMFilter::Filter::Scope_Project)); appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Filter> > (
mDocument.getData().getFilters(), mState, CSMWorld::Scope_Project));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::DebugProfile> > (
mDocument.getData().getDebugProfiles(), mState, CSMWorld::Scope_Project));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Script> > (
mDocument.getData().getScripts(), mState, CSMWorld::Scope_Project));
appendStage (new CloseSaveStage (mState)); appendStage (new CloseSaveStage (mState));

@ -201,23 +201,6 @@ void CSMDoc::WriteRefIdCollectionStage::perform (int stage, Messages& messages)
} }
CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& state,
CSMFilter::Filter::Scope scope)
: WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> > (document.getData().getFilters(),
state),
mDocument (document), mScope (scope)
{}
void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<CSMFilter::Filter>& record =
mDocument.getData().getFilters().getRecord (stage);
if (record.get().mScope==mScope)
WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >::perform (stage, messages);
}
CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document, CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document,
SavingState& state) SavingState& state)
: mDocument (document), mState (state) : mDocument (document), mState (state)

@ -5,8 +5,7 @@
#include "../world/record.hpp" #include "../world/record.hpp"
#include "../world/idcollection.hpp" #include "../world/idcollection.hpp"
#include "../world/scope.hpp"
#include "../filter/filter.hpp"
#include "savingstate.hpp" #include "savingstate.hpp"
@ -67,10 +66,12 @@ namespace CSMDoc
{ {
const CollectionT& mCollection; const CollectionT& mCollection;
SavingState& mState; SavingState& mState;
CSMWorld::Scope mScope;
public: public:
WriteCollectionStage (const CollectionT& collection, SavingState& state); WriteCollectionStage (const CollectionT& collection, SavingState& state,
CSMWorld::Scope scope = CSMWorld::Scope_Content);
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
@ -81,8 +82,8 @@ namespace CSMDoc
template<class CollectionT> template<class CollectionT>
WriteCollectionStage<CollectionT>::WriteCollectionStage (const CollectionT& collection, WriteCollectionStage<CollectionT>::WriteCollectionStage (const CollectionT& collection,
SavingState& state) SavingState& state, CSMWorld::Scope scope)
: mCollection (collection), mState (state) : mCollection (collection), mState (state), mScope (scope)
{} {}
template<class CollectionT> template<class CollectionT>
@ -94,6 +95,9 @@ namespace CSMDoc
template<class CollectionT> template<class CollectionT>
void WriteCollectionStage<CollectionT>::perform (int stage, Messages& messages) void WriteCollectionStage<CollectionT>::perform (int stage, Messages& messages)
{ {
if (CSMWorld::getScopeFromId (mCollection.getRecord (stage).get().mId)!=mScope)
return;
CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState;
if (state==CSMWorld::RecordBase::State_Modified || if (state==CSMWorld::RecordBase::State_Modified ||
@ -152,20 +156,6 @@ namespace CSMDoc
}; };
class WriteFilterStage : public WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >
{
Document& mDocument;
CSMFilter::Filter::Scope mScope;
public:
WriteFilterStage (Document& document, SavingState& state, CSMFilter::Filter::Scope scope);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class CollectionReferencesStage : public Stage class CollectionReferencesStage : public Stage
{ {
Document& mDocument; Document& mDocument;

@ -8,12 +8,13 @@ namespace CSMDoc
State_Modified = 1, State_Modified = 1,
State_Locked = 2, State_Locked = 2,
State_Operation = 4, State_Operation = 4,
State_Running = 8,
State_Saving = 8, State_Saving = 16,
State_Verifying = 16, State_Verifying = 32,
State_Compiling = 32, // not implemented yet State_Compiling = 64, // not implemented yet
State_Searching = 64, // not implemented yet State_Searching = 128, // not implemented yet
State_Loading = 128 // pseudo-state; can not be encountered in a loaded document State_Loading = 256 // pseudo-state; can not be encountered in a loaded document
}; };
} }

@ -1,25 +0,0 @@
#ifndef CSM_FILTER_FILTER_H
#define CSM_FILTER_FILTER_H
#include <vector>
#include <string>
#include <components/esm/filter.hpp>
namespace CSMFilter
{
/// \brief Wrapper for Filter record
struct Filter : public ESM::Filter
{
enum Scope
{
Scope_Project = 0, // per project
Scope_Session = 1, // exists only for one editing session; not saved
Scope_Content = 2 // embedded in the edited content file
};
Scope mScope;
};
}
#endif

@ -596,7 +596,7 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined)
return false; return false;
} }
const CSMWorld::Record<CSMFilter::Filter>& record = mData.getFilters().getRecord (index); const CSMWorld::Record<ESM::Filter>& record = mData.getFilters().getRecord (index);
if (record.isDeleted()) if (record.isDeleted())
{ {

@ -46,7 +46,7 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false); mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
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)), this, SIGNAL (done (int))); connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (mVerifier, connect (mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int))); this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int)));

@ -70,7 +70,7 @@ namespace CSMTools
void progress (int current, int max, int type); void progress (int current, int max, int type);
void done (int type); void done (int type, bool failed);
}; };
} }

@ -100,7 +100,8 @@ namespace CSMWorld
Display_SoundRes, Display_SoundRes,
Display_Texture, Display_Texture,
Display_Video, Display_Video,
Display_Colour Display_Colour,
Display_ScriptLines // console context
}; };
int mColumnId; int mColumnId;

@ -500,6 +500,47 @@ namespace CSMWorld
} }
}; };
template<typename ESXRecordT>
struct FlagColumn2 : public Column<ESXRecordT>
{
int mMask;
bool mInverted;
FlagColumn2 (int columnId, int mask, bool inverted = false)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Boolean), mMask (mask),
mInverted (inverted)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
bool flag = (record.get().mFlags & mMask)!=0;
if (mInverted)
flag = !flag;
return flag;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
int flags = record2.mFlags & ~mMask;
if ((data.toInt()!=0)!=mInverted)
flags |= mMask;
record2.mFlags = flags;
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT> template<typename ESXRecordT>
struct WeightHeightColumn : public Column<ESXRecordT> struct WeightHeightColumn : public Column<ESXRecordT>
{ {
@ -766,8 +807,18 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct ScriptColumn : public Column<ESXRecordT> struct ScriptColumn : public Column<ESXRecordT>
{ {
ScriptColumn() enum Type
: Column<ESXRecordT> (Columns::ColumnId_ScriptText, ColumnBase::Display_Script, 0) {} {
Type_File, // regular script record
Type_Lines, // console context
Type_Info // dialogue context (not implemented yet)
};
ScriptColumn (Type type)
: Column<ESXRecordT> (Columns::ColumnId_ScriptText,
type==Type_File ? ColumnBase::Display_Script : ColumnBase::Display_ScriptLines,
type==Type_File ? 0 : ColumnBase::Flag_Dialogue)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1224,36 +1275,6 @@ namespace CSMWorld
} }
}; };
template<typename ESXRecordT>
struct ScopeColumn : public Column<ESXRecordT>
{
ScopeColumn()
: Column<ESXRecordT> (Columns::ColumnId_Scope, ColumnBase::Display_Integer, 0)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mScope);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mScope = static_cast<CSMFilter::Filter::Scope> (data.toInt());
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT> template<typename ESXRecordT>
struct PosColumn : public Column<ESXRecordT> struct PosColumn : public Column<ESXRecordT>

@ -172,7 +172,6 @@ namespace CSMWorld
{ ColumnId_Rank, "Rank" }, { ColumnId_Rank, "Rank" },
{ ColumnId_Gender, "Gender" }, { ColumnId_Gender, "Gender" },
{ ColumnId_PcRank, "PC Rank" }, { ColumnId_PcRank, "PC Rank" },
{ ColumnId_Scope, "Scope" },
{ ColumnId_ReferenceableId, "Referenceable ID" }, { ColumnId_ReferenceableId, "Referenceable ID" },
{ ColumnId_CombatState, "Combat" }, { ColumnId_CombatState, "Combat" },
{ ColumnId_MagicState, "Magic" }, { ColumnId_MagicState, "Magic" },
@ -182,6 +181,9 @@ namespace CSMWorld
{ ColumnId_BodyPartType, "Bodypart Type" }, { ColumnId_BodyPartType, "Bodypart Type" },
{ ColumnId_MeshType, "Mesh Type" }, { ColumnId_MeshType, "Mesh Type" },
{ ColumnId_OwnerGlobal, "Owner Global" }, { ColumnId_OwnerGlobal, "Owner Global" },
{ ColumnId_DefaultProfile, "Default Profile" },
{ ColumnId_BypassNewGame, "Bypass New Game" },
{ ColumnId_GlobalProfile, "Global Profile" },
{ ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue2, "Use value 2" },

@ -165,7 +165,6 @@ namespace CSMWorld
ColumnId_Rank = 152, ColumnId_Rank = 152,
ColumnId_Gender = 153, ColumnId_Gender = 153,
ColumnId_PcRank = 154, ColumnId_PcRank = 154,
ColumnId_Scope = 155,
ColumnId_ReferenceableId = 156, ColumnId_ReferenceableId = 156,
ColumnId_CombatState = 157, ColumnId_CombatState = 157,
ColumnId_MagicState = 158, ColumnId_MagicState = 158,
@ -175,6 +174,9 @@ namespace CSMWorld
ColumnId_BodyPartType = 162, ColumnId_BodyPartType = 162,
ColumnId_MeshType = 163, ColumnId_MeshType = 163,
ColumnId_OwnerGlobal = 164, ColumnId_OwnerGlobal = 164,
ColumnId_DefaultProfile = 165,
ColumnId_BypassNewGame = 166,
ColumnId_GlobalProfile = 167,
// 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.

@ -131,7 +131,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mScripts.addColumn (new StringIdColumn<ESM::Script>); mScripts.addColumn (new StringIdColumn<ESM::Script>);
mScripts.addColumn (new RecordStateColumn<ESM::Script>); mScripts.addColumn (new RecordStateColumn<ESM::Script>);
mScripts.addColumn (new FixedRecordTypeColumn<ESM::Script> (UniversalId::Type_Script)); mScripts.addColumn (new FixedRecordTypeColumn<ESM::Script> (UniversalId::Type_Script));
mScripts.addColumn (new ScriptColumn<ESM::Script>); mScripts.addColumn (new ScriptColumn<ESM::Script> (ScriptColumn<ESM::Script>::Type_File));
mRegions.addColumn (new StringIdColumn<ESM::Region>); mRegions.addColumn (new StringIdColumn<ESM::Region>);
mRegions.addColumn (new RecordStateColumn<ESM::Region>); mRegions.addColumn (new RecordStateColumn<ESM::Region>);
@ -252,12 +252,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mRefs.addColumn (new TrapColumn<CellRef>); mRefs.addColumn (new TrapColumn<CellRef>);
mRefs.addColumn (new OwnerGlobalColumn<CellRef>); mRefs.addColumn (new OwnerGlobalColumn<CellRef>);
mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>); mFilters.addColumn (new StringIdColumn<ESM::Filter>);
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>); mFilters.addColumn (new RecordStateColumn<ESM::Filter>);
mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter)); mFilters.addColumn (new FixedRecordTypeColumn<ESM::Filter> (UniversalId::Type_Filter));
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>); mFilters.addColumn (new FilterColumn<ESM::Filter>);
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>); mFilters.addColumn (new DescriptionColumn<ESM::Filter>);
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
mDebugProfiles.addColumn (new StringIdColumn<ESM::DebugProfile>);
mDebugProfiles.addColumn (new RecordStateColumn<ESM::DebugProfile>);
mDebugProfiles.addColumn (new FixedRecordTypeColumn<ESM::DebugProfile> (UniversalId::Type_DebugProfile));
mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
Columns::ColumnId_DefaultProfile, ESM::DebugProfile::Flag_Default));
mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
Columns::ColumnId_BypassNewGame, ESM::DebugProfile::Flag_BypassNewGame));
mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
Columns::ColumnId_GlobalProfile, ESM::DebugProfile::Flag_Global));
mDebugProfiles.addColumn (new DescriptionColumn<ESM::DebugProfile>);
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
ScriptColumn<ESM::DebugProfile>::Type_Lines));
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);
@ -281,6 +293,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
UniversalId::Type_Referenceable); UniversalId::Type_Referenceable);
addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference);
addModel (new IdTable (&mFilters), UniversalId::Type_Filter); addModel (new IdTable (&mFilters), UniversalId::Type_Filter);
addModel (new IdTable (&mDebugProfiles), UniversalId::Type_DebugProfile);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Meshes)), addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Meshes)),
UniversalId::Type_Mesh); UniversalId::Type_Mesh);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Icons)), addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Icons)),
@ -484,12 +497,12 @@ CSMWorld::RefCollection& CSMWorld::Data::getReferences()
return mRefs; return mRefs;
} }
const CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() const const CSMWorld::IdCollection<ESM::Filter>& CSMWorld::Data::getFilters() const
{ {
return mFilters; return mFilters;
} }
CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() CSMWorld::IdCollection<ESM::Filter>& CSMWorld::Data::getFilters()
{ {
return mFilters; return mFilters;
} }
@ -514,6 +527,16 @@ CSMWorld::IdCollection<ESM::BodyPart>& CSMWorld::Data::getBodyParts()
return mBodyParts; return mBodyParts;
} }
const CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles() const
{
return mDebugProfiles;
}
CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles()
{
return mDebugProfiles;
}
const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const
{ {
return mResourcesManager.get (id.getType()); return mResourcesManager.get (id.getType());
@ -583,6 +606,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
ESM::NAME n = mReader->getRecName(); ESM::NAME n = mReader->getRecName();
mReader->getRecHeader(); mReader->getRecHeader();
bool unhandledRecord = false;
switch (n.val) switch (n.val)
{ {
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break; case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
@ -693,23 +718,37 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
case ESM::REC_FILT: case ESM::REC_FILT:
if (mProject) if (!mProject)
{
unhandledRecord = true;
break;
}
mFilters.load (*mReader, mBase);
break;
case ESM::REC_DBGP:
if (!mProject)
{ {
mFilters.load (*mReader, mBase); unhandledRecord = true;
mFilters.setData (mFilters.getSize()-1,
mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
static_cast<int> (CSMFilter::Filter::Scope_Project));
break; break;
} }
// fall through (filter record in a content file is an error with format 0) mDebugProfiles.load (*mReader, mBase);
break;
default: default:
messages.push_back (std::make_pair (UniversalId::Type_None, unhandledRecord = true;
"Unsupported record type: " + n.toString())); }
if (unhandledRecord)
{
messages.push_back (std::make_pair (UniversalId::Type_None,
"Unsupported record type: " + n.toString()));
mReader->skipRecord(); mReader->skipRecord();
} }
return false; return false;

@ -23,11 +23,11 @@
#include <components/esm/loaddial.hpp> #include <components/esm/loaddial.hpp>
#include <components/esm/loadench.hpp> #include <components/esm/loadench.hpp>
#include <components/esm/loadbody.hpp> #include <components/esm/loadbody.hpp>
#include <components/esm/debugprofile.hpp>
#include <components/esm/filter.hpp>
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
#include "../filter/filter.hpp"
#include "../doc/stage.hpp" #include "../doc/stage.hpp"
#include "idcollection.hpp" #include "idcollection.hpp"
@ -70,12 +70,13 @@ namespace CSMWorld
IdCollection<ESM::Dialogue> mJournals; IdCollection<ESM::Dialogue> mJournals;
IdCollection<ESM::Enchantment> mEnchantments; IdCollection<ESM::Enchantment> mEnchantments;
IdCollection<ESM::BodyPart> mBodyParts; IdCollection<ESM::BodyPart> mBodyParts;
IdCollection<ESM::DebugProfile> mDebugProfiles;
InfoCollection mTopicInfos; InfoCollection mTopicInfos;
InfoCollection mJournalInfos; InfoCollection mJournalInfos;
IdCollection<Cell> mCells; IdCollection<Cell> mCells;
RefIdCollection mReferenceables; RefIdCollection mReferenceables;
RefCollection mRefs; RefCollection mRefs;
IdCollection<CSMFilter::Filter> mFilters; IdCollection<ESM::Filter> mFilters;
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;
@ -178,9 +179,9 @@ namespace CSMWorld
RefCollection& getReferences(); RefCollection& getReferences();
const IdCollection<CSMFilter::Filter>& getFilters() const; const IdCollection<ESM::Filter>& getFilters() const;
IdCollection<CSMFilter::Filter>& getFilters(); IdCollection<ESM::Filter>& getFilters();
const IdCollection<ESM::Enchantment>& getEnchantments() const; const IdCollection<ESM::Enchantment>& getEnchantments() const;
@ -190,6 +191,10 @@ namespace CSMWorld
IdCollection<ESM::BodyPart>& getBodyParts(); IdCollection<ESM::BodyPart>& getBodyParts();
const IdCollection<ESM::DebugProfile>& getDebugProfiles() const;
IdCollection<ESM::DebugProfile>& getDebugProfiles();
/// 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;

@ -0,0 +1,25 @@
#include "scope.hpp"
#include <stdexcept>
#include <components/misc/stringops.hpp>
CSMWorld::Scope CSMWorld::getScopeFromId (const std::string& id)
{
// get root namespace
std::string namespace_;
std::string::size_type i = id.find ("::");
if (i!=std::string::npos)
namespace_ = Misc::StringUtils::lowerCase (id.substr (0, i));
if (namespace_=="project")
return Scope_Project;
if (namespace_=="session")
return Scope_Session;
return Scope_Content;
}

@ -0,0 +1,23 @@
#ifndef CSM_WOLRD_SCOPE_H
#define CSM_WOLRD_SCOPE_H
#include <string>
namespace CSMWorld
{
enum Scope
{
// record stored in content file
Scope_Content = 1,
// record stored in project file
Scope_Project = 2,
// record that exists only for the duration of one editing session
Scope_Session = 4
};
Scope getScopeFromId (const std::string& id);
}
#endif

@ -50,6 +50,8 @@ namespace
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 }, { CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles", 0 },
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 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
}; };
@ -109,6 +111,7 @@ namespace
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", 0 }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", 0 },
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", 0 }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", 0 },
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", 0 }, { CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 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
}; };

@ -119,10 +119,13 @@ namespace CSMWorld
Type_Textures, Type_Textures,
Type_Texture, Type_Texture,
Type_Videos, Type_Videos,
Type_Video Type_Video,
Type_DebugProfiles,
Type_DebugProfile,
Type_RunLog
}; };
enum { NumberOfTypes = Type_BodyPart+1 }; enum { NumberOfTypes = Type_DebugProfile+1 };
private: private:

@ -0,0 +1,93 @@
#include "globaldebugprofilemenu.hpp"
#include <vector>
#include <algorithm>
#include <QActionGroup>
#include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp"
void CSVDoc::GlobalDebugProfileMenu::rebuild()
{
clear();
delete mActions;
mActions = 0;
int idColumn = mDebugProfiles->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int stateColumn = mDebugProfiles->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
int globalColumn = mDebugProfiles->findColumnIndex (
CSMWorld::Columns::ColumnId_GlobalProfile);
int size = mDebugProfiles->rowCount();
std::vector<QString> ids;
for (int i=0; i<size; ++i)
{
int state = mDebugProfiles->data (mDebugProfiles->index (i, stateColumn)).toInt();
bool global = mDebugProfiles->data (mDebugProfiles->index (i, globalColumn)).toInt();
if (state!=CSMWorld::RecordBase::State_Deleted && global)
ids.push_back (
mDebugProfiles->data (mDebugProfiles->index (i, idColumn)).toString());
}
mActions = new QActionGroup (this);
connect (mActions, SIGNAL (triggered (QAction *)), this, SLOT (actionTriggered (QAction *)));
std::sort (ids.begin(), ids.end());
for (std::vector<QString>::const_iterator iter (ids.begin()); iter!=ids.end(); ++iter)
{
mActions->addAction (addAction (*iter));
}
}
CSVDoc::GlobalDebugProfileMenu::GlobalDebugProfileMenu (CSMWorld::IdTable *debugProfiles,
QWidget *parent)
: QMenu (parent), mDebugProfiles (debugProfiles), mActions (0)
{
rebuild();
connect (mDebugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (profileAboutToBeRemoved (const QModelIndex&, int, int)));
connect (mDebugProfiles, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (profileInserted (const QModelIndex&, int, int)));
connect (mDebugProfiles, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (profileChanged (const QModelIndex&, const QModelIndex&)));
}
void CSVDoc::GlobalDebugProfileMenu::updateActions (bool running)
{
if (mActions)
mActions->setEnabled (!running);
}
void CSVDoc::GlobalDebugProfileMenu::profileAboutToBeRemoved (const QModelIndex& parent,
int start, int end)
{
rebuild();
}
void CSVDoc::GlobalDebugProfileMenu::profileInserted (const QModelIndex& parent, int start,
int end)
{
rebuild();
}
void CSVDoc::GlobalDebugProfileMenu::profileChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
rebuild();
}
void CSVDoc::GlobalDebugProfileMenu::actionTriggered (QAction *action)
{
emit triggered (std::string (action->text().toUtf8().constData()));
}

@ -0,0 +1,49 @@
#ifndef CSV_DOC_GLOBALDEBUGPROFILEMENU_H
#define CSV_DOC_GLOBALDEBUGPROFILEMENU_H
#include <QMenu>
class QModelIndex;
class QActionGroup;
namespace CSMWorld
{
class IdTable;
}
namespace CSVDoc
{
class GlobalDebugProfileMenu : public QMenu
{
Q_OBJECT
CSMWorld::IdTable *mDebugProfiles;
QActionGroup *mActions;
private:
void rebuild();
public:
GlobalDebugProfileMenu (CSMWorld::IdTable *debugProfiles, QWidget *parent = 0);
void updateActions (bool running);
private slots:
void profileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
void profileInserted (const QModelIndex& parent, int start, int end);
void profileChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void actionTriggered (QAction *action);
signals:
void triggered (const std::string& profile);
};
}
#endif

@ -0,0 +1,20 @@
#include "runlogsubview.hpp"
#include <QTextEdit>
CSVDoc::RunLogSubView::RunLogSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document)
: SubView (id)
{
QTextEdit *edit = new QTextEdit (this);
edit->setDocument (document.getRunLog());
edit->setReadOnly (true);
setWidget (edit);
}
void CSVDoc::RunLogSubView::setEditLock (bool locked)
{
// ignored since this SubView does not have editing
}

@ -0,0 +1,20 @@
#ifndef CSV_DOC_RUNLOGSUBVIEW_H
#define CSV_DOC_RUNLOGSUBVIEW_H
#include "subview.hpp"
namespace CSVDoc
{
class RunLogSubView : public SubView
{
Q_OBJECT
public:
RunLogSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
virtual void setEditLock (bool locked);
};
}
#endif

@ -12,6 +12,8 @@
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
#include "../../model/world/idtable.hpp"
#include "../world/subviews.hpp" #include "../world/subviews.hpp"
#include "../tools/subviews.hpp" #include "../tools/subviews.hpp"
@ -19,6 +21,9 @@
#include "viewmanager.hpp" #include "viewmanager.hpp"
#include "operations.hpp" #include "operations.hpp"
#include "subview.hpp" #include "subview.hpp"
#include "globaldebugprofilemenu.hpp"
#include "runlogsubview.hpp"
#include "subviewfactoryimp.hpp"
void CSVDoc::View::closeEvent (QCloseEvent *event) void CSVDoc::View::closeEvent (QCloseEvent *event)
{ {
@ -232,6 +237,35 @@ void CSVDoc::View::setupAssetsMenu()
assets->addAction (videos); assets->addAction (videos);
} }
void CSVDoc::View::setupDebugMenu()
{
QMenu *debug = menuBar()->addMenu (tr ("Debug"));
QAction *profiles = new QAction (tr ("Debug Profiles"), this);
connect (profiles, SIGNAL (triggered()), this, SLOT (addDebugProfilesSubView()));
debug->addAction (profiles);
debug->addSeparator();
mGlobalDebugProfileMenu = new GlobalDebugProfileMenu (
&dynamic_cast<CSMWorld::IdTable&> (*mDocument->getData().getTableModel (
CSMWorld::UniversalId::Type_DebugProfiles)), this);
connect (mGlobalDebugProfileMenu, SIGNAL (triggered (const std::string&)),
this, SLOT (run (const std::string&)));
QAction *runDebug = debug->addMenu (mGlobalDebugProfileMenu);
runDebug->setText (tr ("Run OpenMW"));
mStopDebug = new QAction (tr ("Shutdown OpenMW"), this);
connect (mStopDebug, SIGNAL (triggered()), this, SLOT (stop()));
debug->addAction (mStopDebug);
QAction *runLog = new QAction (tr ("Run Log"), this);
connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView()));
debug->addAction (runLog);
}
void CSVDoc::View::setupUi() void CSVDoc::View::setupUi()
{ {
setupFileMenu(); setupFileMenu();
@ -241,6 +275,7 @@ void CSVDoc::View::setupUi()
setupMechanicsMenu(); setupMechanicsMenu();
setupCharacterMenu(); setupCharacterMenu();
setupAssetsMenu(); setupAssetsMenu();
setupDebugMenu();
} }
void CSVDoc::View::updateTitle() void CSVDoc::View::updateTitle()
@ -261,6 +296,7 @@ void CSVDoc::View::updateTitle()
void CSVDoc::View::updateActions() void CSVDoc::View::updateActions()
{ {
bool editing = !(mDocument->getState() & CSMDoc::State_Locked); bool editing = !(mDocument->getState() & CSMDoc::State_Locked);
bool running = mDocument->getState() & CSMDoc::State_Running;
for (std::vector<QAction *>::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter) for (std::vector<QAction *>::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter)
(*iter)->setEnabled (editing); (*iter)->setEnabled (editing);
@ -268,8 +304,11 @@ void CSVDoc::View::updateActions()
mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo()); mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo());
mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo()); mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo());
mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving)); mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving) && !running);
mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying)); mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying));
mGlobalDebugProfileMenu->updateActions (running);
mStopDebug->setEnabled (running);
} }
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
@ -295,9 +334,13 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
setupUi(); setupUi();
updateActions();
CSVWorld::addSubViewFactories (mSubViewFactory); CSVWorld::addSubViewFactories (mSubViewFactory);
CSVTools::addSubViewFactories (mSubViewFactory); CSVTools::addSubViewFactories (mSubViewFactory);
mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory<RunLogSubView>);
connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int)));
} }
@ -543,6 +586,16 @@ void CSVDoc::View::addVideosSubView()
addSubView (CSMWorld::UniversalId::Type_Videos); addSubView (CSMWorld::UniversalId::Type_Videos);
} }
void CSVDoc::View::addDebugProfilesSubView()
{
addSubView (CSMWorld::UniversalId::Type_DebugProfiles);
}
void CSVDoc::View::addRunLogSubView()
{
addSubView (CSMWorld::UniversalId::Type_RunLog);
}
void CSVDoc::View::abortOperation (int type) void CSVDoc::View::abortOperation (int type)
{ {
mDocument->abortOperation (type); mDocument->abortOperation (type);
@ -588,3 +641,13 @@ void CSVDoc::View::loadErrorLog()
{ {
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_LoadErrorLog, 0)); addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_LoadErrorLog, 0));
} }
void CSVDoc::View::run (const std::string& profile, const std::string& startupInstruction)
{
mDocument->startRunning (profile, startupInstruction);
}
void CSVDoc::View::stop()
{
mDocument->stopRunning();
}

@ -25,6 +25,7 @@ namespace CSVDoc
{ {
class ViewManager; class ViewManager;
class Operations; class Operations;
class GlobalDebugProfileMenu;
class View : public QMainWindow class View : public QMainWindow
{ {
@ -39,10 +40,12 @@ namespace CSVDoc
QAction *mSave; QAction *mSave;
QAction *mVerify; QAction *mVerify;
QAction *mShowStatusBar; QAction *mShowStatusBar;
QAction *mStopDebug;
std::vector<QAction *> mEditingActions; std::vector<QAction *> mEditingActions;
Operations *mOperations; Operations *mOperations;
SubViewFactoryManager mSubViewFactory; SubViewFactoryManager mSubViewFactory;
QMainWindow mSubViewWindow; QMainWindow mSubViewWindow;
GlobalDebugProfileMenu *mGlobalDebugProfileMenu;
// not implemented // not implemented
@ -67,6 +70,8 @@ namespace CSVDoc
void setupAssetsMenu(); void setupAssetsMenu();
void setupDebugMenu();
void setupUi(); void setupUi();
void updateTitle(); void updateTitle();
@ -194,9 +199,17 @@ namespace CSVDoc
void addVideosSubView(); void addVideosSubView();
void addDebugProfilesSubView();
void addRunLogSubView();
void toggleShowStatusBar (bool show); void toggleShowStatusBar (bool show);
void loadErrorLog(); void loadErrorLog();
void run (const std::string& profile, const std::string& startupInstruction = "");
void stop();
}; };
} }

@ -1,77 +0,0 @@
#include "filtercreator.hpp"
#include <QComboBox>
#include <QLabel>
#include "../../model/filter/filter.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp"
std::string CSVFilter::FilterCreator::getNamespace() const
{
switch (mScope->currentIndex())
{
case CSMFilter::Filter::Scope_Project: return "project::";
case CSMFilter::Filter::Scope_Session: return "session::";
}
return "";
}
void CSVFilter::FilterCreator::update()
{
mNamespace->setText (QString::fromUtf8 (getNamespace().c_str()));
GenericCreator::update();
}
std::string CSVFilter::FilterCreator::getId() const
{
return getNamespace() + GenericCreator::getId();
}
void CSVFilter::FilterCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
{
int index =
dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())).
findColumnIndex (CSMWorld::Columns::ColumnId_Scope);
command.addValue (index, mScope->currentIndex());
}
CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
: GenericCreator (data, undoStack, id)
{
mNamespace = new QLabel ("::", this);
insertAtBeginning (mNamespace, false);
mScope = new QComboBox (this);
mScope->addItem ("Project");
mScope->addItem ("Session");
/// \todo re-enable for OpenMW 1.1
// mScope->addItem ("Content");
connect (mScope, SIGNAL (currentIndexChanged (int)), this, SLOT (setScope (int)));
insertAtBeginning (mScope, false);
QLabel *label = new QLabel ("Scope", this);
insertAtBeginning (label, false);
mScope->setCurrentIndex (1);
}
void CSVFilter::FilterCreator::reset()
{
GenericCreator::reset();
}
void CSVFilter::FilterCreator::setScope (int index)
{
update();
}

@ -1,43 +0,0 @@
#ifndef CSV_FILTER_FILTERCREATOR_H
#define CSV_FILTER_FILTERCREATOR_H
class QComboBox;
class QLabel;
#include "../world/genericcreator.hpp"
namespace CSVFilter
{
class FilterCreator : public CSVWorld::GenericCreator
{
Q_OBJECT
QComboBox *mScope;
QLabel *mNamespace;
private:
std::string getNamespace() const;
protected:
void update();
virtual std::string getId() const;
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
public:
FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
virtual void reset();
private slots:
void setScope (int index);
};
}
#endif

@ -133,6 +133,20 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent
flagAsModified(); flagAsModified();
} }
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
{
Ogre::Vector3 position = getCamera()->getPosition();
std::ostringstream stream;
stream
<< "player->position "
<< position.x << ", " << position.y << ", " << position.z
<< ", 0";
return stream.str();
}
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document) CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
: WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default") : WorldspaceWidget (document, parent), mDocument (document), mWorldspace ("std::default")
{ {
@ -206,8 +220,15 @@ std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (co
return std::make_pair(x, y); return std::make_pair(x, y);
} }
void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data) bool CSVRender::PagedWorldspaceWidget::handleDrop (
const std::vector< CSMWorld::UniversalId >& data, DropType type)
{ {
if (WorldspaceWidget::handleDrop (data, type))
return true;
if (type!=Type_CellsExterior)
return false;
bool selectionChanged = false; bool selectionChanged = false;
for (unsigned i = 0; i < data.size(); ++i) for (unsigned i = 0; i < data.size(); ++i)
{ {
@ -224,16 +245,23 @@ void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::
emit cellSelectionChanged(mSelection); emit cellSelectionChanged(mSelection);
} }
return true;
} }
CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const
{ {
dropRequirments requirements = WorldspaceWidget::getDropRequirements (type);
if (requirements!=ignored)
return requirements;
switch (type) switch (type)
{ {
case cellsExterior: case Type_CellsExterior:
return canHandle; return canHandle;
case cellsInterior: case Type_CellsInterior:
return needUnpaged; return needUnpaged;
default: default:

@ -42,6 +42,8 @@ namespace CSVRender
virtual void referenceAdded (const QModelIndex& index, int start, int end); virtual void referenceAdded (const QModelIndex& index, int start, int end);
virtual std::string getStartupInstruction();
public: public:
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
@ -55,9 +57,11 @@ namespace CSVRender
void setCellSelection (const CSMWorld::CellSelection& selection); void setCellSelection (const CSMWorld::CellSelection& selection);
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data); /// \return Drop handled?
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type);
virtual dropRequirments getDropRequirements(dropType type) const; virtual dropRequirments getDropRequirements(DropType type) const;
/// \attention The created tool is not added to the toolbar (via addTool). Doing /// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function. /// that is the responsibility of the calling function.

@ -1,7 +1,10 @@
#include "unpagedworldspacewidget.hpp" #include "unpagedworldspacewidget.hpp"
#include <sstream>
#include <OgreColourValue.h> #include <OgreColourValue.h>
#include <OgreCamera.h>
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
@ -86,13 +89,21 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI
emit closeRequest(); emit closeRequest();
} }
void CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data) bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& data, DropType type)
{ {
if (WorldspaceWidget::handleDrop (data, type))
return true;
if (type!=Type_CellsInterior)
return false;
mCellId = data.begin()->getId(); mCellId = data.begin()->getId();
mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId));
update(); update();
emit cellChanged(*data.begin()); emit cellChanged(*data.begin());
/// \todo replace mCell return true;
} }
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
@ -149,14 +160,33 @@ void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& pare
flagAsModified(); flagAsModified();
} }
CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
{
Ogre::Vector3 position = getCamera()->getPosition();
std::ostringstream stream;
stream
<< "player->positionCell "
<< position.x << ", " << position.y << ", " << position.z
<< ", 0, \"" << mCellId << "\"";
return stream.str();
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const
{ {
dropRequirments requirements = WorldspaceWidget::getDropRequirements (type);
if (requirements!=ignored)
return requirements;
switch(type) switch(type)
{ {
case cellsInterior: case Type_CellsInterior:
return canHandle; return canHandle;
case cellsExterior: case Type_CellsExterior:
return needPaged; return needPaged;
default: default:

@ -41,9 +41,11 @@ namespace CSVRender
UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document,
QWidget *parent); QWidget *parent);
virtual dropRequirments getDropRequirements(dropType type) const; virtual dropRequirments getDropRequirements(DropType type) const;
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data); /// \return Drop handled?
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type);
private: private:
@ -60,6 +62,8 @@ namespace CSVRender
virtual void referenceAdded (const QModelIndex& index, int start, int end); virtual void referenceAdded (const QModelIndex& index, int start, int end);
virtual std::string getStartupInstruction();
private slots: private slots:
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);

@ -1,6 +1,8 @@
#include "worldspacewidget.hpp" #include "worldspacewidget.hpp"
#include <algorithm>
#include <OgreSceneNode.h> #include <OgreSceneNode.h>
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include <OgreEntity.h> #include <OgreEntity.h>
@ -8,14 +10,16 @@
#include <QtGui/qevent.h> #include <QtGui/qevent.h>
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "../../model/world/idtable.hpp"
#include "../widget/scenetoolmode.hpp" #include "../widget/scenetoolmode.hpp"
#include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle.hpp"
#include "../widget/scenetoolrun.hpp"
#include "elements.hpp" #include "elements.hpp"
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
: SceneWidget (parent), mDocument(document) : SceneWidget (parent), mDocument(document), mRun (0)
{ {
setAcceptDrops(true); setAcceptDrops(true);
@ -38,6 +42,14 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int))); this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int)));
connect (references, SIGNAL (rowsInserted (const QModelIndex&, int, int)), connect (references, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (referenceAdded (const QModelIndex&, int, int))); this, SLOT (referenceAdded (const QModelIndex&, int, int)));
QAbstractItemModel *debugProfiles =
document.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles);
connect (debugProfiles, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&)));
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
} }
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
@ -112,59 +124,98 @@ CSVWidget::SceneToolToggle *CSVRender::WorldspaceWidget::makeSceneVisibilitySele
return mSceneElements; return mSceneElements;
} }
CSVRender::WorldspaceWidget::dropType CSVRender::WorldspaceWidget::getDropType ( CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
CSVWidget::SceneToolbar *parent)
{
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
std::vector<std::string> profiles;
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int stateColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
int defaultColumn = debugProfiles.findColumnIndex (
CSMWorld::Columns::ColumnId_DefaultProfile);
int size = debugProfiles.rowCount();
for (int i=0; i<size; ++i)
{
int state = debugProfiles.data (debugProfiles.index (i, stateColumn)).toInt();
bool default_ = debugProfiles.data (debugProfiles.index (i, defaultColumn)).toInt();
if (state!=CSMWorld::RecordBase::State_Deleted && default_)
profiles.push_back (
debugProfiles.data (debugProfiles.index (i, idColumn)).
toString().toUtf8().constData());
}
std::sort (profiles.begin(), profiles.end());
mRun = new CSVWidget::SceneToolRun (parent, "Run OpenMW from the current camera position",
":door.png", ":faction.png", profiles);
connect (mRun, SIGNAL (runRequest (const std::string&)),
this, SLOT (runRequest (const std::string&)));
return mRun;
}
CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType (
const std::vector< CSMWorld::UniversalId >& data) const std::vector< CSMWorld::UniversalId >& data)
{ {
dropType output = notCells; DropType output = Type_Other;
bool firstIteration = true;
for (unsigned i = 0; i < data.size(); ++i) for (std::vector<CSMWorld::UniversalId>::const_iterator iter (data.begin());
iter!=data.end(); ++iter)
{ {
if (data[i].getType() == CSMWorld::UniversalId::Type_Cell || DropType type = Type_Other;
data[i].getType() == CSMWorld::UniversalId::Type_Cell_Missing)
if (iter->getType()==CSMWorld::UniversalId::Type_Cell ||
iter->getType()==CSMWorld::UniversalId::Type_Cell_Missing)
{ {
if (*(data[i].getId().begin()) == '#') //exterior type = iter->getId().substr (0, 1)=="#" ? Type_CellsExterior : Type_CellsInterior;
{
if (firstIteration)
{
output = cellsExterior;
firstIteration = false;
continue;
}
if (output == cellsInterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
} else //interior
{
if (firstIteration)
{
output = cellsInterior;
firstIteration = false;
continue;
}
if (output == cellsExterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
}
} else {
output = notCells;
break;
} }
else if (iter->getType()==CSMWorld::UniversalId::Type_DebugProfile)
type = Type_DebugProfile;
if (iter==data.begin())
output = type;
else if (output!=type) // mixed types -> ignore
return Type_Other;
} }
return output; return output;
} }
CSVRender::WorldspaceWidget::dropRequirments
CSVRender::WorldspaceWidget::getDropRequirements (DropType type) const
{
if (type==Type_DebugProfile)
return canHandle;
return ignored;
}
bool CSVRender::WorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type)
{
if (type==Type_DebugProfile)
{
if (mRun)
{
for (std::vector<CSMWorld::UniversalId>::const_iterator iter (data.begin());
iter!=data.end(); ++iter)
mRun->addProfile (iter->getId());
}
return true;
}
return false;
}
unsigned int CSVRender::WorldspaceWidget::getElementMask() const unsigned int CSVRender::WorldspaceWidget::getElementMask() const
{ {
return mSceneElements->getSelection(); return mSceneElements->getSelection();
@ -179,6 +230,11 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
tool->addButton (":armor.png", Element_Pathgrid, ":armor.png", "Pathgrid"); tool->addButton (":armor.png", Element_Pathgrid, ":armor.png", "Pathgrid");
} }
CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
{
return mDocument;
}
void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event)
{ {
event->accept(); event->accept();
@ -201,6 +257,58 @@ void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
} //not handling drops from different documents at the moment } //not handling drops from different documents at the moment
} }
void CSVRender::WorldspaceWidget::runRequest (const std::string& profile)
{
mDocument.startRunning (profile, getStartupInstruction());
}
void CSVRender::WorldspaceWidget::debugProfileDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (!mRun)
return;
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int stateColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
for (int i=topLeft.row(); i<=bottomRight.row(); ++i)
{
int state = debugProfiles.data (debugProfiles.index (i, stateColumn)).toInt();
// As of version 0.33 this case can not happen because debug profiles exist only in
// project or session scope, which means they will never be in deleted state. But we
// are adding the code for the sake of completeness and to avoid surprises if debug
// profile ever get extended to content scope.
if (state==CSMWorld::RecordBase::State_Deleted)
mRun->removeProfile (debugProfiles.data (
debugProfiles.index (i, idColumn)).toString().toUtf8().constData());
}
}
void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelIndex& parent,
int start, int end)
{
if (parent.isValid())
return;
if (!mRun)
return;
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
for (int i=start; i<=end; ++i)
{
mRun->removeProfile (debugProfiles.data (
debugProfiles.index (i, idColumn)).toString().toUtf8().constData());
}
}
void CSVRender::WorldspaceWidget::elementSelectionChanged() void CSVRender::WorldspaceWidget::elementSelectionChanged()
{ {
setVisibilityMask (getElementMask()); setVisibilityMask (getElementMask());

@ -18,6 +18,7 @@ namespace CSVWidget
class SceneToolMode; class SceneToolMode;
class SceneToolToggle; class SceneToolToggle;
class SceneToolbar; class SceneToolbar;
class SceneToolRun;
} }
namespace CSVRender namespace CSVRender
@ -30,15 +31,17 @@ namespace CSVRender
CSVRender::NavigationFree mFree; CSVRender::NavigationFree mFree;
CSVRender::NavigationOrbit mOrbit; CSVRender::NavigationOrbit mOrbit;
CSVWidget::SceneToolToggle *mSceneElements; CSVWidget::SceneToolToggle *mSceneElements;
CSVWidget::SceneToolRun *mRun;
CSMDoc::Document& mDocument;
public: public:
enum dropType enum DropType
{ {
cellsMixed, Type_CellsInterior,
cellsInterior, Type_CellsExterior,
cellsExterior, Type_Other,
notCells Type_DebugProfile
}; };
enum dropRequirments enum dropRequirments
@ -60,16 +63,22 @@ namespace CSVRender
CSVWidget::SceneToolToggle *makeSceneVisibilitySelector ( CSVWidget::SceneToolToggle *makeSceneVisibilitySelector (
CSVWidget::SceneToolbar *parent); CSVWidget::SceneToolbar *parent);
/// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function.
CSVWidget::SceneToolRun *makeRunTool (CSVWidget::SceneToolbar *parent);
void selectDefaultNavigationMode(); void selectDefaultNavigationMode();
static dropType getDropType(const std::vector<CSMWorld::UniversalId>& data); static DropType getDropType(const std::vector<CSMWorld::UniversalId>& data);
virtual dropRequirments getDropRequirements(dropType type) const = 0; virtual dropRequirments getDropRequirements(DropType type) const;
virtual void useViewHint (const std::string& hint); virtual void useViewHint (const std::string& hint);
///< Default-implementation: ignored. ///< Default-implementation: ignored.
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data) = 0; /// \return Drop handled?
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type);
virtual unsigned int getElementMask() const; virtual unsigned int getElementMask() const;
@ -77,7 +86,7 @@ namespace CSVRender
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool); virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool);
const CSMDoc::Document& mDocument; CSMDoc::Document& getDocument();
private: private:
@ -87,6 +96,8 @@ namespace CSVRender
void dragMoveEvent(QDragMoveEvent *event); void dragMoveEvent(QDragMoveEvent *event);
virtual std::string getStartupInstruction() = 0;
private slots: private slots:
void selectNavigationMode (const std::string& mode); void selectNavigationMode (const std::string& mode);
@ -104,6 +115,14 @@ namespace CSVRender
virtual void referenceAdded (const QModelIndex& index, int start, int end) = 0; virtual void referenceAdded (const QModelIndex& index, int start, int end) = 0;
virtual void runRequest (const std::string& profile);
void debugProfileDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
protected slots: protected slots:
void elementSelectionChanged(); void elementSelectionChanged();

@ -21,7 +21,7 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc:
mTable->setSelectionMode (QAbstractItemView::ExtendedSelection); mTable->setSelectionMode (QAbstractItemView::ExtendedSelection);
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate ( mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (
document.getUndoStack(), this); document, this);
mTable->setItemDelegateForColumn (0, mIdTypeDelegate); mTable->setItemDelegateForColumn (0, mIdTypeDelegate);

@ -20,6 +20,10 @@ void CSVWidget::PushButton::setExtendedToolTip()
break; break;
case Type_TopAction:
break;
case Type_Mode: case Type_Mode:
tooltip += tooltip +=
@ -87,4 +91,9 @@ bool CSVWidget::PushButton::hasKeepOpen() const
QString CSVWidget::PushButton::getBaseToolTip() const QString CSVWidget::PushButton::getBaseToolTip() const
{ {
return mToolTip; return mToolTip;
}
CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const
{
return mType;
} }

@ -14,6 +14,7 @@ namespace CSVWidget
enum Type enum Type
{ {
Type_TopMode, // top level button for mode selector panel Type_TopMode, // top level button for mode selector panel
Type_TopAction, // top level button that triggers an action
Type_Mode, // mode button Type_Mode, // mode button
Type_Toggle Type_Toggle
}; };
@ -50,6 +51,8 @@ namespace CSVWidget
/// Return tooltip used at construction (without any button-specific modifications) /// Return tooltip used at construction (without any button-specific modifications)
QString getBaseToolTip() const; QString getBaseToolTip() const;
Type getType() const;
}; };
} }

@ -1,10 +1,12 @@
#include "scenetool.hpp" #include "scenetool.hpp"
#include <QMouseEvent>
#include "scenetoolbar.hpp" #include "scenetoolbar.hpp"
CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) CSVWidget::SceneTool::SceneTool (SceneToolbar *parent, Type type)
: PushButton (PushButton::Type_TopMode, "", parent) : PushButton (type, "", parent)
{ {
setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
setIconSize (QSize (parent->getIconSize(), parent->getIconSize())); setIconSize (QSize (parent->getIconSize(), parent->getIconSize()));
@ -13,7 +15,20 @@ CSVWidget::SceneTool::SceneTool (SceneToolbar *parent)
connect (this, SIGNAL (clicked()), this, SLOT (openRequest())); connect (this, SIGNAL (clicked()), this, SLOT (openRequest()));
} }
void CSVWidget::SceneTool::activate() {}
void CSVWidget::SceneTool::mouseReleaseEvent (QMouseEvent *event)
{
if (getType()==Type_TopAction && event->button()==Qt::RightButton)
showPanel (parentWidget()->mapToGlobal (pos()));
else
PushButton::mouseReleaseEvent (event);
}
void CSVWidget::SceneTool::openRequest() void CSVWidget::SceneTool::openRequest()
{ {
showPanel (parentWidget()->mapToGlobal (pos())); if (getType()==Type_TopAction)
activate();
else
showPanel (parentWidget()->mapToGlobal (pos()));
} }

@ -14,10 +14,18 @@ namespace CSVWidget
public: public:
SceneTool (SceneToolbar *parent); SceneTool (SceneToolbar *parent, Type type = Type_TopMode);
virtual void showPanel (const QPoint& position) = 0; virtual void showPanel (const QPoint& position) = 0;
/// This function will only called for buttons of type Type_TopAction. The default
/// implementation is empty.
virtual void activate();
protected:
void mouseReleaseEvent (QMouseEvent *event);
private slots: private slots:
void openRequest(); void openRequest();

@ -0,0 +1,151 @@
#include "scenetoolrun.hpp"
#include <iterator>
#include <QFrame>
#include <QTableWidget>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QApplication>
void CSVWidget::SceneToolRun::adjustToolTips()
{
QString toolTip = mToolTip;
if (mSelected==mProfiles.end())
toolTip += "<p>No debug profile selected (function disabled)";
else
{
toolTip += "<p>Debug profile: " + QString::fromUtf8 (mSelected->c_str());
toolTip += "<p>(right click to switch to a different profile)";
}
setToolTip (toolTip);
}
void CSVWidget::SceneToolRun::updateIcon()
{
setIcon (QIcon (mSelected==mProfiles.end() ? mIconDisabled : mIcon));
}
void CSVWidget::SceneToolRun::updatePanel()
{
mTable->setRowCount (mProfiles.size());
int i = 0;
for (std::set<std::string>::const_iterator iter (mProfiles.begin()); iter!=mProfiles.end();
++iter, ++i)
{
mTable->setItem (i, 0, new QTableWidgetItem (QString::fromUtf8 (iter->c_str())));
mTable->setItem (i, 1, new QTableWidgetItem (
QApplication::style()->standardIcon (QStyle::SP_TitleBarCloseButton), ""));
}
}
CSVWidget::SceneToolRun::SceneToolRun (SceneToolbar *parent, const QString& toolTip,
const QString& icon, const QString& iconDisabled, const std::vector<std::string>& profiles)
: SceneTool (parent, Type_TopAction), mProfiles (profiles.begin(), profiles.end()),
mSelected (mProfiles.begin()), mToolTip (toolTip), mIcon (icon),
mIconDisabled (iconDisabled)
{
updateIcon();
adjustToolTips();
mPanel = new QFrame (this, Qt::Popup);
QHBoxLayout *layout = new QHBoxLayout (mPanel);
layout->setContentsMargins (QMargins (0, 0, 0, 0));
mTable = new QTableWidget (0, 2, this);
mTable->setShowGrid (false);
mTable->verticalHeader()->hide();
mTable->horizontalHeader()->hide();
mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch);
mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents);
mTable->setSelectionMode (QAbstractItemView::NoSelection);
layout->addWidget (mTable);
connect (mTable, SIGNAL (clicked (const QModelIndex&)),
this, SLOT (clicked (const QModelIndex&)));
}
void CSVWidget::SceneToolRun::showPanel (const QPoint& position)
{
updatePanel();
mPanel->move (position);
mPanel->show();
}
void CSVWidget::SceneToolRun::activate()
{
if (mSelected!=mProfiles.end())
emit runRequest (*mSelected);
}
void CSVWidget::SceneToolRun::removeProfile (const std::string& profile)
{
std::set<std::string>::iterator iter = mProfiles.find (profile);
if (iter!=mProfiles.end())
{
if (iter==mSelected)
{
if (iter!=mProfiles.begin())
--mSelected;
else
++mSelected;
}
mProfiles.erase (iter);
if (mSelected==mProfiles.end())
updateIcon();
adjustToolTips();
}
}
void CSVWidget::SceneToolRun::addProfile (const std::string& profile)
{
std::set<std::string>::iterator iter = mProfiles.find (profile);
if (iter==mProfiles.end())
{
mProfiles.insert (profile);
if (mSelected==mProfiles.end())
{
mSelected = mProfiles.begin();
updateIcon();
}
adjustToolTips();
}
}
void CSVWidget::SceneToolRun::clicked (const QModelIndex& index)
{
if (index.column()==0)
{
// select profile
mSelected = mProfiles.begin();
std::advance (mSelected, index.row());
mPanel->hide();
adjustToolTips();
}
else if (index.column()==1)
{
// remove profile from list
std::set<std::string>::iterator iter = mProfiles.begin();
std::advance (iter, index.row());
removeProfile (*iter);
updatePanel();
}
}

@ -0,0 +1,64 @@
#ifndef CSV_WIDGET_SCENETOOLRUN_H
#define CSV_WIDGET_SCENETOOLRUN_H
#include <set>
#include <string>
#include "scenetool.hpp"
class QFrame;
class QTableWidget;
class QModelIndex;
namespace CSVWidget
{
class SceneToolRun : public SceneTool
{
Q_OBJECT
std::set<std::string> mProfiles;
std::set<std::string>::iterator mSelected;
QString mToolTip;
QString mIcon;
QString mIconDisabled;
QFrame *mPanel;
QTableWidget *mTable;
private:
void adjustToolTips();
void updateIcon();
void updatePanel();
public:
SceneToolRun (SceneToolbar *parent, const QString& toolTip, const QString& icon,
const QString& iconDisabled, const std::vector<std::string>& profiles);
virtual void showPanel (const QPoint& position);
virtual void activate();
/// \attention This function does not remove the profile from the profile selection
/// panel.
void removeProfile (const std::string& profile);
/// \attention This function doe not add the profile to the profile selection
/// panel. This only happens when the panel is re-opened.
///
/// \note Adding profiles that are already listed is a no-op.
void addProfile (const std::string& profile);
private slots:
void clicked (const QModelIndex& index);
signals:
void runRequest (const std::string& profile);
};
}
#endif

@ -1,7 +1,16 @@
#include "creator.hpp" #include "creator.hpp"
CSVWorld::Creator:: ~Creator() {} #include <stdexcept>
CSVWorld::Creator::~Creator() {}
void CSVWorld::Creator::setScope (unsigned int scope)
{
if (scope!=CSMWorld::Scope_Content)
throw std::logic_error ("Invalid scope in creator");
}
CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {} CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {}

@ -1,9 +1,14 @@
#ifndef CSV_WORLD_CREATOR_H #ifndef CSV_WORLD_CREATOR_H
#define CSV_WORLD_CREATOR_H #define CSV_WORLD_CREATOR_H
#include <memory>
#include <QWidget> #include <QWidget>
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "../../model/world/scope.hpp"
class QUndoStack; class QUndoStack;
namespace CSMWorld namespace CSMWorld
@ -32,6 +37,9 @@ namespace CSVWorld
virtual void toggleWidgets(bool active = true) = 0; virtual void toggleWidgets(bool active = true) = 0;
/// Default implementation: Throw an exception if scope!=Scope_Content.
virtual void setScope (unsigned int scope);
signals: signals:
void done(); void done();
@ -68,7 +76,7 @@ namespace CSVWorld
/// \note The function always returns 0. /// \note The function always returns 0.
}; };
template<class CreatorT> template<class CreatorT, unsigned int scope = CSMWorld::Scope_Content>
class CreatorFactory : public CreatorFactoryBase class CreatorFactory : public CreatorFactoryBase
{ {
public: public:
@ -81,11 +89,15 @@ namespace CSVWorld
/// records should be provided. /// records should be provided.
}; };
template<class CreatorT> template<class CreatorT, unsigned int scope>
Creator *CreatorFactory<CreatorT>::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, Creator *CreatorFactory<CreatorT, scope>::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const const CSMWorld::UniversalId& id) const
{ {
return new CreatorT (data, undoStack, id); std::auto_ptr<CreatorT> creator (new CreatorT (data, undoStack, id));
creator->setScope (scope);
return creator.release();
} }
} }

@ -6,11 +6,11 @@
CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
const IconList &icons, const IconList &icons,
QUndoStack &undoStack, CSMDoc::Document& document,
const QString &pageName, const QString &pageName,
const QString &settingName, const QString &settingName,
QObject *parent) QObject *parent)
: EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly), : EnumDelegate (values, document, parent), mDisplayMode (Mode_TextOnly),
mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3), mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3),
mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName) mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName)
{ {
@ -126,8 +126,6 @@ void CSVWorld::DataDisplayDelegate::updateDisplayMode (const QString &mode)
CSVWorld::DataDisplayDelegate::~DataDisplayDelegate() CSVWorld::DataDisplayDelegate::~DataDisplayDelegate()
{ {
mIcons.clear();
mPixmaps.clear();
} }
void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName, QString iconFilename) void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName, QString iconFilename)
@ -137,11 +135,10 @@ void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName,
} }
CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (QUndoStack& undoStack, CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (
QObject *parent) const CSMDoc::Document& document, QObject *parent) const
{ {
return new DataDisplayDelegate (mValues, mIcons, document, "", "", parent);
return new DataDisplayDelegate (mValues, mIcons, undoStack, "", "", parent);
} }

@ -40,7 +40,7 @@ namespace CSVWorld
public: public:
explicit DataDisplayDelegate (const ValueList & values, explicit DataDisplayDelegate (const ValueList & values,
const IconList & icons, const IconList & icons,
QUndoStack& undoStack, CSMDoc::Document& document,
const QString &pageName, const QString &pageName,
const QString &settingName, const QString &settingName,
QObject *parent); QObject *parent);
@ -82,7 +82,7 @@ namespace CSVWorld
public: public:
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
protected: protected:

@ -167,10 +167,10 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::
==============================DialogueDelegateDispatcher========================================== ==============================DialogueDelegateDispatcher==========================================
*/ */
CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack) : CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document) :
mParent(parent), mParent(parent),
mTable(table), mTable(table),
mUndoStack(undoStack), mDocument (document),
mNotEditableDelegate(table, parent) mNotEditableDelegate(table, parent)
{ {
} }
@ -182,7 +182,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS
if (delegateIt == mDelegates.end()) if (delegateIt == mDelegates.end())
{ {
delegate = CommandDelegateFactoryCollection::get().makeDelegate ( delegate = CommandDelegateFactoryCollection::get().makeDelegate (
display, mUndoStack, mParent); display, mDocument, mParent);
mDelegates.insert(std::make_pair(display, delegate)); mDelegates.insert(std::make_pair(display, delegate));
} else } else
{ {
@ -266,7 +266,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
editor = delegateIt->second->createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index, display); editor = delegateIt->second->createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index, display);
DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display);
bool skip = false;
if (qobject_cast<DropLineEdit*>(editor)) if (qobject_cast<DropLineEdit*>(editor))
{ {
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
@ -274,27 +273,22 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
proxy, SLOT(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*))); proxy, SLOT(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)));
connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), 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*))); this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
skip = true;
} }
if(!skip && qobject_cast<QCheckBox*>(editor)) else if (qobject_cast<QCheckBox*>(editor))
{ {
connect(editor, SIGNAL(stateChanged(int)), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(stateChanged(int)), proxy, SLOT(editorDataCommited()));
skip = true;
} }
if(!skip && qobject_cast<QPlainTextEdit*>(editor)) else if (qobject_cast<QPlainTextEdit*>(editor))
{ {
connect(editor, SIGNAL(textChanged()), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(textChanged()), proxy, SLOT(editorDataCommited()));
skip = true;
} }
if(!skip && qobject_cast<QComboBox*>(editor)) else if (qobject_cast<QComboBox*>(editor))
{ {
connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited()));
skip = true;
} }
if(!skip && qobject_cast<QAbstractSpinBox*>(editor)) else if (qobject_cast<QAbstractSpinBox*>(editor))
{ {
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
skip = true;
} }
connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display))); connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)));
@ -315,12 +309,12 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher()
=============================================================EditWidget===================================================== =============================================================EditWidget=====================================================
*/ */
CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) : CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) :
mDispatcher(this, table, undoStack), mDispatcher(this, table, document),
QScrollArea(parent), QScrollArea(parent),
mWidgetMapper(NULL), mWidgetMapper(NULL),
mMainWidget(NULL), mMainWidget(NULL),
mUndoStack(undoStack), mDocument (document),
mTable(table) mTable(table)
{ {
remake (row); remake (row);
@ -478,7 +472,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
mMainLayout = new QVBoxLayout(mainWidget); mMainLayout = new QVBoxLayout(mainWidget);
mEditWidget = new EditWidget(mainWidget, mRow, mTable, mUndoStack, false); mEditWidget = new EditWidget(mainWidget, mRow, mTable, document, false);
connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)), 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*))); this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));

@ -101,14 +101,14 @@ namespace CSVWorld
CSMWorld::IdTable* mTable; CSMWorld::IdTable* mTable;
QUndoStack& mUndoStack; CSMDoc::Document& mDocument;
NotEditableSubDelegate mNotEditableDelegate; NotEditableSubDelegate mNotEditableDelegate;
std::vector<DialogueDelegateDispatcherProxy*> mProxys; //once we move to the C++11 we should use unique_ptr std::vector<DialogueDelegateDispatcherProxy*> mProxys; //once we move to the C++11 we should use unique_ptr
public: public:
DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack); DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document);
~DialogueDelegateDispatcher(); ~DialogueDelegateDispatcher();
@ -145,11 +145,11 @@ namespace CSVWorld
DialogueDelegateDispatcher mDispatcher; DialogueDelegateDispatcher mDispatcher;
QWidget* mMainWidget; QWidget* mMainWidget;
CSMWorld::IdTable* mTable; CSMWorld::IdTable* mTable;
QUndoStack& mUndoStack; CSMDoc::Document& mDocument;
public: public:
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false); EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete = false);
void remake(int row); void remake(int row);

@ -35,8 +35,8 @@ void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model,
CSVWorld::EnumDelegate::EnumDelegate (const std::vector<std::pair<int, QString> >& values, CSVWorld::EnumDelegate::EnumDelegate (const std::vector<std::pair<int, QString> >& values,
QUndoStack& undoStack, QObject *parent) CSMDoc::Document& document, QObject *parent)
: CommandDelegate (undoStack, parent), mValues (values) : CommandDelegate (document, parent), mValues (values)
{ {
} }
@ -140,10 +140,10 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector<std::strin
add (i, names[i].c_str()); add (i, names[i].c_str());
} }
CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack, CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (
QObject *parent) const CSMDoc::Document& document, QObject *parent) const
{ {
return new EnumDelegate (mValues, undoStack, parent); return new EnumDelegate (mValues, document, parent);
} }
void CSVWorld::EnumDelegateFactory::add (int value, const QString& name) void CSVWorld::EnumDelegateFactory::add (int value, const QString& name)

@ -30,7 +30,7 @@ namespace CSVWorld
public: public:
EnumDelegate (const std::vector<std::pair<int, QString> >& values, EnumDelegate (const std::vector<std::pair<int, QString> >& values,
QUndoStack& undoStack, QObject *parent); CSMDoc::Document& document, QObject *parent);
virtual QWidget *createEditor(QWidget *parent, virtual QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem& option, const QStyleOptionViewItem& option,
@ -64,7 +64,7 @@ namespace CSVWorld
EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false); EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false);
/// \param allowNone Use value of -1 for "none selected" (empty string) /// \param allowNone Use value of -1 for "none selected" (empty string)
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
void add (int value, const QString& name); void add (int value, const QString& name);

@ -7,6 +7,10 @@
#include <QPushButton> #include <QPushButton>
#include <QLineEdit> #include <QLineEdit>
#include <QUndoStack> #include <QUndoStack>
#include <QLabel>
#include <QComboBox>
#include <components/misc/stringops.hpp>
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
@ -56,22 +60,66 @@ const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
return mListId; return mListId;
} }
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack, std::string CSVWorld::GenericCreator::getNamespace() const
const CSMWorld::UniversalId& id, bool relaxedIdRules): {
CSMWorld::Scope scope = CSMWorld::Scope_Content;
if (mScope)
{
scope = static_cast<CSMWorld::Scope> (mScope->itemData (mScope->currentIndex()).toInt());
}
else
{
if (mScopes & CSMWorld::Scope_Project)
scope = CSMWorld::Scope_Project;
else if (mScopes & CSMWorld::Scope_Session)
scope = CSMWorld::Scope_Session;
}
mData (data), switch (scope)
mUndoStack (undoStack), {
mListId (id), case CSMWorld::Scope_Content: return "";
mLocked (false), case CSMWorld::Scope_Project: return "project::";
mCloneMode(false), case CSMWorld::Scope_Session: return "session::";
mClonedType(CSMWorld::UniversalId::Type_None) }
return "";
}
void CSVWorld::GenericCreator::updateNamespace()
{
std::string namespace_ = getNamespace();
mValidator->setNamespace (namespace_);
int index = mId->text().indexOf ("::");
if (index==-1)
{
// no namespace in old text
mId->setText (QString::fromUtf8 (namespace_.c_str()) + mId->text());
}
else
{
std::string oldNamespace =
Misc::StringUtils::lowerCase (mId->text().left (index).toUtf8().constData());
if (oldNamespace=="project" || oldNamespace=="session")
mId->setText (QString::fromUtf8 (namespace_.c_str()) + mId->text().mid (index+2));
}
}
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id, bool relaxedIdRules)
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false), mCloneMode (false),
mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0),
mScopeLabel (0)
{ {
mLayout = new QHBoxLayout; mLayout = new QHBoxLayout;
mLayout->setContentsMargins (0, 0, 0, 0); mLayout->setContentsMargins (0, 0, 0, 0);
mId = new QLineEdit; mId = new QLineEdit;
mId->setValidator (new IdValidator (relaxedIdRules, this)); mId->setValidator (mValidator = new IdValidator (relaxedIdRules, this));
mLayout->addWidget (mId, 1); mLayout->addWidget (mId, 1);
mCreate = new QPushButton ("Create"); mCreate = new QPushButton ("Create");
@ -99,22 +147,17 @@ void CSVWorld::GenericCreator::reset()
mCloneMode = false; mCloneMode = false;
mId->setText (""); mId->setText ("");
update(); update();
updateNamespace();
} }
std::string CSVWorld::GenericCreator::getErrors() const std::string CSVWorld::GenericCreator::getErrors() const
{ {
std::string errors; std::string errors;
std::string id = getId(); if (!mId->hasAcceptableInput())
errors = mValidator->getError();
if (id.empty()) else if (mData.hasId (getId()))
{
errors = "Missing ID";
}
else if (mData.hasId (id))
{
errors = "ID is already in use"; errors = "ID is already in use";
}
return errors; return errors;
} }
@ -128,29 +171,28 @@ void CSVWorld::GenericCreator::create()
{ {
if (!mLocked) if (!mLocked)
{ {
std::string id = getId();
if (mCloneMode) if (mCloneMode)
{ {
std::string id = getId();
std::auto_ptr<CSMWorld::CloneCommand> command (new CSMWorld::CloneCommand ( std::auto_ptr<CSMWorld::CloneCommand> command (new CSMWorld::CloneCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel(mListId)), mClonedId, id, mClonedType)); dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel(mListId)), mClonedId, id, mClonedType));
mUndoStack.push(command.release()); mUndoStack.push(command.release());
emit done(); }
emit requestFocus(id); else
} else { {
std::string id = getId();
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand ( std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id)); dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id));
configureCreateCommand (*command); configureCreateCommand (*command);
mUndoStack.push (command.release()); mUndoStack.push (command.release());
emit done();
emit requestFocus (id);
} }
emit done();
emit requestFocus(id);
} }
} }
@ -165,3 +207,49 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId,
void CSVWorld::GenericCreator::toggleWidgets(bool active) void CSVWorld::GenericCreator::toggleWidgets(bool active)
{ {
} }
void CSVWorld::GenericCreator::setScope (unsigned int scope)
{
mScopes = scope;
int count = (mScopes & CSMWorld::Scope_Content) + (mScopes & CSMWorld::Scope_Project) +
(mScopes & CSMWorld::Scope_Session);
// scope selector widget
if (count>1)
{
mScope = new QComboBox (this);
insertAtBeginning (mScope, false);
if (mScopes & CSMWorld::Scope_Content)
mScope->addItem ("Content", static_cast<int> (CSMWorld::Scope_Content));
if (mScopes & CSMWorld::Scope_Project)
mScope->addItem ("Project", static_cast<int> (CSMWorld::Scope_Project));
if (mScopes & CSMWorld::Scope_Session)
mScope->addItem ("Session", static_cast<int> (CSMWorld::Scope_Session));
connect (mScope, SIGNAL (currentIndexChanged (int)), this, SLOT (scopeChanged (int)));
mScopeLabel = new QLabel ("Scope", this);
insertAtBeginning (mScopeLabel, false);
mScope->setCurrentIndex (0);
}
else
{
delete mScope;
mScope = 0;
delete mScopeLabel;
mScopeLabel = 0;
}
updateNamespace();
}
void CSVWorld::GenericCreator::scopeChanged (int index)
{
update();
updateNamespace();
}

@ -5,6 +5,8 @@ class QString;
class QPushButton; class QPushButton;
class QLineEdit; class QLineEdit;
class QHBoxLayout; class QHBoxLayout;
class QComboBox;
class QLabel;
#include "creator.hpp" #include "creator.hpp"
@ -17,6 +19,8 @@ namespace CSMWorld
namespace CSVWorld namespace CSVWorld
{ {
class IdValidator;
class GenericCreator : public Creator class GenericCreator : public Creator
{ {
Q_OBJECT Q_OBJECT
@ -31,6 +35,10 @@ namespace CSVWorld
bool mLocked; bool mLocked;
std::string mClonedId; std::string mClonedId;
CSMWorld::UniversalId::Type mClonedType; CSMWorld::UniversalId::Type mClonedType;
unsigned int mScopes;
QComboBox *mScope;
QLabel *mScopeLabel;
IdValidator *mValidator;
protected: protected:
bool mCloneMode; bool mCloneMode;
@ -54,6 +62,12 @@ namespace CSVWorld
const CSMWorld::UniversalId& getCollectionId() const; const CSMWorld::UniversalId& getCollectionId() const;
std::string getNamespace() const;
private:
void updateNamespace();
public: public:
GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack, GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
@ -65,18 +79,22 @@ namespace CSVWorld
virtual void toggleWidgets (bool active = true); virtual void toggleWidgets (bool active = true);
virtual void cloneMode(const std::string& originId, virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type); const CSMWorld::UniversalId::Type type);
virtual std::string getErrors() const; virtual std::string getErrors() const;
///< Return formatted error descriptions for the current state of the creator. if an empty ///< Return formatted error descriptions for the current state of the creator. if an empty
/// string is returned, there is no error. /// string is returned, there is no error.
virtual void setScope (unsigned int scope);
private slots: private slots:
void textChanged (const QString& text); void textChanged (const QString& text);
void create(); void create();
void scopeChanged (int index);
}; };
} }

@ -3,8 +3,8 @@
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
CSVWorld::IdTypeDelegate::IdTypeDelegate CSVWorld::IdTypeDelegate::IdTypeDelegate
(const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent) (const ValueList &values, const IconList &icons, CSMDoc::Document& document, QObject *parent)
: DataDisplayDelegate (values, icons, undoStack, : DataDisplayDelegate (values, icons, document,
"Display Format", "Referenceable ID Type Display", "Display Format", "Referenceable ID Type Display",
parent) parent)
{} {}
@ -20,8 +20,8 @@ CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory()
} }
} }
CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate (
QObject *parent) const CSMDoc::Document& document, QObject *parent) const
{ {
return new IdTypeDelegate (mValues, mIcons, undoStack, parent); return new IdTypeDelegate (mValues, mIcons, document, parent);
} }

@ -11,7 +11,7 @@ namespace CSVWorld
class IdTypeDelegate : public DataDisplayDelegate class IdTypeDelegate : public DataDisplayDelegate
{ {
public: public:
IdTypeDelegate (const ValueList &mValues, const IconList &icons, QUndoStack& undoStack, QObject *parent); IdTypeDelegate (const ValueList &mValues, const IconList &icons, CSMDoc::Document& document, QObject *parent);
}; };
class IdTypeDelegateFactory : public DataDisplayDelegateFactory class IdTypeDelegateFactory : public DataDisplayDelegateFactory
@ -20,7 +20,7 @@ namespace CSVWorld
IdTypeDelegateFactory(); IdTypeDelegateFactory();
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
}; };
} }

@ -1,6 +1,8 @@
#include "idvalidator.hpp" #include "idvalidator.hpp"
#include <components/misc/stringops.hpp>
bool CSVWorld::IdValidator::isValid (const QChar& c, bool first) const bool CSVWorld::IdValidator::isValid (const QChar& c, bool first) const
{ {
if (c.isLetter() || c=='_') if (c.isLetter() || c=='_')
@ -18,6 +20,8 @@ CSVWorld::IdValidator::IdValidator (bool relaxed, QObject *parent)
QValidator::State CSVWorld::IdValidator::validate (QString& input, int& pos) const QValidator::State CSVWorld::IdValidator::validate (QString& input, int& pos) const
{ {
mError.clear();
if (mRelaxed) if (mRelaxed)
{ {
if (input.indexOf ('"')!=-1 || input.indexOf ("::")!=-1 || input.indexOf ("#")!=-1) if (input.indexOf ('"')!=-1 || input.indexOf ("::")!=-1 || input.indexOf ("#")!=-1)
@ -25,12 +29,95 @@ QValidator::State CSVWorld::IdValidator::validate (QString& input, int& pos) con
} }
else else
{ {
if (input.isEmpty())
{
mError = "Missing ID";
return QValidator::Intermediate;
}
bool first = true; bool first = true;
bool scope = false;
bool prevScope = false;
QString::const_iterator iter = input.begin();
if (!mNamespace.empty())
{
std::string namespace_ = input.left (mNamespace.size()).toUtf8().constData();
if (Misc::StringUtils::lowerCase (namespace_)!=mNamespace)
return QValidator::Invalid; // incorrect namespace
iter += namespace_.size();
first = false;
prevScope = true;
}
else
{
int index = input.indexOf (":");
if (index!=-1)
{
QString namespace_ = input.left (index);
if (namespace_=="project" || namespace_=="session")
return QValidator::Invalid; // reserved namespace
}
}
for (; iter!=input.end(); ++iter, first = false)
{
if (*iter==':')
{
if (first)
return QValidator::Invalid; // scope operator at the beginning
for (QString::const_iterator iter (input.begin()); iter!=input.end(); ++iter, first = false) if (scope)
if (!isValid (*iter, first)) {
return QValidator::Invalid; scope = false;
prevScope = true;
}
else
{
if (prevScope)
return QValidator::Invalid; // sequence of two scope operators
scope = true;
}
}
else if (scope)
return QValidator::Invalid; // incomplete scope operator
else
{
prevScope = false;
if (!isValid (*iter, first))
return QValidator::Invalid;
}
}
if (scope)
{
mError = "ID ending with incomplete scope operator";
return QValidator::Intermediate;
}
if (prevScope)
{
mError = "ID ending with scope operator";
return QValidator::Intermediate;
}
} }
return QValidator::Acceptable; return QValidator::Acceptable;
}
void CSVWorld::IdValidator::setNamespace (const std::string& namespace_)
{
mNamespace = Misc::StringUtils::lowerCase (namespace_);
}
std::string CSVWorld::IdValidator::getError() const
{
return mError;
} }

@ -1,6 +1,8 @@
#ifndef CSV_WORLD_IDVALIDATOR_H #ifndef CSV_WORLD_IDVALIDATOR_H
#define CSV_WORLD_IDVALIDATOR_H #define CSV_WORLD_IDVALIDATOR_H
#include <string>
#include <QValidator> #include <QValidator>
namespace CSVWorld namespace CSVWorld
@ -8,6 +10,8 @@ namespace CSVWorld
class IdValidator : public QValidator class IdValidator : public QValidator
{ {
bool mRelaxed; bool mRelaxed;
std::string mNamespace;
mutable std::string mError;
private: private:
@ -20,6 +24,14 @@ namespace CSVWorld
virtual State validate (QString& input, int& pos) const; virtual State validate (QString& input, int& pos) const;
void setNamespace (const std::string& namespace_);
/// Return a description of the error that resulted in the last call of validate
/// returning QValidator::Intermediate. If the last call to validate returned
/// a different value (or if there was no such call yet), an empty string is
/// returned.
std::string getError() const;
}; };
} }

@ -9,16 +9,16 @@
CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values,
const IconList & icons, const IconList & icons,
QUndoStack &undoStack, QObject *parent) CSMDoc::Document& document, QObject *parent)
: DataDisplayDelegate (values, icons, undoStack, : DataDisplayDelegate (values, icons, document,
"Display Format", "Record Status Display", "Display Format", "Record Status Display",
parent) parent)
{} {}
CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate (QUndoStack& undoStack, CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate (
QObject *parent) const CSMDoc::Document& document, QObject *parent) const
{ {
return new RecordStatusDelegate (mValues, mIcons, undoStack, parent); return new RecordStatusDelegate (mValues, mIcons, document, parent);
} }
CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory() CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory()

@ -19,7 +19,7 @@ namespace CSVWorld
explicit RecordStatusDelegate(const ValueList& values, explicit RecordStatusDelegate(const ValueList& values,
const IconList& icons, const IconList& icons,
QUndoStack& undoStack, QObject *parent = 0); CSMDoc::Document& document, QObject *parent = 0);
}; };
class RecordStatusDelegateFactory : public DataDisplayDelegateFactory class RecordStatusDelegateFactory : public DataDisplayDelegateFactory
@ -28,7 +28,7 @@ namespace CSVWorld
RecordStatusDelegateFactory(); RecordStatusDelegateFactory();
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
}; };

@ -20,6 +20,7 @@
#include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolbar.hpp"
#include "../widget/scenetoolmode.hpp" #include "../widget/scenetoolmode.hpp"
#include "../widget/scenetooltoggle.hpp" #include "../widget/scenetooltoggle.hpp"
#include "../widget/scenetoolrun.hpp"
#include "tablebottombox.hpp" #include "tablebottombox.hpp"
#include "creator.hpp" #include "creator.hpp"
@ -121,6 +122,9 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp
toolbar->addTool (controlVisibilityTool); toolbar->addTool (controlVisibilityTool);
} }
CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar);
toolbar->addTool (runTool);
return toolbar; return toolbar;
} }
@ -194,10 +198,12 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI
CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL; CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = NULL;
CSVWidget::SceneToolbar* toolbar = NULL; CSVWidget::SceneToolbar* toolbar = NULL;
switch (mScene->getDropRequirements(CSVRender::WorldspaceWidget::getDropType(data))) CSVRender::WorldspaceWidget::DropType type = CSVRender::WorldspaceWidget::getDropType (data);
switch (mScene->getDropRequirements (type))
{ {
case CSVRender::WorldspaceWidget::canHandle: case CSVRender::WorldspaceWidget::canHandle:
mScene->handleDrop(data); mScene->handleDrop (data, type);
break; break;
case CSVRender::WorldspaceWidget::needPaged: case CSVRender::WorldspaceWidget::needPaged:
@ -205,7 +211,7 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI
toolbar = makeToolbar(pagedNewWidget, widget_Paged); toolbar = makeToolbar(pagedNewWidget, widget_Paged);
makeConnections(pagedNewWidget); makeConnections(pagedNewWidget);
replaceToolbarAndWorldspace(pagedNewWidget, toolbar); replaceToolbarAndWorldspace(pagedNewWidget, toolbar);
mScene->handleDrop(data); mScene->handleDrop (data, type);
break; break;
case CSVRender::WorldspaceWidget::needUnpaged: case CSVRender::WorldspaceWidget::needUnpaged:

@ -6,14 +6,35 @@
#include <QRegExp> #include <QRegExp>
#include <QString> #include <QString>
#include "../../model/doc/document.hpp"
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
CSVWorld::ScriptEdit::ScriptEdit (QWidget* parent, const CSMDoc::Document& document) :
QTextEdit (parent), CSVWorld::ScriptEdit::ChangeLock::ChangeLock (ScriptEdit& edit) : mEdit (edit)
{
++mEdit.mChangeLocked;
}
CSVWorld::ScriptEdit::ChangeLock::~ChangeLock()
{
--mEdit.mChangeLocked;
}
CSVWorld::ScriptEdit::ScriptEdit (const CSMDoc::Document& document, ScriptHighlighter::Mode mode,
QWidget* parent)
: QPlainTextEdit (parent),
mDocument (document), mDocument (document),
mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive) mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive),
mChangeLocked (0)
{ {
// setAcceptRichText (false);
setLineWrapMode (QPlainTextEdit::NoWrap);
setTabStopWidth (4);
setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead
mAllowedTypes <<CSMWorld::UniversalId::Type_Journal mAllowedTypes <<CSMWorld::UniversalId::Type_Journal
<<CSMWorld::UniversalId::Type_Global <<CSMWorld::UniversalId::Type_Global
<<CSMWorld::UniversalId::Type_Topic <<CSMWorld::UniversalId::Type_Topic
@ -40,14 +61,29 @@ CSVWorld::ScriptEdit::ScriptEdit (QWidget* parent, const CSMDoc::Document& docum
<<CSMWorld::UniversalId::Type_Probe <<CSMWorld::UniversalId::Type_Probe
<<CSMWorld::UniversalId::Type_Repair <<CSMWorld::UniversalId::Type_Repair
<<CSMWorld::UniversalId::Type_Static <<CSMWorld::UniversalId::Type_Static
<<CSMWorld::UniversalId::Type_Weapon; <<CSMWorld::UniversalId::Type_Weapon
<<CSMWorld::UniversalId::Type_Script
<<CSMWorld::UniversalId::Type_Region;
mHighlighter = new ScriptHighlighter (document.getData(), mode, ScriptEdit::document());
connect (&document.getData(), SIGNAL (idListChanged()), this, SLOT (idListChanged()));
connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting()));
mUpdateTimer.setSingleShot (true);
}
bool CSVWorld::ScriptEdit::isChangeLocked() const
{
return mChangeLocked!=0;
} }
void CSVWorld::ScriptEdit::dragEnterEvent (QDragEnterEvent* event) void CSVWorld::ScriptEdit::dragEnterEvent (QDragEnterEvent* event)
{ {
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()); const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) if (!mime)
QTextEdit::dragEnterEvent(event); QPlainTextEdit::dragEnterEvent(event);
else else
{ {
setTextCursor (cursorForPosition (event->pos())); setTextCursor (cursorForPosition (event->pos()));
@ -59,7 +95,7 @@ void CSVWorld::ScriptEdit::dragMoveEvent (QDragMoveEvent* event)
{ {
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()); const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (!mime) if (!mime)
QTextEdit::dragMoveEvent(event); QPlainTextEdit::dragMoveEvent(event);
else else
{ {
setTextCursor (cursorForPosition (event->pos())); setTextCursor (cursorForPosition (event->pos()));
@ -72,7 +108,7 @@ void CSVWorld::ScriptEdit::dropEvent (QDropEvent* event)
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData()); 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 if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped
{ {
QTextEdit::dropEvent(event); QPlainTextEdit::dropEvent(event);
return; return;
} }
@ -103,3 +139,21 @@ bool CSVWorld::ScriptEdit::stringNeedsQuote (const std::string& id) const
//I'm not quite sure when do we need to put quotes. To be safe we will use quotes for anything other than… //I'm not quite sure when do we need to put quotes. To be safe we will use quotes for anything other than…
return !(string.contains(mWhiteListQoutes)); return !(string.contains(mWhiteListQoutes));
} }
void CSVWorld::ScriptEdit::idListChanged()
{
mHighlighter->invalidateIds();
if (!mUpdateTimer.isActive())
mUpdateTimer.start (0);
}
void CSVWorld::ScriptEdit::updateHighlighting()
{
if (isChangeLocked())
return;
ChangeLock lock (*this);
mHighlighter->rehighlight();
}

@ -1,11 +1,14 @@
#ifndef SCRIPTEDIT_H #ifndef SCRIPTEDIT_H
#define SCRIPTEDIT_H #define SCRIPTEDIT_H
#include <qtextedit.h> #include <QPlainTextEdit>
#include <QVector> #include <QVector>
#include <QTimer>
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "scripthighlighter.hpp"
class QWidget; class QWidget;
class QRegExp; class QRegExp;
@ -16,11 +19,42 @@ namespace CSMDoc
namespace CSVWorld namespace CSVWorld
{ {
class ScriptEdit : public QTextEdit class ScriptEdit : public QPlainTextEdit
{ {
Q_OBJECT Q_OBJECT
public: public:
ScriptEdit (QWidget* parent, const CSMDoc::Document& document);
class ChangeLock
{
ScriptEdit& mEdit;
ChangeLock (const ChangeLock&);
ChangeLock& operator= (const ChangeLock&);
public:
ChangeLock (ScriptEdit& edit);
~ChangeLock();
};
friend class ChangeLock;
private:
int mChangeLocked;
ScriptHighlighter *mHighlighter;
QTimer mUpdateTimer;
public:
ScriptEdit (const CSMDoc::Document& document, ScriptHighlighter::Mode mode,
QWidget* parent);
/// Should changes to the data be ignored (i.e. not cause updated)?
///
/// \note This mechanism is used to avoid infinite update recursions
bool isChangeLocked() const;
private: private:
QVector<CSMWorld::UniversalId::Type> mAllowedTypes; QVector<CSMWorld::UniversalId::Type> mAllowedTypes;
@ -34,6 +68,12 @@ namespace CSVWorld
void dragMoveEvent (QDragMoveEvent* event); void dragMoveEvent (QDragMoveEvent* event);
bool stringNeedsQuote(const std::string& id) const; bool stringNeedsQuote(const std::string& id) const;
private slots:
void idListChanged();
void updateHighlighting();
}; };
} }
#endif // SCRIPTEDIT_H #endif // SCRIPTEDIT_H

@ -30,6 +30,16 @@ bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Comp
bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc, bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc,
Compiler::Scanner& scanner) Compiler::Scanner& scanner)
{ {
if (((mMode==Mode_Console || mMode==Mode_Dialogue) &&
(keyword==Compiler::Scanner::K_begin || keyword==Compiler::Scanner::K_end ||
keyword==Compiler::Scanner::K_short || keyword==Compiler::Scanner::K_long ||
keyword==Compiler::Scanner::K_float))
|| (mMode==Mode_Console && (keyword==Compiler::Scanner::K_if ||
keyword==Compiler::Scanner::K_endif || keyword==Compiler::Scanner::K_else ||
keyword==Compiler::Scanner::K_elseif || keyword==Compiler::Scanner::K_while ||
keyword==Compiler::Scanner::K_endwhile)))
return parseName (loc.mLiteral, loc, scanner);
highlight (loc, Type_Keyword); highlight (loc, Type_Keyword);
return true; return true;
} }
@ -63,8 +73,10 @@ void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type
setFormat (index, length, mScheme[type]); setFormat (index, length, mScheme[type]);
} }
CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent) CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, Mode mode,
: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data) QTextDocument *parent)
: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data),
mMode (mode)
{ {
/// \todo replace this with user settings /// \todo replace this with user settings
{ {

@ -28,12 +28,20 @@ namespace CSVWorld
Type_Id Type_Id
}; };
enum Mode
{
Mode_General,
Mode_Console,
Mode_Dialogue
};
private: private:
Compiler::NullErrorHandler mErrorHandler; Compiler::NullErrorHandler mErrorHandler;
Compiler::Extensions mExtensions; Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext; CSMWorld::ScriptContext mContext;
std::map<Type, QTextCharFormat> mScheme; std::map<Type, QTextCharFormat> mScheme;
Mode mMode;
private: private:
@ -74,7 +82,7 @@ namespace CSVWorld
public: public:
ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent); ScriptHighlighter (const CSMWorld::Data& data, Mode mode, QTextDocument *parent);
virtual void highlightBlock (const QString& text); virtual void highlightBlock (const QString& text);

@ -3,8 +3,6 @@
#include <stdexcept> #include <stdexcept>
#include <QTextEdit>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
@ -12,28 +10,12 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "scripthighlighter.hpp"
#include "scriptedit.hpp" #include "scriptedit.hpp"
CSVWorld::ScriptSubView::ChangeLock::ChangeLock (ScriptSubView& view) : mView (view)
{
++mView.mChangeLocked;
}
CSVWorld::ScriptSubView::ChangeLock::~ChangeLock()
{
--mView.mChangeLocked;
}
CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document) CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document)
: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) : SubView (id), mDocument (document), mColumn (-1)
{ {
setWidget (mEditor = new ScriptEdit (this, mDocument)); setWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this));
mEditor->setAcceptRichText (false);
mEditor->setLineWrapMode (QTextEdit::NoWrap);
mEditor->setTabStopWidth (4);
mEditor->setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead
mModel = &dynamic_cast<CSMWorld::IdTable&> ( mModel = &dynamic_cast<CSMWorld::IdTable&> (
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts)); *document.getData().getTableModel (CSMWorld::UniversalId::Type_Scripts));
@ -58,14 +40,6 @@ CSVWorld::ScriptSubView::ScriptSubView (const CSMWorld::UniversalId& id, CSMDoc:
connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)), connect (mModel, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int))); this, SLOT (rowsAboutToBeRemoved (const QModelIndex&, int, int)));
connect (&document.getData(), SIGNAL (idListChanged()), this, SLOT (idListChanged()));
mHighlighter = new ScriptHighlighter (document.getData(), mEditor->document());
connect (&mUpdateTimer, SIGNAL (timeout()), this, SLOT (updateHighlighting()));
mUpdateTimer.setSingleShot (true);
} }
void CSVWorld::ScriptSubView::setEditLock (bool locked) void CSVWorld::ScriptSubView::setEditLock (bool locked)
@ -73,20 +47,12 @@ void CSVWorld::ScriptSubView::setEditLock (bool locked)
mEditor->setReadOnly (locked); mEditor->setReadOnly (locked);
} }
void CSVWorld::ScriptSubView::idListChanged()
{
mHighlighter->invalidateIds();
if (!mUpdateTimer.isActive())
mUpdateTimer.start (0);
}
void CSVWorld::ScriptSubView::textChanged() void CSVWorld::ScriptSubView::textChanged()
{ {
if (mChangeLocked) if (mEditor->isChangeLocked())
return; return;
ChangeLock lock (*this); ScriptEdit::ChangeLock lock (*mEditor);
mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel,
mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText())); mModel->getModelIndex (getUniversalId().getId(), mColumn), mEditor->toPlainText()));
@ -94,10 +60,10 @@ void CSVWorld::ScriptSubView::textChanged()
void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight) void CSVWorld::ScriptSubView::dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight)
{ {
if (mChangeLocked) if (mEditor->isChangeLocked())
return; return;
ChangeLock lock (*this); ScriptEdit::ChangeLock lock (*mEditor);
QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn);
@ -118,12 +84,3 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i
deleteLater(); deleteLater();
} }
void CSVWorld::ScriptSubView::updateHighlighting()
{
if (mChangeLocked)
return;
ChangeLock lock (*this);
mHighlighter->rehighlight();
}

@ -3,9 +3,6 @@
#include "../doc/subview.hpp" #include "../doc/subview.hpp"
#include <QTimer>
class QTextEdit;
class QModelIndex; class QModelIndex;
namespace CSMDoc namespace CSMDoc
@ -20,34 +17,16 @@ namespace CSMWorld
namespace CSVWorld namespace CSVWorld
{ {
class ScriptHighlighter; class ScriptEdit;
class ScriptSubView : public CSVDoc::SubView class ScriptSubView : public CSVDoc::SubView
{ {
Q_OBJECT Q_OBJECT
QTextEdit *mEditor; ScriptEdit *mEditor;
CSMDoc::Document& mDocument; CSMDoc::Document& mDocument;
CSMWorld::IdTable *mModel; CSMWorld::IdTable *mModel;
int mColumn; int mColumn;
int mChangeLocked;
ScriptHighlighter *mHighlighter;
QTimer mUpdateTimer;
class ChangeLock
{
ScriptSubView& mView;
ChangeLock (const ChangeLock&);
ChangeLock& operator= (const ChangeLock&);
public:
ChangeLock (ScriptSubView& view);
~ChangeLock();
};
friend class ChangeLock;
public: public:
@ -57,17 +36,11 @@ namespace CSVWorld
public slots: public slots:
void idListChanged();
void textChanged(); void textChanged();
void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
private slots:
void updateHighlighting();
}; };
} }

@ -3,8 +3,6 @@
#include "../doc/subviewfactoryimp.hpp" #include "../doc/subviewfactoryimp.hpp"
#include "../filter/filtercreator.hpp"
#include "tablesubview.hpp" #include "tablesubview.hpp"
#include "dialoguesubview.hpp" #include "dialoguesubview.hpp"
#include "scriptsubview.hpp" #include "scriptsubview.hpp"
@ -35,7 +33,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Factions,
CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Races,
CSMWorld::UniversalId::Type_Sounds, CSMWorld::UniversalId::Type_Sounds,
CSMWorld::UniversalId::Type_Scripts,
CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Regions,
CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Birthsigns,
CSMWorld::UniversalId::Type_Spells, CSMWorld::UniversalId::Type_Spells,
@ -91,11 +88,20 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
// Other stuff (combined record tables) // Other stuff (combined record tables)
manager.add (CSMWorld::UniversalId::Type_RegionMap, new CSVDoc::SubViewFactory<RegionMapSubView>); manager.add (CSMWorld::UniversalId::Type_RegionMap, new CSVDoc::SubViewFactory<RegionMapSubView>);
manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory<SceneSubView>);
// More other stuff
manager.add (CSMWorld::UniversalId::Type_Filters, manager.add (CSMWorld::UniversalId::Type_Filters,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, new CSVDoc::SubViewFactoryWithCreator<TableSubView,
CreatorFactory<CSVFilter::FilterCreator> >); CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> >);
manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory<SceneSubView>); manager.add (CSMWorld::UniversalId::Type_DebugProfiles,
new CSVDoc::SubViewFactoryWithCreator<TableSubView,
CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> >);
manager.add (CSMWorld::UniversalId::Type_Scripts,
new CSVDoc::SubViewFactoryWithCreator<TableSubView, CreatorFactory<GenericCreator,
CSMWorld::Scope_Project | CSMWorld::Scope_Content> >);
// Dialogue subviews // Dialogue subviews
static const CSMWorld::UniversalId::Type sTableTypes2[] = static const CSMWorld::UniversalId::Type sTableTypes2[] =
@ -106,7 +112,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_Global, CSMWorld::UniversalId::Type_Global,
CSMWorld::UniversalId::Type_Race, CSMWorld::UniversalId::Type_Race,
CSMWorld::UniversalId::Type_Class, CSMWorld::UniversalId::Type_Class,
CSMWorld::UniversalId::Type_Filter,
CSMWorld::UniversalId::Type_Sound, CSMWorld::UniversalId::Type_Sound,
CSMWorld::UniversalId::Type_Faction, CSMWorld::UniversalId::Type_Faction,
CSMWorld::UniversalId::Type_Enchantment, CSMWorld::UniversalId::Type_Enchantment,
@ -147,6 +152,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
manager.add (CSMWorld::UniversalId::Type_Journal, manager.add (CSMWorld::UniversalId::Type_Journal,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, JournalCreatorFactory> (false)); new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, JournalCreatorFactory> (false));
manager.add (CSMWorld::UniversalId::Type_DebugProfile,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
manager.add (CSMWorld::UniversalId::Type_Filter,
new CSVDoc::SubViewFactoryWithCreator<DialogueSubView, CreatorFactory<GenericCreator, CSMWorld::Scope_Project | CSMWorld::Scope_Session> > (false));
//preview //preview
manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>); manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory<PreviewSubView>);
} }

@ -179,7 +179,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id,
mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt());
CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display,
mDocument.getUndoStack(), this); mDocument, this);
mDelegates.push_back (delegate); mDelegates.push_back (delegate);
setItemDelegateForColumn (i, delegate); setItemDelegateForColumn (i, delegate);

@ -17,6 +17,8 @@
#include "../../model/world/commands.hpp" #include "../../model/world/commands.hpp"
#include "../../model/world/tablemimedata.hpp" #include "../../model/world/tablemimedata.hpp"
#include "scriptedit.hpp"
CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model)
: mModel (model) : mModel (model)
{} {}
@ -78,15 +80,15 @@ void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Disp
} }
CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate ( CSVWorld::CommandDelegate *CSVWorld::CommandDelegateFactoryCollection::makeDelegate (
CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, QObject *parent) const CSMWorld::ColumnBase::Display display, CSMDoc::Document& document, QObject *parent) const
{ {
std::map<CSMWorld::ColumnBase::Display, CommandDelegateFactory *>::const_iterator iter = std::map<CSMWorld::ColumnBase::Display, CommandDelegateFactory *>::const_iterator iter =
mFactories.find (display); mFactories.find (display);
if (iter!=mFactories.end()) if (iter!=mFactories.end())
return iter->second->makeDelegate (undoStack, parent); return iter->second->makeDelegate (document, parent);
return new CommandDelegate (undoStack, parent); return new CommandDelegate (document, parent);
} }
const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get() const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFactoryCollection::get()
@ -100,7 +102,12 @@ const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFacto
QUndoStack& CSVWorld::CommandDelegate::getUndoStack() const QUndoStack& CSVWorld::CommandDelegate::getUndoStack() const
{ {
return mUndoStack; return mDocument.getUndoStack();
}
CSMDoc::Document& CSVWorld::CommandDelegate::getDocument() const
{
return mDocument;
} }
void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model, void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemModel *model,
@ -112,11 +119,11 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM
QVariant new_ = hack.getData(); QVariant new_ = hack.getData();
if (model->data (index)!=new_) if (model->data (index)!=new_)
mUndoStack.push (new CSMWorld::ModifyCommand (*model, index, new_)); getUndoStack().push (new CSMWorld::ModifyCommand (*model, index, new_));
} }
CSVWorld::CommandDelegate::CommandDelegate (QUndoStack& undoStack, QObject *parent) CSVWorld::CommandDelegate::CommandDelegate (CSMDoc::Document& document, QObject *parent)
: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) : QStyledItemDelegate (parent), mDocument (document), mEditLock (false)
{} {}
void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model,
@ -162,8 +169,11 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
return new QDoubleSpinBox(parent); return new QDoubleSpinBox(parent);
case CSMWorld::ColumnBase::Display_LongString: case CSMWorld::ColumnBase::Display_LongString:
{
return new QTextEdit(parent); QPlainTextEdit *edit = new QPlainTextEdit(parent);
edit->setUndoRedoEnabled (false);
return edit;
}
case CSMWorld::ColumnBase::Display_Boolean: case CSMWorld::ColumnBase::Display_Boolean:
@ -188,6 +198,10 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO
return new DropLineEdit(parent); return new DropLineEdit(parent);
case CSMWorld::ColumnBase::Display_ScriptLines:
return new ScriptEdit (mDocument, ScriptHighlighter::Mode_Console, parent);
default: default:
return QStyledItemDelegate::createEditor (parent, option, index); return QStyledItemDelegate::createEditor (parent, option, index);

@ -51,7 +51,8 @@ namespace CSVWorld
virtual ~CommandDelegateFactory(); virtual ~CommandDelegateFactory();
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const = 0; virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent)
const = 0;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
}; };
@ -77,7 +78,7 @@ namespace CSVWorld
/// ///
/// This function must not be called more than once per value of \a display. /// This function must not be called more than once per value of \a display.
CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, QUndoStack& undoStack, CommandDelegate *makeDelegate (CSMWorld::ColumnBase::Display display, CSMDoc::Document& document,
QObject *parent) const; QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
/// ///
@ -110,19 +111,21 @@ namespace CSVWorld
{ {
Q_OBJECT Q_OBJECT
QUndoStack& mUndoStack; CSMDoc::Document& mDocument;
bool mEditLock; bool mEditLock;
protected: protected:
QUndoStack& getUndoStack() const; QUndoStack& getUndoStack() const;
CSMDoc::Document& getDocument() const;
virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const; const QModelIndex& index) const;
public: public:
CommandDelegate (QUndoStack& undoStack, QObject *parent); CommandDelegate (CSMDoc::Document& document, QObject *parent);
virtual void setModelData (QWidget *editor, QAbstractItemModel *model, virtual void setModelData (QWidget *editor, QAbstractItemModel *model,
const QModelIndex& index) const; const QModelIndex& index) const;

@ -47,8 +47,8 @@ void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QM
} }
CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector<std::pair<int, QString> >& values, CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
QUndoStack& undoStack, QObject *parent) CSMDoc::Document& document, QObject *parent)
: EnumDelegate (values, undoStack, parent) : EnumDelegate (values, document, parent)
{} {}
@ -68,10 +68,10 @@ CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0,
add (type3); add (type3);
} }
CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (
QObject *parent) const CSMDoc::Document& document, QObject *parent) const
{ {
return new VarTypeDelegate (mValues, undoStack, parent); return new VarTypeDelegate (mValues, document, parent);
} }
void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type) void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)

@ -17,7 +17,7 @@ namespace CSVWorld
public: public:
VarTypeDelegate (const std::vector<std::pair<int, QString> >& values, VarTypeDelegate (const std::vector<std::pair<int, QString> >& values,
QUndoStack& undoStack, QObject *parent); CSMDoc::Document& document, QObject *parent);
}; };
class VarTypeDelegateFactory : public CommandDelegateFactory class VarTypeDelegateFactory : public CommandDelegateFactory
@ -30,7 +30,7 @@ namespace CSVWorld
ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown, ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = ESM::VT_Unknown,
ESM::VarType type3 = ESM::VT_Unknown); ESM::VarType type3 = ESM::VT_Unknown);
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const; virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller. ///< The ownership of the returned CommandDelegate is transferred to the caller.
void add (ESM::VarType type); void add (ESM::VarType type);

@ -64,7 +64,7 @@ add_openmw_dir (mwworld
cells localscripts customdata weather inventorystore ptr actionopen actionread cells localscripts customdata weather inventorystore ptr actionopen actionread
actionequip timestamp actionalchemy cellstore actionapply actioneat actionequip timestamp actionalchemy cellstore actionapply actioneat
esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor esmstore store recordcmp fallback actionrepair actionsoulgem livecellref actiondoor
contentloader esmloader omwloader actiontrap cellreflist projectilemanager cellref contentloader esmloader actiontrap cellreflist projectilemanager cellref
) )
add_openmw_dir (mwclass add_openmw_dir (mwclass
@ -109,7 +109,7 @@ if (NOT ANDROID)
${APPLE_BUNDLE_RESOURCES} ${APPLE_BUNDLE_RESOURCES}
) )
else () else ()
add_library(openmw add_library(openmw
SHARED SHARED
${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER}
${OPENMW_FILES} ${OPENMW_FILES}
@ -139,18 +139,18 @@ target_link_libraries(openmw
if (ANDROID) if (ANDROID)
target_link_libraries(openmw target_link_libraries(openmw
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
EGL EGL
android android
log log
dl dl
MyGUI.OgrePlatform MyGUI.OgrePlatform
MyGUIEngineStatic MyGUIEngineStatic
Plugin_StrangeButtonStatic Plugin_StrangeButtonStatic
cpufeatures cpufeatures
BulletCollision BulletCollision
BulletDynamics BulletDynamics
LinearMath LinearMath
) )
endif (ANDROID) endif (ANDROID)

@ -186,6 +186,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager)
, mGrab(true) , mGrab(true)
, mScriptBlacklistUse (true) , mScriptBlacklistUse (true)
, mExportFonts(false) , mExportFonts(false)
, mNewGame (false)
{ {
std::srand ( std::time(NULL) ); std::srand ( std::time(NULL) );
MWClass::registerClasses(); MWClass::registerClasses();
@ -268,9 +269,10 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity)
mVerboseScripts = scriptsVerbosity; mVerboseScripts = scriptsVerbosity;
} }
void OMW::Engine::setSkipMenu (bool skipMenu) void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame)
{ {
mSkipMenu = skipMenu; mSkipMenu = skipMenu;
mNewGame = newGame;
} }
std::string OMW::Engine::loadSettings (Settings::Manager & settings) std::string OMW::Engine::loadSettings (Settings::Manager & settings)
@ -474,7 +476,7 @@ void OMW::Engine::go()
} }
else else
{ {
MWBase::Environment::get().getStateManager()->newGame (true); MWBase::Environment::get().getStateManager()->newGame (!mNewGame);
} }
// Start the main rendering loop // Start the main rendering loop

@ -95,6 +95,7 @@ namespace OMW
Translation::Storage mTranslationDataStorage; Translation::Storage mTranslationDataStorage;
std::vector<std::string> mScriptBlacklist; std::vector<std::string> mScriptBlacklist;
bool mScriptBlacklistUse; bool mScriptBlacklistUse;
bool mNewGame;
Nif::Cache mNifCache; Nif::Cache mNifCache;
@ -157,7 +158,11 @@ namespace OMW
/// Disable or enable all sounds /// Disable or enable all sounds
void setSoundUsage(bool soundUsage); void setSoundUsage(bool soundUsage);
void setSkipMenu (bool skipMenu); /// Skip main menu and go directly into the game
///
/// \param newGame Start a new game instead off dumping the player into the game
/// (ignored if !skipMenu).
void setSkipMenu (bool skipMenu, bool newGame);
void setGrabMouse(bool grab) { mGrab = grab; } void setGrabMouse(bool grab) { mGrab = grab; }

@ -105,7 +105,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("help", "print help message") ("help", "print help message")
("version", "print version information and quit") ("version", "print version information and quit")
("data", bpo::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data") ("data", bpo::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")
->multitoken(), "set data directories (later directories have higher priority)") ->multitoken()->composing(), "set data directories (later directories have higher priority)")
("data-local", bpo::value<std::string>()->default_value(""), ("data-local", bpo::value<std::string>()->default_value(""),
"set local data directory (highest priority)") "set local data directory (highest priority)")
@ -153,6 +153,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
("skip-menu", bpo::value<bool>()->implicit_value(true) ("skip-menu", bpo::value<bool>()->implicit_value(true)
->default_value(false), "skip main menu on game startup") ->default_value(false), "skip main menu on game startup")
("new-game", bpo::value<bool>()->implicit_value(true)
->default_value(false), "run new game sequence (ignored if skip-menu=0)")
("fs-strict", bpo::value<bool>()->implicit_value(true) ("fs-strict", bpo::value<bool>()->implicit_value(true)
->default_value(false), "strict file system handling (no case folding)") ->default_value(false), "strict file system handling (no case folding)")
@ -256,7 +259,9 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat
// startup-settings // startup-settings
engine.setCell(variables["start"].as<std::string>()); engine.setCell(variables["start"].as<std::string>());
engine.setSkipMenu (variables["skip-menu"].as<bool>()); engine.setSkipMenu (variables["skip-menu"].as<bool>(), variables["new-game"].as<bool>());
if (!variables["skip-menu"].as<bool>() && variables["new-game"].as<bool>())
std::cerr << "new-game used without skip-menu -> ignoring it" << std::endl;
// scripts // scripts
engine.setCompileAll(variables["script-all"].as<bool>()); engine.setCompileAll(variables["script-all"].as<bool>());

@ -81,7 +81,13 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener)
mMagicEffects.load (esm); mMagicEffects.load (esm);
} else if (n.val == ESM::REC_SKIL) { } else if (n.val == ESM::REC_SKIL) {
mSkills.load (esm); mSkills.load (esm);
} else { }
else if (n.val==ESM::REC_FILT || ESM::REC_DBGP)
{
// ignore project file only records
esm.skipRecord();
}
else {
std::stringstream error; std::stringstream error;
error << "Unknown record: " << n.toString(); error << "Unknown record: " << n.toString();
throw std::runtime_error(error.str()); throw std::runtime_error(error.str());

@ -1,17 +0,0 @@
#include "omwloader.hpp"
namespace MWWorld
{
OmwLoader::OmwLoader(Loading::Listener& listener)
: ContentLoader(listener)
{
}
void OmwLoader::load(const boost::filesystem::path& filepath, int& index)
{
ContentLoader::load(filepath.filename(), index);
}
} /* namespace MWWorld */

@ -1,21 +0,0 @@
#ifndef OMWLOADER_HPP
#define OMWLOADER_HPP
#include "contentloader.hpp"
namespace MWWorld
{
/**
* @brief Placeholder for real OpenMW content loader
*/
struct OmwLoader : public ContentLoader
{
OmwLoader(Loading::Listener& listener);
void load(const boost::filesystem::path& filepath, int& index);
};
} /* namespace MWWorld */
#endif /* OMWLOADER_HPP */

@ -51,7 +51,6 @@
#include "contentloader.hpp" #include "contentloader.hpp"
#include "esmloader.hpp" #include "esmloader.hpp"
#include "omwloader.hpp"
using namespace Ogre; using namespace Ogre;
@ -170,12 +169,12 @@ namespace MWWorld
GameContentLoader gameContentLoader(*listener); GameContentLoader gameContentLoader(*listener);
EsmLoader esmLoader(mStore, mEsm, encoder, *listener); EsmLoader esmLoader(mStore, mEsm, encoder, *listener);
OmwLoader omwLoader(*listener);
gameContentLoader.addLoader(".esm", &esmLoader); gameContentLoader.addLoader(".esm", &esmLoader);
gameContentLoader.addLoader(".esp", &esmLoader); gameContentLoader.addLoader(".esp", &esmLoader);
gameContentLoader.addLoader(".omwgame", &omwLoader); gameContentLoader.addLoader(".omwgame", &esmLoader);
gameContentLoader.addLoader(".omwaddon", &omwLoader); gameContentLoader.addLoader(".omwaddon", &esmLoader);
gameContentLoader.addLoader(".project", &esmLoader);
loadContentFiles(fileCollections, contentFiles, gameContentLoader); loadContentFiles(fileCollections, contentFiles, gameContentLoader);

@ -45,7 +45,7 @@ add_component_dir (esm
loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat
loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter loadweap records aipackage effectlist spelllist variant variantimp loadtes3 cellref filter
savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate savedgame journalentry queststate locals globalscript player objectstate cellid cellstate globalmap lightstate inventorystate containerstate npcstate creaturestate dialoguestate statstate
npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile
aisequence magiceffects aisequence magiceffects
) )

@ -0,0 +1,29 @@
#include "debugprofile.hpp"
#include "esmreader.hpp"
#include "esmwriter.hpp"
#include "defs.hpp"
unsigned int ESM::DebugProfile::sRecordId = REC_DBGP;
void ESM::DebugProfile::load (ESMReader& esm)
{
mDescription = esm.getHNString ("DESC");
mScriptText = esm.getHNString ("SCRP");
esm.getHNT (mFlags, "FLAG");
}
void ESM::DebugProfile::save (ESMWriter& esm) const
{
esm.writeHNCString ("DESC", mDescription);
esm.writeHNCString ("SCRP", mScriptText);
esm.writeHNT ("FLAG", mFlags);
}
void ESM::DebugProfile::blank()
{
mDescription.clear();
mScriptText.clear();
mFlags = 0;
}

@ -0,0 +1,38 @@
#ifndef COMPONENTS_ESM_DEBUGPROFILE_H
#define COMPONENTS_ESM_DEBUGPROFILE_H
#include <string>
namespace ESM
{
class ESMReader;
class ESMWriter;
struct DebugProfile
{
static unsigned int sRecordId;
enum Flags
{
Flag_Default = 1, // add to newly opened scene subviews
Flag_BypassNewGame = 2, // bypass regular game startup
Flag_Global = 4 // make available from main menu (i.e. not location specific)
};
std::string mId;
std::string mDescription;
std::string mScriptText;
unsigned int mFlags;
void load (ESMReader& esm);
void save (ESMWriter& esm) const;
/// Set record to default state (does not touch the ID).
void blank();
};
}
#endif

@ -115,7 +115,8 @@ enum RecNameInts
REC_MARK = FourCC<'M','A','R','K'>::value, REC_MARK = FourCC<'M','A','R','K'>::value,
// format 1 // format 1
REC_FILT = 0x544C4946 REC_FILT = 0x544C4946,
REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files
}; };
} }

@ -124,7 +124,11 @@ void Script::save(ESMWriter &esm) const
mVarNames.clear(); mVarNames.clear();
mScriptData.clear(); mScriptData.clear();
mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n";
if (mId.find ("::")!=std::string::npos)
mScriptText = "Begin \"" + mId + "\"\n\nEnd " + mId + "\n";
else
mScriptText = "Begin " + mId + "\n\nEnd " + mId + "\n";
} }
} }

@ -73,6 +73,8 @@ Allowed options:
correctly compiled anyway correctly compiled anyway
2 - treat warnings as errors 2 - treat warnings as errors
--skip-menu [=arg(=1)] (=0) skip main menu on game startup --skip-menu [=arg(=1)] (=0) skip main menu on game startup
--new-game [=arg(=1)] (=0) run new game sequence (ignored if
skip-menu=0)
--fs-strict [=arg(=1)] (=0) strict file system handling (no case --fs-strict [=arg(=1)] (=0) strict file system handling (no case
folding) folding)
--encoding arg (=win1252) Character encoding used in OpenMW game --encoding arg (=win1252) Character encoding used in OpenMW game

Loading…
Cancel
Save