diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index 8afcc9795..7094f8799 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -7,7 +7,7 @@ opencs_units (. editor) set (CMAKE_BUILD_TYPE DEBUG) opencs_units (model/doc - document operation saving documentmanager loader + document operation saving documentmanager loader runner ) opencs_units_noqt (model/doc @@ -26,7 +26,7 @@ opencs_units (model/world opencs_units_noqt (model/world universalid record commands columnbase scriptcontext cell refidcollection - refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager + refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope ) opencs_hdrs_noqt (model/world @@ -46,7 +46,7 @@ opencs_units_noqt (model/tools opencs_units (view/doc 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 - scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle + scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun ) opencs_units (view/render @@ -128,12 +128,8 @@ opencs_units_noqt (model/filter node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode ) -opencs_hdrs_noqt (model/filter - filter - ) - opencs_units (view/filter - filtercreator filterbox recordfilterbox editwidget + filterbox recordfilterbox editwidget ) set (OPENCS_US diff --git a/apps/opencs/editor.cpp b/apps/opencs/editor.cpp index 44d66b236..e8e2d9077 100644 --- a/apps/opencs/editor.cpp +++ b/apps/opencs/editor.cpp @@ -80,7 +80,7 @@ std::pair > CS::Editor::readConfi boost::program_options::options_description desc("Syntax: opencs \nAllowed options"); desc.add_options() - ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()) + ("data", boost::program_options::value()->default_value(Files::PathContainer(), "data")->multitoken()->composing()) ("data-local", boost::program_options::value()->default_value("")) ("fs-strict", boost::program_options::value()->implicit_value(true)->default_value(false)) ("encoding", boost::program_options::value()->default_value("win1252")) diff --git a/apps/opencs/model/doc/document.cpp b/apps/opencs/model/doc/document.cpp index 29c728333..9a174d9d5 100644 --- a/apps/opencs/model/doc/document.cpp +++ b/apps/opencs/model/doc/document.cpp @@ -2212,7 +2212,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, mTools (*this), mResDir(resDir), mProjectPath ((configuration.getUserDataPath() / "projects") / (savePath.filename().string() + ".project")), - mSaving (*this, mProjectPath, encoding) + mSaving (*this, mProjectPath, encoding), + mRunner (mProjectPath) { if (mContentFiles.empty()) 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 (&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 (done (int)), this, SLOT (operationDone (int))); + connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); connect ( &mSaving, SIGNAL (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() @@ -2280,6 +2283,9 @@ int CSMDoc::Document::getState() const if (mSaving.isRunning()) state |= State_Locked | State_Saving | State_Operation; + if (mRunner.isRunning()) + state |= State_Locked | State_Running; + if (int operations = mTools.getRunningOperations()) 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; } -void CSMDoc::Document::operationDone (int type) +void CSMDoc::Document::operationDone (int type, bool failed) { emit stateChanged (getState(), this); } @@ -2370,6 +2376,48 @@ bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id) return mBlacklist.isBlacklisted (id); } +void CSMDoc::Document::startRunning (const std::string& profile, + const std::string& startupInstruction) +{ + std::vector contentFiles; + + for (std::vector::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) { diff --git a/apps/opencs/model/doc/document.hpp b/apps/opencs/model/doc/document.hpp index d0e94d5e0..29235e6e4 100644 --- a/apps/opencs/model/doc/document.hpp +++ b/apps/opencs/model/doc/document.hpp @@ -18,6 +18,7 @@ #include "state.hpp" #include "saving.hpp" #include "blacklist.hpp" +#include "runner.hpp" class QAbstractItemModel; @@ -54,6 +55,7 @@ namespace CSMDoc Saving mSaving; boost::filesystem::path mResDir; 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 // 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; + void startRunning (const std::string& profile, + const std::string& startupInstruction = ""); + + void stopRunning(); + + QTextDocument *getRunLog(); + signals: void stateChanged (int state, CSMDoc::Document *document); @@ -128,7 +137,9 @@ namespace CSMDoc void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, int type); - void operationDone (int type); + void operationDone (int type, bool failed); + + void runStateChanged(); public slots: diff --git a/apps/opencs/model/doc/operation.cpp b/apps/opencs/model/doc/operation.cpp index 42a432043..533ee20a9 100644 --- a/apps/opencs/model/doc/operation.cpp +++ b/apps/opencs/model/doc/operation.cpp @@ -119,5 +119,5 @@ void CSMDoc::Operation::executeStage() void CSMDoc::Operation::operationDone() { - emit done (mType); + emit done (mType, mError); } \ No newline at end of file diff --git a/apps/opencs/model/doc/operation.hpp b/apps/opencs/model/doc/operation.hpp index 651283880..d5a7d4e09 100644 --- a/apps/opencs/model/doc/operation.hpp +++ b/apps/opencs/model/doc/operation.hpp @@ -54,7 +54,7 @@ namespace CSMDoc void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, int type); - void done (int type); + void done (int type, bool failed); public slots: diff --git a/apps/opencs/model/doc/runner.cpp b/apps/opencs/model/doc/runner.cpp new file mode 100644 index 000000000..d473a7e7a --- /dev/null +++ b/apps/opencs/model/doc/runner.cpp @@ -0,0 +1,157 @@ + +#include "runner.hpp" + +#include +#include + +#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::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& 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(); +} diff --git a/apps/opencs/model/doc/runner.hpp b/apps/opencs/model/doc/runner.hpp new file mode 100644 index 000000000..38b52a73b --- /dev/null +++ b/apps/opencs/model/doc/runner.hpp @@ -0,0 +1,85 @@ +#ifndef CSM_DOC_RUNNER_H +#define CSM_DOC_RUNNER_H + +#include +#include + +#include + +#include +#include +#include + +#include + +class QTemporaryFile; + +namespace CSMDoc +{ + class Runner : public QObject + { + Q_OBJECT + + QProcess mProcess; + bool mRunning; + ESM::DebugProfile mProfile; + std::vector 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& 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 diff --git a/apps/opencs/model/doc/saving.cpp b/apps/opencs/model/doc/saving.cpp index 95631eea9..9c6932941 100644 --- a/apps/opencs/model/doc/saving.cpp +++ b/apps/opencs/model/doc/saving.cpp @@ -17,7 +17,14 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje appendStage (new WriteHeaderStage (mDocument, mState, true)); - appendStage (new WriteFilterStage (mDocument, mState, CSMFilter::Filter::Scope_Project)); + appendStage (new WriteCollectionStage > ( + mDocument.getData().getFilters(), mState, CSMWorld::Scope_Project)); + + appendStage (new WriteCollectionStage > ( + mDocument.getData().getDebugProfiles(), mState, CSMWorld::Scope_Project)); + + appendStage (new WriteCollectionStage > ( + mDocument.getData().getScripts(), mState, CSMWorld::Scope_Project)); appendStage (new CloseSaveStage (mState)); diff --git a/apps/opencs/model/doc/savingstages.cpp b/apps/opencs/model/doc/savingstages.cpp index d36c2fb86..17c2b4dca 100644 --- a/apps/opencs/model/doc/savingstages.cpp +++ b/apps/opencs/model/doc/savingstages.cpp @@ -201,23 +201,6 @@ void CSMDoc::WriteRefIdCollectionStage::perform (int stage, Messages& messages) } -CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& state, - CSMFilter::Filter::Scope scope) -: WriteCollectionStage > (document.getData().getFilters(), - state), - mDocument (document), mScope (scope) -{} - -void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages) -{ - const CSMWorld::Record& record = - mDocument.getData().getFilters().getRecord (stage); - - if (record.get().mScope==mScope) - WriteCollectionStage >::perform (stage, messages); -} - - CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document, SavingState& state) : mDocument (document), mState (state) diff --git a/apps/opencs/model/doc/savingstages.hpp b/apps/opencs/model/doc/savingstages.hpp index dcb1a8650..d766b774e 100644 --- a/apps/opencs/model/doc/savingstages.hpp +++ b/apps/opencs/model/doc/savingstages.hpp @@ -5,8 +5,7 @@ #include "../world/record.hpp" #include "../world/idcollection.hpp" - -#include "../filter/filter.hpp" +#include "../world/scope.hpp" #include "savingstate.hpp" @@ -67,10 +66,12 @@ namespace CSMDoc { const CollectionT& mCollection; SavingState& mState; + CSMWorld::Scope mScope; public: - WriteCollectionStage (const CollectionT& collection, SavingState& state); + WriteCollectionStage (const CollectionT& collection, SavingState& state, + CSMWorld::Scope scope = CSMWorld::Scope_Content); virtual int setup(); ///< \return number of steps @@ -81,8 +82,8 @@ namespace CSMDoc template WriteCollectionStage::WriteCollectionStage (const CollectionT& collection, - SavingState& state) - : mCollection (collection), mState (state) + SavingState& state, CSMWorld::Scope scope) + : mCollection (collection), mState (state), mScope (scope) {} template @@ -94,6 +95,9 @@ namespace CSMDoc template void WriteCollectionStage::perform (int stage, Messages& messages) { + if (CSMWorld::getScopeFromId (mCollection.getRecord (stage).get().mId)!=mScope) + return; + CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; if (state==CSMWorld::RecordBase::State_Modified || @@ -152,20 +156,6 @@ namespace CSMDoc }; - class WriteFilterStage : public WriteCollectionStage > - { - 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 { Document& mDocument; diff --git a/apps/opencs/model/doc/state.hpp b/apps/opencs/model/doc/state.hpp index 6e1a1c4f4..287439a8b 100644 --- a/apps/opencs/model/doc/state.hpp +++ b/apps/opencs/model/doc/state.hpp @@ -8,12 +8,13 @@ namespace CSMDoc State_Modified = 1, State_Locked = 2, State_Operation = 4, + State_Running = 8, - State_Saving = 8, - State_Verifying = 16, - State_Compiling = 32, // not implemented yet - State_Searching = 64, // not implemented yet - State_Loading = 128 // pseudo-state; can not be encountered in a loaded document + State_Saving = 16, + State_Verifying = 32, + State_Compiling = 64, // not implemented yet + State_Searching = 128, // not implemented yet + State_Loading = 256 // pseudo-state; can not be encountered in a loaded document }; } diff --git a/apps/opencs/model/filter/filter.hpp b/apps/opencs/model/filter/filter.hpp deleted file mode 100644 index 62170ca80..000000000 --- a/apps/opencs/model/filter/filter.hpp +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CSM_FILTER_FILTER_H -#define CSM_FILTER_FILTER_H - -#include -#include - -#include - -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 \ No newline at end of file diff --git a/apps/opencs/model/filter/parser.cpp b/apps/opencs/model/filter/parser.cpp index bec445cbc..51338dfc9 100644 --- a/apps/opencs/model/filter/parser.cpp +++ b/apps/opencs/model/filter/parser.cpp @@ -596,7 +596,7 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined) return false; } - const CSMWorld::Record& record = mData.getFilters().getRecord (index); + const CSMWorld::Record& record = mData.getFilters().getRecord (index); if (record.isDeleted()) { diff --git a/apps/opencs/model/tools/tools.cpp b/apps/opencs/model/tools/tools.cpp index 0f73acd16..79b0b18b0 100644 --- a/apps/opencs/model/tools/tools.cpp +++ b/apps/opencs/model/tools/tools.cpp @@ -46,7 +46,7 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false); connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); - connect (mVerifier, SIGNAL (done (int)), this, SIGNAL (done (int))); + connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (mVerifier, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int))); diff --git a/apps/opencs/model/tools/tools.hpp b/apps/opencs/model/tools/tools.hpp index 4d677142d..7ca30e6b9 100644 --- a/apps/opencs/model/tools/tools.hpp +++ b/apps/opencs/model/tools/tools.hpp @@ -70,7 +70,7 @@ namespace CSMTools void progress (int current, int max, int type); - void done (int type); + void done (int type, bool failed); }; } diff --git a/apps/opencs/model/world/columnbase.hpp b/apps/opencs/model/world/columnbase.hpp index 6a0ee68d6..45cb47ba0 100644 --- a/apps/opencs/model/world/columnbase.hpp +++ b/apps/opencs/model/world/columnbase.hpp @@ -100,7 +100,8 @@ namespace CSMWorld Display_SoundRes, Display_Texture, Display_Video, - Display_Colour + Display_Colour, + Display_ScriptLines // console context }; int mColumnId; diff --git a/apps/opencs/model/world/columnimp.hpp b/apps/opencs/model/world/columnimp.hpp index a8ee52fdc..73dfc9ac0 100644 --- a/apps/opencs/model/world/columnimp.hpp +++ b/apps/opencs/model/world/columnimp.hpp @@ -500,6 +500,47 @@ namespace CSMWorld } }; + template + struct FlagColumn2 : public Column + { + int mMask; + bool mInverted; + + FlagColumn2 (int columnId, int mask, bool inverted = false) + : Column (columnId, ColumnBase::Display_Boolean), mMask (mask), + mInverted (inverted) + {} + + virtual QVariant get (const Record& record) const + { + bool flag = (record.get().mFlags & mMask)!=0; + + if (mInverted) + flag = !flag; + + return flag; + } + + virtual void set (Record& 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 struct WeightHeightColumn : public Column { @@ -766,8 +807,18 @@ namespace CSMWorld template struct ScriptColumn : public Column { - ScriptColumn() - : Column (Columns::ColumnId_ScriptText, ColumnBase::Display_Script, 0) {} + enum Type + { + Type_File, // regular script record + Type_Lines, // console context + Type_Info // dialogue context (not implemented yet) + }; + + ScriptColumn (Type type) + : Column (Columns::ColumnId_ScriptText, + type==Type_File ? ColumnBase::Display_Script : ColumnBase::Display_ScriptLines, + type==Type_File ? 0 : ColumnBase::Flag_Dialogue) + {} virtual QVariant get (const Record& record) const { @@ -1224,36 +1275,6 @@ namespace CSMWorld } }; - template - struct ScopeColumn : public Column - { - ScopeColumn() - : Column (Columns::ColumnId_Scope, ColumnBase::Display_Integer, 0) - {} - - virtual QVariant get (const Record& record) const - { - return static_cast (record.get().mScope); - } - - virtual void set (Record& record, const QVariant& data) - { - ESXRecordT record2 = record.get(); - record2.mScope = static_cast (data.toInt()); - record.setModified (record2); - } - - virtual bool isEditable() const - { - return true; - } - - virtual bool isUserEditable() const - { - return false; - } - }; - template struct PosColumn : public Column diff --git a/apps/opencs/model/world/columns.cpp b/apps/opencs/model/world/columns.cpp index d809f69b9..7d789e2f7 100644 --- a/apps/opencs/model/world/columns.cpp +++ b/apps/opencs/model/world/columns.cpp @@ -172,7 +172,6 @@ namespace CSMWorld { ColumnId_Rank, "Rank" }, { ColumnId_Gender, "Gender" }, { ColumnId_PcRank, "PC Rank" }, - { ColumnId_Scope, "Scope" }, { ColumnId_ReferenceableId, "Referenceable ID" }, { ColumnId_CombatState, "Combat" }, { ColumnId_MagicState, "Magic" }, @@ -182,6 +181,9 @@ namespace CSMWorld { ColumnId_BodyPartType, "Bodypart Type" }, { ColumnId_MeshType, "Mesh Type" }, { ColumnId_OwnerGlobal, "Owner Global" }, + { ColumnId_DefaultProfile, "Default Profile" }, + { ColumnId_BypassNewGame, "Bypass New Game" }, + { ColumnId_GlobalProfile, "Global Profile" }, { ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue2, "Use value 2" }, diff --git a/apps/opencs/model/world/columns.hpp b/apps/opencs/model/world/columns.hpp index 08ed66377..a1ddaabec 100644 --- a/apps/opencs/model/world/columns.hpp +++ b/apps/opencs/model/world/columns.hpp @@ -165,7 +165,6 @@ namespace CSMWorld ColumnId_Rank = 152, ColumnId_Gender = 153, ColumnId_PcRank = 154, - ColumnId_Scope = 155, ColumnId_ReferenceableId = 156, ColumnId_CombatState = 157, ColumnId_MagicState = 158, @@ -175,6 +174,9 @@ namespace CSMWorld ColumnId_BodyPartType = 162, ColumnId_MeshType = 163, 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 // to extend the number of use values. diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 8045d77f6..ec69b46bb 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -131,7 +131,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mScripts.addColumn (new StringIdColumn); mScripts.addColumn (new RecordStateColumn); mScripts.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Script)); - mScripts.addColumn (new ScriptColumn); + mScripts.addColumn (new ScriptColumn (ScriptColumn::Type_File)); mRegions.addColumn (new StringIdColumn); mRegions.addColumn (new RecordStateColumn); @@ -252,12 +252,24 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc mRefs.addColumn (new TrapColumn); mRefs.addColumn (new OwnerGlobalColumn); - mFilters.addColumn (new StringIdColumn); - mFilters.addColumn (new RecordStateColumn); - mFilters.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Filter)); - mFilters.addColumn (new FilterColumn); - mFilters.addColumn (new DescriptionColumn); - mFilters.addColumn (new ScopeColumn); + mFilters.addColumn (new StringIdColumn); + mFilters.addColumn (new RecordStateColumn); + mFilters.addColumn (new FixedRecordTypeColumn (UniversalId::Type_Filter)); + mFilters.addColumn (new FilterColumn); + mFilters.addColumn (new DescriptionColumn); + + mDebugProfiles.addColumn (new StringIdColumn); + mDebugProfiles.addColumn (new RecordStateColumn); + mDebugProfiles.addColumn (new FixedRecordTypeColumn (UniversalId::Type_DebugProfile)); + mDebugProfiles.addColumn (new FlagColumn2 ( + Columns::ColumnId_DefaultProfile, ESM::DebugProfile::Flag_Default)); + mDebugProfiles.addColumn (new FlagColumn2 ( + Columns::ColumnId_BypassNewGame, ESM::DebugProfile::Flag_BypassNewGame)); + mDebugProfiles.addColumn (new FlagColumn2 ( + Columns::ColumnId_GlobalProfile, ESM::DebugProfile::Flag_Global)); + mDebugProfiles.addColumn (new DescriptionColumn); + mDebugProfiles.addColumn (new ScriptColumn ( + ScriptColumn::Type_Lines)); addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); @@ -281,6 +293,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc UniversalId::Type_Referenceable); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); addModel (new IdTable (&mFilters), UniversalId::Type_Filter); + addModel (new IdTable (&mDebugProfiles), UniversalId::Type_DebugProfile); addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Meshes)), UniversalId::Type_Mesh); addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Icons)), @@ -484,12 +497,12 @@ CSMWorld::RefCollection& CSMWorld::Data::getReferences() return mRefs; } -const CSMWorld::IdCollection& CSMWorld::Data::getFilters() const +const CSMWorld::IdCollection& CSMWorld::Data::getFilters() const { return mFilters; } -CSMWorld::IdCollection& CSMWorld::Data::getFilters() +CSMWorld::IdCollection& CSMWorld::Data::getFilters() { return mFilters; } @@ -514,6 +527,16 @@ CSMWorld::IdCollection& CSMWorld::Data::getBodyParts() return mBodyParts; } +const CSMWorld::IdCollection& CSMWorld::Data::getDebugProfiles() const +{ + return mDebugProfiles; +} + +CSMWorld::IdCollection& CSMWorld::Data::getDebugProfiles() +{ + return mDebugProfiles; +} + const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const { return mResourcesManager.get (id.getType()); @@ -583,6 +606,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) ESM::NAME n = mReader->getRecName(); mReader->getRecHeader(); + bool unhandledRecord = false; + switch (n.val) { 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: - if (mProject) + if (!mProject) { - mFilters.load (*mReader, mBase); - mFilters.setData (mFilters.getSize()-1, - mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope), - static_cast (CSMFilter::Filter::Scope_Project)); + unhandledRecord = true; break; } - // fall through (filter record in a content file is an error with format 0) + mFilters.load (*mReader, mBase); + break; + + case ESM::REC_DBGP: + + if (!mProject) + { + unhandledRecord = true; + break; + } + + mDebugProfiles.load (*mReader, mBase); + break; default: - messages.push_back (std::make_pair (UniversalId::Type_None, - "Unsupported record type: " + n.toString())); + unhandledRecord = true; + } - mReader->skipRecord(); + if (unhandledRecord) + { + messages.push_back (std::make_pair (UniversalId::Type_None, + "Unsupported record type: " + n.toString())); + + mReader->skipRecord(); } return false; diff --git a/apps/opencs/model/world/data.hpp b/apps/opencs/model/world/data.hpp index cbf13d8b1..d0a07c677 100644 --- a/apps/opencs/model/world/data.hpp +++ b/apps/opencs/model/world/data.hpp @@ -23,11 +23,11 @@ #include #include #include +#include +#include #include -#include "../filter/filter.hpp" - #include "../doc/stage.hpp" #include "idcollection.hpp" @@ -70,12 +70,13 @@ namespace CSMWorld IdCollection mJournals; IdCollection mEnchantments; IdCollection mBodyParts; + IdCollection mDebugProfiles; InfoCollection mTopicInfos; InfoCollection mJournalInfos; IdCollection mCells; RefIdCollection mReferenceables; RefCollection mRefs; - IdCollection mFilters; + IdCollection mFilters; const ResourcesManager& mResourcesManager; std::vector mModels; std::map mModelIndex; @@ -178,9 +179,9 @@ namespace CSMWorld RefCollection& getReferences(); - const IdCollection& getFilters() const; + const IdCollection& getFilters() const; - IdCollection& getFilters(); + IdCollection& getFilters(); const IdCollection& getEnchantments() const; @@ -190,6 +191,10 @@ namespace CSMWorld IdCollection& getBodyParts(); + const IdCollection& getDebugProfiles() const; + + IdCollection& getDebugProfiles(); + /// Throws an exception, if \a id does not match a resources list. const Resources& getResources (const UniversalId& id) const; diff --git a/apps/opencs/model/world/scope.cpp b/apps/opencs/model/world/scope.cpp new file mode 100644 index 000000000..e3ebf5ebd --- /dev/null +++ b/apps/opencs/model/world/scope.cpp @@ -0,0 +1,25 @@ + +#include "scope.hpp" + +#include + +#include + +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; +} \ No newline at end of file diff --git a/apps/opencs/model/world/scope.hpp b/apps/opencs/model/world/scope.hpp new file mode 100644 index 000000000..3983d91f5 --- /dev/null +++ b/apps/opencs/model/world/scope.hpp @@ -0,0 +1,23 @@ +#ifndef CSM_WOLRD_SCOPE_H +#define CSM_WOLRD_SCOPE_H + +#include + +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 diff --git a/apps/opencs/model/world/universalid.cpp b/apps/opencs/model/world/universalid.cpp index 7ee767354..d338a4a3b 100644 --- a/apps/opencs/model/world/universalid.cpp +++ b/apps/opencs/model/world/universalid.cpp @@ -50,6 +50,8 @@ namespace { 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_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 }; @@ -109,6 +111,7 @@ namespace { 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_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 }; diff --git a/apps/opencs/model/world/universalid.hpp b/apps/opencs/model/world/universalid.hpp index 3d3f215d6..069beed4b 100644 --- a/apps/opencs/model/world/universalid.hpp +++ b/apps/opencs/model/world/universalid.hpp @@ -119,10 +119,13 @@ namespace CSMWorld Type_Textures, Type_Texture, Type_Videos, - Type_Video + Type_Video, + Type_DebugProfiles, + Type_DebugProfile, + Type_RunLog }; - enum { NumberOfTypes = Type_BodyPart+1 }; + enum { NumberOfTypes = Type_DebugProfile+1 }; private: diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.cpp b/apps/opencs/view/doc/globaldebugprofilemenu.cpp new file mode 100644 index 000000000..82bd96326 --- /dev/null +++ b/apps/opencs/view/doc/globaldebugprofilemenu.cpp @@ -0,0 +1,93 @@ + +#include "globaldebugprofilemenu.hpp" + +#include +#include + +#include + +#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 ids; + + for (int i=0; idata (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::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())); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/globaldebugprofilemenu.hpp b/apps/opencs/view/doc/globaldebugprofilemenu.hpp new file mode 100644 index 000000000..0d7906cce --- /dev/null +++ b/apps/opencs/view/doc/globaldebugprofilemenu.hpp @@ -0,0 +1,49 @@ +#ifndef CSV_DOC_GLOBALDEBUGPROFILEMENU_H +#define CSV_DOC_GLOBALDEBUGPROFILEMENU_H + +#include + +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 diff --git a/apps/opencs/view/doc/runlogsubview.cpp b/apps/opencs/view/doc/runlogsubview.cpp new file mode 100644 index 000000000..68e888e8d --- /dev/null +++ b/apps/opencs/view/doc/runlogsubview.cpp @@ -0,0 +1,20 @@ + +#include "runlogsubview.hpp" + +#include + +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 +} \ No newline at end of file diff --git a/apps/opencs/view/doc/runlogsubview.hpp b/apps/opencs/view/doc/runlogsubview.hpp new file mode 100644 index 000000000..cfb676a37 --- /dev/null +++ b/apps/opencs/view/doc/runlogsubview.hpp @@ -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 diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 4868f20ff..cf5148391 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -12,6 +12,8 @@ #include "../../model/doc/document.hpp" #include "../../model/settings/usersettings.hpp" +#include "../../model/world/idtable.hpp" + #include "../world/subviews.hpp" #include "../tools/subviews.hpp" @@ -19,6 +21,9 @@ #include "viewmanager.hpp" #include "operations.hpp" #include "subview.hpp" +#include "globaldebugprofilemenu.hpp" +#include "runlogsubview.hpp" +#include "subviewfactoryimp.hpp" void CSVDoc::View::closeEvent (QCloseEvent *event) { @@ -232,6 +237,35 @@ void CSVDoc::View::setupAssetsMenu() 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 (*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() { setupFileMenu(); @@ -241,6 +275,7 @@ void CSVDoc::View::setupUi() setupMechanicsMenu(); setupCharacterMenu(); setupAssetsMenu(); + setupDebugMenu(); } void CSVDoc::View::updateTitle() @@ -261,6 +296,7 @@ void CSVDoc::View::updateTitle() void CSVDoc::View::updateActions() { bool editing = !(mDocument->getState() & CSMDoc::State_Locked); + bool running = mDocument->getState() & CSMDoc::State_Running; for (std::vector::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter) (*iter)->setEnabled (editing); @@ -268,8 +304,11 @@ void CSVDoc::View::updateActions() mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo()); 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)); + + mGlobalDebugProfileMenu->updateActions (running); + mStopDebug->setEnabled (running); } 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(); + updateActions(); + CSVWorld::addSubViewFactories (mSubViewFactory); CSVTools::addSubViewFactories (mSubViewFactory); + mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory); + connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int))); } @@ -543,6 +586,16 @@ void CSVDoc::View::addVideosSubView() 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) { mDocument->abortOperation (type); @@ -588,3 +641,13 @@ void CSVDoc::View::loadErrorLog() { 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(); +} \ No newline at end of file diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 19171ff42..9b4f2099b 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -25,6 +25,7 @@ namespace CSVDoc { class ViewManager; class Operations; + class GlobalDebugProfileMenu; class View : public QMainWindow { @@ -39,10 +40,12 @@ namespace CSVDoc QAction *mSave; QAction *mVerify; QAction *mShowStatusBar; + QAction *mStopDebug; std::vector mEditingActions; Operations *mOperations; SubViewFactoryManager mSubViewFactory; QMainWindow mSubViewWindow; + GlobalDebugProfileMenu *mGlobalDebugProfileMenu; // not implemented @@ -67,6 +70,8 @@ namespace CSVDoc void setupAssetsMenu(); + void setupDebugMenu(); + void setupUi(); void updateTitle(); @@ -194,9 +199,17 @@ namespace CSVDoc void addVideosSubView(); + void addDebugProfilesSubView(); + + void addRunLogSubView(); + void toggleShowStatusBar (bool show); void loadErrorLog(); + + void run (const std::string& profile, const std::string& startupInstruction = ""); + + void stop(); }; } diff --git a/apps/opencs/view/filter/filtercreator.cpp b/apps/opencs/view/filter/filtercreator.cpp deleted file mode 100644 index 640c9fe78..000000000 --- a/apps/opencs/view/filter/filtercreator.cpp +++ /dev/null @@ -1,77 +0,0 @@ - -#include "filtercreator.hpp" - -#include -#include - -#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 (*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(); -} diff --git a/apps/opencs/view/filter/filtercreator.hpp b/apps/opencs/view/filter/filtercreator.hpp deleted file mode 100644 index 437d01c8d..000000000 --- a/apps/opencs/view/filter/filtercreator.hpp +++ /dev/null @@ -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 diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 21d88fb89..ab594826d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -133,6 +133,20 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent 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) : 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); } -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; for (unsigned i = 0; i < data.size(); ++i) { @@ -224,16 +245,23 @@ void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld:: 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) { - case cellsExterior: + case Type_CellsExterior: return canHandle; - case cellsInterior: + case Type_CellsInterior: return needUnpaged; default: diff --git a/apps/opencs/view/render/pagedworldspacewidget.hpp b/apps/opencs/view/render/pagedworldspacewidget.hpp index ec4485697..249c0c5fb 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.hpp +++ b/apps/opencs/view/render/pagedworldspacewidget.hpp @@ -42,6 +42,8 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + virtual std::string getStartupInstruction(); + public: PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document); @@ -55,9 +57,11 @@ namespace CSVRender void setCellSelection (const CSMWorld::CellSelection& selection); - virtual void handleDrop(const std::vector& data); + /// \return Drop handled? + virtual bool handleDrop (const std::vector& 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 /// that is the responsibility of the calling function. diff --git a/apps/opencs/view/render/unpagedworldspacewidget.cpp b/apps/opencs/view/render/unpagedworldspacewidget.cpp index 5175eba6e..aab3791fc 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.cpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.cpp @@ -1,7 +1,10 @@ #include "unpagedworldspacewidget.hpp" +#include + #include +#include #include @@ -86,13 +89,21 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI emit closeRequest(); } -void CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data) +bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector& data, DropType type) { + if (WorldspaceWidget::handleDrop (data, type)) + return true; + + if (type!=Type_CellsInterior) + return false; + mCellId = data.begin()->getId(); + mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId)); + update(); emit cellChanged(*data.begin()); - /// \todo replace mCell + return true; } void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft, @@ -149,14 +160,33 @@ void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& pare 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) { - case cellsInterior: + case Type_CellsInterior: return canHandle; - case cellsExterior: + case Type_CellsExterior: return needPaged; default: diff --git a/apps/opencs/view/render/unpagedworldspacewidget.hpp b/apps/opencs/view/render/unpagedworldspacewidget.hpp index 505d60735..5924abaa9 100644 --- a/apps/opencs/view/render/unpagedworldspacewidget.hpp +++ b/apps/opencs/view/render/unpagedworldspacewidget.hpp @@ -41,9 +41,11 @@ namespace CSVRender UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget *parent); - virtual dropRequirments getDropRequirements(dropType type) const; + virtual dropRequirments getDropRequirements(DropType type) const; - virtual void handleDrop(const std::vector& data); + /// \return Drop handled? + virtual bool handleDrop (const std::vector& data, + DropType type); private: @@ -60,6 +62,8 @@ namespace CSVRender virtual void referenceAdded (const QModelIndex& index, int start, int end); + virtual std::string getStartupInstruction(); + private slots: void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); diff --git a/apps/opencs/view/render/worldspacewidget.cpp b/apps/opencs/view/render/worldspacewidget.cpp index 4d3c7f666..fa304dd82 100644 --- a/apps/opencs/view/render/worldspacewidget.cpp +++ b/apps/opencs/view/render/worldspacewidget.cpp @@ -1,6 +1,8 @@ #include "worldspacewidget.hpp" +#include + #include #include #include @@ -8,14 +10,16 @@ #include #include "../../model/world/universalid.hpp" +#include "../../model/world/idtable.hpp" #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle.hpp" +#include "../widget/scenetoolrun.hpp" #include "elements.hpp" CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent) -: SceneWidget (parent), mDocument(document) +: SceneWidget (parent), mDocument(document), mRun (0) { setAcceptDrops(true); @@ -38,6 +42,14 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int))); connect (references, SIGNAL (rowsInserted (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) @@ -112,59 +124,98 @@ CSVWidget::SceneToolToggle *CSVRender::WorldspaceWidget::makeSceneVisibilitySele return mSceneElements; } -CSVRender::WorldspaceWidget::dropType CSVRender::WorldspaceWidget::getDropType ( +CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool ( + CSVWidget::SceneToolbar *parent) +{ + CSMWorld::IdTable& debugProfiles = dynamic_cast ( + *mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles)); + + std::vector 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& data) { - dropType output = notCells; - bool firstIteration = true; + DropType output = Type_Other; - for (unsigned i = 0; i < data.size(); ++i) + for (std::vector::const_iterator iter (data.begin()); + iter!=data.end(); ++iter) { - if (data[i].getType() == CSMWorld::UniversalId::Type_Cell || - data[i].getType() == CSMWorld::UniversalId::Type_Cell_Missing) + DropType type = Type_Other; + + if (iter->getType()==CSMWorld::UniversalId::Type_Cell || + iter->getType()==CSMWorld::UniversalId::Type_Cell_Missing) { - if (*(data[i].getId().begin()) == '#') //exterior - { - 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; + type = iter->getId().substr (0, 1)=="#" ? Type_CellsExterior : Type_CellsInterior; } + 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; } +CSVRender::WorldspaceWidget::dropRequirments + CSVRender::WorldspaceWidget::getDropRequirements (DropType type) const +{ + if (type==Type_DebugProfile) + return canHandle; + + return ignored; +} + +bool CSVRender::WorldspaceWidget::handleDrop (const std::vector& data, + DropType type) +{ + if (type==Type_DebugProfile) + { + if (mRun) + { + for (std::vector::const_iterator iter (data.begin()); + iter!=data.end(); ++iter) + mRun->addProfile (iter->getId()); + } + + return true; + } + + return false; +} + unsigned int CSVRender::WorldspaceWidget::getElementMask() const { return mSceneElements->getSelection(); @@ -179,6 +230,11 @@ void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons ( tool->addButton (":armor.png", Element_Pathgrid, ":armor.png", "Pathgrid"); } +CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument() +{ + return mDocument; +} + void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event) { event->accept(); @@ -201,6 +257,58 @@ void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event) } //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 ( + *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 ( + *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() { setVisibilityMask (getElementMask()); diff --git a/apps/opencs/view/render/worldspacewidget.hpp b/apps/opencs/view/render/worldspacewidget.hpp index e21ad5ec2..0754e9ecf 100644 --- a/apps/opencs/view/render/worldspacewidget.hpp +++ b/apps/opencs/view/render/worldspacewidget.hpp @@ -18,6 +18,7 @@ namespace CSVWidget class SceneToolMode; class SceneToolToggle; class SceneToolbar; + class SceneToolRun; } namespace CSVRender @@ -30,15 +31,17 @@ namespace CSVRender CSVRender::NavigationFree mFree; CSVRender::NavigationOrbit mOrbit; CSVWidget::SceneToolToggle *mSceneElements; + CSVWidget::SceneToolRun *mRun; + CSMDoc::Document& mDocument; public: - enum dropType + enum DropType { - cellsMixed, - cellsInterior, - cellsExterior, - notCells + Type_CellsInterior, + Type_CellsExterior, + Type_Other, + Type_DebugProfile }; enum dropRequirments @@ -60,16 +63,22 @@ namespace CSVRender CSVWidget::SceneToolToggle *makeSceneVisibilitySelector ( 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(); - static dropType getDropType(const std::vector& data); + static DropType getDropType(const std::vector& data); - virtual dropRequirments getDropRequirements(dropType type) const = 0; + virtual dropRequirments getDropRequirements(DropType type) const; virtual void useViewHint (const std::string& hint); ///< Default-implementation: ignored. - virtual void handleDrop(const std::vector& data) = 0; + /// \return Drop handled? + virtual bool handleDrop (const std::vector& data, + DropType type); virtual unsigned int getElementMask() const; @@ -77,7 +86,7 @@ namespace CSVRender virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool); - const CSMDoc::Document& mDocument; + CSMDoc::Document& getDocument(); private: @@ -87,6 +96,8 @@ namespace CSVRender void dragMoveEvent(QDragMoveEvent *event); + virtual std::string getStartupInstruction() = 0; + private slots: 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 runRequest (const std::string& profile); + + void debugProfileDataChanged (const QModelIndex& topLeft, + const QModelIndex& bottomRight); + + void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end); + + protected slots: void elementSelectionChanged(); diff --git a/apps/opencs/view/tools/reportsubview.cpp b/apps/opencs/view/tools/reportsubview.cpp index e84f5cf4b..5a2523789 100644 --- a/apps/opencs/view/tools/reportsubview.cpp +++ b/apps/opencs/view/tools/reportsubview.cpp @@ -21,7 +21,7 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc: mTable->setSelectionMode (QAbstractItemView::ExtendedSelection); mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate ( - document.getUndoStack(), this); + document, this); mTable->setItemDelegateForColumn (0, mIdTypeDelegate); diff --git a/apps/opencs/view/widget/pushbutton.cpp b/apps/opencs/view/widget/pushbutton.cpp index 307ea1a75..f23462585 100644 --- a/apps/opencs/view/widget/pushbutton.cpp +++ b/apps/opencs/view/widget/pushbutton.cpp @@ -20,6 +20,10 @@ void CSVWidget::PushButton::setExtendedToolTip() break; + case Type_TopAction: + + break; + case Type_Mode: tooltip += @@ -87,4 +91,9 @@ bool CSVWidget::PushButton::hasKeepOpen() const QString CSVWidget::PushButton::getBaseToolTip() const { return mToolTip; +} + +CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const +{ + return mType; } \ No newline at end of file diff --git a/apps/opencs/view/widget/pushbutton.hpp b/apps/opencs/view/widget/pushbutton.hpp index 64b38db2e..35062a137 100644 --- a/apps/opencs/view/widget/pushbutton.hpp +++ b/apps/opencs/view/widget/pushbutton.hpp @@ -14,6 +14,7 @@ namespace CSVWidget enum Type { Type_TopMode, // top level button for mode selector panel + Type_TopAction, // top level button that triggers an action Type_Mode, // mode button Type_Toggle }; @@ -50,6 +51,8 @@ namespace CSVWidget /// Return tooltip used at construction (without any button-specific modifications) QString getBaseToolTip() const; + + Type getType() const; }; } diff --git a/apps/opencs/view/widget/scenetool.cpp b/apps/opencs/view/widget/scenetool.cpp index e3f2dfd1c..b8e9f895f 100644 --- a/apps/opencs/view/widget/scenetool.cpp +++ b/apps/opencs/view/widget/scenetool.cpp @@ -1,10 +1,12 @@ #include "scenetool.hpp" +#include + #include "scenetoolbar.hpp" -CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) -: PushButton (PushButton::Type_TopMode, "", parent) +CSVWidget::SceneTool::SceneTool (SceneToolbar *parent, Type type) +: PushButton (type, "", parent) { setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed)); setIconSize (QSize (parent->getIconSize(), parent->getIconSize())); @@ -13,7 +15,20 @@ CSVWidget::SceneTool::SceneTool (SceneToolbar *parent) 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() { - showPanel (parentWidget()->mapToGlobal (pos())); + if (getType()==Type_TopAction) + activate(); + else + showPanel (parentWidget()->mapToGlobal (pos())); } diff --git a/apps/opencs/view/widget/scenetool.hpp b/apps/opencs/view/widget/scenetool.hpp index 24099683e..cdea88096 100644 --- a/apps/opencs/view/widget/scenetool.hpp +++ b/apps/opencs/view/widget/scenetool.hpp @@ -14,10 +14,18 @@ namespace CSVWidget public: - SceneTool (SceneToolbar *parent); + SceneTool (SceneToolbar *parent, Type type = Type_TopMode); 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: void openRequest(); diff --git a/apps/opencs/view/widget/scenetoolrun.cpp b/apps/opencs/view/widget/scenetoolrun.cpp new file mode 100644 index 000000000..92f3193fe --- /dev/null +++ b/apps/opencs/view/widget/scenetoolrun.cpp @@ -0,0 +1,151 @@ + +#include "scenetoolrun.hpp" + +#include + +#include +#include +#include +#include +#include + +void CSVWidget::SceneToolRun::adjustToolTips() +{ + QString toolTip = mToolTip; + + if (mSelected==mProfiles.end()) + toolTip += "

No debug profile selected (function disabled)"; + else + { + toolTip += "

Debug profile: " + QString::fromUtf8 (mSelected->c_str()); + toolTip += "

(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::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& 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::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::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::iterator iter = mProfiles.begin(); + std::advance (iter, index.row()); + removeProfile (*iter); + updatePanel(); + } +} \ No newline at end of file diff --git a/apps/opencs/view/widget/scenetoolrun.hpp b/apps/opencs/view/widget/scenetoolrun.hpp new file mode 100644 index 000000000..4396c2288 --- /dev/null +++ b/apps/opencs/view/widget/scenetoolrun.hpp @@ -0,0 +1,64 @@ +#ifndef CSV_WIDGET_SCENETOOLRUN_H +#define CSV_WIDGET_SCENETOOLRUN_H + +#include +#include + +#include "scenetool.hpp" + +class QFrame; +class QTableWidget; +class QModelIndex; + +namespace CSVWidget +{ + class SceneToolRun : public SceneTool + { + Q_OBJECT + + std::set mProfiles; + std::set::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& 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 diff --git a/apps/opencs/view/world/creator.cpp b/apps/opencs/view/world/creator.cpp index d753a2b47..a24c58e54 100644 --- a/apps/opencs/view/world/creator.cpp +++ b/apps/opencs/view/world/creator.cpp @@ -1,7 +1,16 @@ #include "creator.hpp" -CSVWorld::Creator:: ~Creator() {} +#include + +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() {} diff --git a/apps/opencs/view/world/creator.hpp b/apps/opencs/view/world/creator.hpp index 88da70330..8e50e8715 100644 --- a/apps/opencs/view/world/creator.hpp +++ b/apps/opencs/view/world/creator.hpp @@ -1,9 +1,14 @@ #ifndef CSV_WORLD_CREATOR_H #define CSV_WORLD_CREATOR_H +#include + #include + #include "../../model/world/universalid.hpp" +#include "../../model/world/scope.hpp" + class QUndoStack; namespace CSMWorld @@ -32,6 +37,9 @@ namespace CSVWorld virtual void toggleWidgets(bool active = true) = 0; + /// Default implementation: Throw an exception if scope!=Scope_Content. + virtual void setScope (unsigned int scope); + signals: void done(); @@ -68,7 +76,7 @@ namespace CSVWorld /// \note The function always returns 0. }; - template + template class CreatorFactory : public CreatorFactoryBase { public: @@ -81,11 +89,15 @@ namespace CSVWorld /// records should be provided. }; - template - Creator *CreatorFactory::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, + template + Creator *CreatorFactory::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack, const CSMWorld::UniversalId& id) const { - return new CreatorT (data, undoStack, id); + std::auto_ptr creator (new CreatorT (data, undoStack, id)); + + creator->setScope (scope); + + return creator.release(); } } diff --git a/apps/opencs/view/world/datadisplaydelegate.cpp b/apps/opencs/view/world/datadisplaydelegate.cpp index 31ec18d52..20cf22cdf 100644 --- a/apps/opencs/view/world/datadisplaydelegate.cpp +++ b/apps/opencs/view/world/datadisplaydelegate.cpp @@ -6,11 +6,11 @@ CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values, const IconList &icons, - QUndoStack &undoStack, + CSMDoc::Document& document, const QString &pageName, const QString &settingName, QObject *parent) - : EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly), + : EnumDelegate (values, document, parent), mDisplayMode (Mode_TextOnly), mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3), mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName) { @@ -126,8 +126,6 @@ void CSVWorld::DataDisplayDelegate::updateDisplayMode (const QString &mode) CSVWorld::DataDisplayDelegate::~DataDisplayDelegate() { - mIcons.clear(); - mPixmaps.clear(); } 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, - QObject *parent) const +CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate ( + CSMDoc::Document& document, QObject *parent) const { - - return new DataDisplayDelegate (mValues, mIcons, undoStack, "", "", parent); + return new DataDisplayDelegate (mValues, mIcons, document, "", "", parent); } diff --git a/apps/opencs/view/world/datadisplaydelegate.hpp b/apps/opencs/view/world/datadisplaydelegate.hpp index ef453c58f..a29675e74 100755 --- a/apps/opencs/view/world/datadisplaydelegate.hpp +++ b/apps/opencs/view/world/datadisplaydelegate.hpp @@ -40,7 +40,7 @@ namespace CSVWorld public: explicit DataDisplayDelegate (const ValueList & values, const IconList & icons, - QUndoStack& undoStack, + CSMDoc::Document& document, const QString &pageName, const QString &settingName, QObject *parent); @@ -82,7 +82,7 @@ namespace CSVWorld 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. protected: diff --git a/apps/opencs/view/world/dialoguesubview.cpp b/apps/opencs/view/world/dialoguesubview.cpp index bcf108934..57069bec0 100644 --- a/apps/opencs/view/world/dialoguesubview.cpp +++ b/apps/opencs/view/world/dialoguesubview.cpp @@ -167,10 +167,10 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std:: ==============================DialogueDelegateDispatcher========================================== */ -CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack) : +CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document) : mParent(parent), mTable(table), -mUndoStack(undoStack), +mDocument (document), mNotEditableDelegate(table, parent) { } @@ -182,7 +182,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS if (delegateIt == mDelegates.end()) { delegate = CommandDelegateFactoryCollection::get().makeDelegate ( - display, mUndoStack, mParent); + display, mDocument, mParent); mDelegates.insert(std::make_pair(display, delegate)); } else { @@ -266,7 +266,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: editor = delegateIt->second->createEditor(qobject_cast(mParent), QStyleOptionViewItem(), index, display); DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display); - bool skip = false; if (qobject_cast(editor)) { connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited())); @@ -274,27 +273,22 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase:: proxy, SLOT(tableMimeDataDropped(const std::vector&, 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*))); - skip = true; } - if(!skip && qobject_cast(editor)) + else if (qobject_cast(editor)) { connect(editor, SIGNAL(stateChanged(int)), proxy, SLOT(editorDataCommited())); - skip = true; } - if(!skip && qobject_cast(editor)) + else if (qobject_cast(editor)) { connect(editor, SIGNAL(textChanged()), proxy, SLOT(editorDataCommited())); - skip = true; } - if(!skip && qobject_cast(editor)) + else if (qobject_cast(editor)) { connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited())); - skip = true; } - if(!skip && qobject_cast(editor)) + else if (qobject_cast(editor)) { 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))); @@ -315,12 +309,12 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher() =============================================================EditWidget===================================================== */ -CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) : -mDispatcher(this, table, undoStack), +CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) : +mDispatcher(this, table, document), QScrollArea(parent), mWidgetMapper(NULL), mMainWidget(NULL), -mUndoStack(undoStack), +mDocument (document), mTable(table) { remake (row); @@ -478,7 +472,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM 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*)), this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*))); diff --git a/apps/opencs/view/world/dialoguesubview.hpp b/apps/opencs/view/world/dialoguesubview.hpp index cbca0159c..4c260170f 100644 --- a/apps/opencs/view/world/dialoguesubview.hpp +++ b/apps/opencs/view/world/dialoguesubview.hpp @@ -101,14 +101,14 @@ namespace CSVWorld CSMWorld::IdTable* mTable; - QUndoStack& mUndoStack; + CSMDoc::Document& mDocument; NotEditableSubDelegate mNotEditableDelegate; std::vector mProxys; //once we move to the C++11 we should use unique_ptr public: - DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack); + DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document); ~DialogueDelegateDispatcher(); @@ -145,11 +145,11 @@ namespace CSVWorld DialogueDelegateDispatcher mDispatcher; QWidget* mMainWidget; CSMWorld::IdTable* mTable; - QUndoStack& mUndoStack; + CSMDoc::Document& mDocument; 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); diff --git a/apps/opencs/view/world/enumdelegate.cpp b/apps/opencs/view/world/enumdelegate.cpp index 377f479bf..168e5cb0a 100644 --- a/apps/opencs/view/world/enumdelegate.cpp +++ b/apps/opencs/view/world/enumdelegate.cpp @@ -35,8 +35,8 @@ void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model, CSVWorld::EnumDelegate::EnumDelegate (const std::vector >& values, - QUndoStack& undoStack, QObject *parent) -: CommandDelegate (undoStack, parent), mValues (values) + CSMDoc::Document& document, QObject *parent) +: CommandDelegate (document, parent), mValues (values) { } @@ -140,10 +140,10 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector >& values, - QUndoStack& undoStack, QObject *parent); + CSMDoc::Document& document, QObject *parent); virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem& option, @@ -64,7 +64,7 @@ namespace CSVWorld EnumDelegateFactory (const std::vector& names, bool allowNone = false); /// \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. void add (int value, const QString& name); diff --git a/apps/opencs/view/world/genericcreator.cpp b/apps/opencs/view/world/genericcreator.cpp index 31c216e2c..e905cfef6 100644 --- a/apps/opencs/view/world/genericcreator.cpp +++ b/apps/opencs/view/world/genericcreator.cpp @@ -7,6 +7,10 @@ #include #include #include +#include +#include + +#include #include "../../model/world/commands.hpp" #include "../../model/world/data.hpp" @@ -56,22 +60,66 @@ const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const return mListId; } +std::string CSVWorld::GenericCreator::getNamespace() const +{ + CSMWorld::Scope scope = CSMWorld::Scope_Content; + + if (mScope) + { + scope = static_cast (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; + } + + switch (scope) + { + case CSMWorld::Scope_Content: return ""; + case CSMWorld::Scope_Project: return "project::"; + case CSMWorld::Scope_Session: return "session::"; + } + + 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) - + 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->setContentsMargins (0, 0, 0, 0); mId = new QLineEdit; - mId->setValidator (new IdValidator (relaxedIdRules, this)); + mId->setValidator (mValidator = new IdValidator (relaxedIdRules, this)); mLayout->addWidget (mId, 1); mCreate = new QPushButton ("Create"); @@ -99,22 +147,17 @@ void CSVWorld::GenericCreator::reset() mCloneMode = false; mId->setText (""); update(); + updateNamespace(); } std::string CSVWorld::GenericCreator::getErrors() const { std::string errors; - std::string id = getId(); - - if (id.empty()) - { - errors = "Missing ID"; - } - else if (mData.hasId (id)) - { + if (!mId->hasAcceptableInput()) + errors = mValidator->getError(); + else if (mData.hasId (getId())) errors = "ID is already in use"; - } return errors; } @@ -128,29 +171,28 @@ void CSVWorld::GenericCreator::create() { if (!mLocked) { + std::string id = getId(); + if (mCloneMode) { - std::string id = getId(); std::auto_ptr command (new CSMWorld::CloneCommand ( dynamic_cast (*mData.getTableModel(mListId)), mClonedId, id, mClonedType)); mUndoStack.push(command.release()); - emit done(); - emit requestFocus(id); - } else { - std::string id = getId(); - + } + else + { std::auto_ptr command (new CSMWorld::CreateCommand ( dynamic_cast (*mData.getTableModel (mListId)), id)); configureCreateCommand (*command); 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::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 (CSMWorld::Scope_Content)); + + if (mScopes & CSMWorld::Scope_Project) + mScope->addItem ("Project", static_cast (CSMWorld::Scope_Project)); + + if (mScopes & CSMWorld::Scope_Session) + mScope->addItem ("Session", static_cast (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(); +} \ No newline at end of file diff --git a/apps/opencs/view/world/genericcreator.hpp b/apps/opencs/view/world/genericcreator.hpp index 714853f98..ea099248e 100644 --- a/apps/opencs/view/world/genericcreator.hpp +++ b/apps/opencs/view/world/genericcreator.hpp @@ -5,6 +5,8 @@ class QString; class QPushButton; class QLineEdit; class QHBoxLayout; +class QComboBox; +class QLabel; #include "creator.hpp" @@ -17,6 +19,8 @@ namespace CSMWorld namespace CSVWorld { + class IdValidator; + class GenericCreator : public Creator { Q_OBJECT @@ -31,6 +35,10 @@ namespace CSVWorld bool mLocked; std::string mClonedId; CSMWorld::UniversalId::Type mClonedType; + unsigned int mScopes; + QComboBox *mScope; + QLabel *mScopeLabel; + IdValidator *mValidator; protected: bool mCloneMode; @@ -54,6 +62,12 @@ namespace CSVWorld const CSMWorld::UniversalId& getCollectionId() const; + std::string getNamespace() const; + + private: + + void updateNamespace(); + public: GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack, @@ -65,18 +79,22 @@ namespace CSVWorld 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); virtual std::string getErrors() const; ///< Return formatted error descriptions for the current state of the creator. if an empty /// string is returned, there is no error. + virtual void setScope (unsigned int scope); + private slots: void textChanged (const QString& text); void create(); + + void scopeChanged (int index); }; } diff --git a/apps/opencs/view/world/idtypedelegate.cpp b/apps/opencs/view/world/idtypedelegate.cpp index 6b4d442f3..543c96a24 100755 --- a/apps/opencs/view/world/idtypedelegate.cpp +++ b/apps/opencs/view/world/idtypedelegate.cpp @@ -3,8 +3,8 @@ #include "../../model/world/universalid.hpp" CSVWorld::IdTypeDelegate::IdTypeDelegate - (const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent) - : DataDisplayDelegate (values, icons, undoStack, + (const ValueList &values, const IconList &icons, CSMDoc::Document& document, QObject *parent) + : DataDisplayDelegate (values, icons, document, "Display Format", "Referenceable ID Type Display", parent) {} @@ -20,8 +20,8 @@ CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory() } } -CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, - QObject *parent) const +CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate ( + CSMDoc::Document& document, QObject *parent) const { - return new IdTypeDelegate (mValues, mIcons, undoStack, parent); + return new IdTypeDelegate (mValues, mIcons, document, parent); } diff --git a/apps/opencs/view/world/idtypedelegate.hpp b/apps/opencs/view/world/idtypedelegate.hpp index bed81f2d5..e9a0af68c 100755 --- a/apps/opencs/view/world/idtypedelegate.hpp +++ b/apps/opencs/view/world/idtypedelegate.hpp @@ -11,7 +11,7 @@ namespace CSVWorld class IdTypeDelegate : public DataDisplayDelegate { 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 @@ -20,7 +20,7 @@ namespace CSVWorld 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. }; } diff --git a/apps/opencs/view/world/idvalidator.cpp b/apps/opencs/view/world/idvalidator.cpp index 7c210daae..7caa20f9b 100644 --- a/apps/opencs/view/world/idvalidator.cpp +++ b/apps/opencs/view/world/idvalidator.cpp @@ -1,6 +1,8 @@ #include "idvalidator.hpp" +#include + bool CSVWorld::IdValidator::isValid (const QChar& c, bool first) const { 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 { + mError.clear(); + if (mRelaxed) { 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 { - bool first = true; + if (input.isEmpty()) + { + mError = "Missing ID"; + return QValidator::Intermediate; + } - for (QString::const_iterator iter (input.begin()); iter!=input.end(); ++iter, first = false) - if (!isValid (*iter, first)) - return QValidator::Invalid; + 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 + + if (scope) + { + 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; +} + +void CSVWorld::IdValidator::setNamespace (const std::string& namespace_) +{ + mNamespace = Misc::StringUtils::lowerCase (namespace_); +} + +std::string CSVWorld::IdValidator::getError() const +{ + return mError; } \ No newline at end of file diff --git a/apps/opencs/view/world/idvalidator.hpp b/apps/opencs/view/world/idvalidator.hpp index 8ca162440..a9df9580a 100644 --- a/apps/opencs/view/world/idvalidator.hpp +++ b/apps/opencs/view/world/idvalidator.hpp @@ -1,6 +1,8 @@ #ifndef CSV_WORLD_IDVALIDATOR_H #define CSV_WORLD_IDVALIDATOR_H +#include + #include namespace CSVWorld @@ -8,6 +10,8 @@ namespace CSVWorld class IdValidator : public QValidator { bool mRelaxed; + std::string mNamespace; + mutable std::string mError; private: @@ -20,6 +24,14 @@ namespace CSVWorld 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; + }; } diff --git a/apps/opencs/view/world/recordstatusdelegate.cpp b/apps/opencs/view/world/recordstatusdelegate.cpp index 4fe7031ce..13931b7ad 100644 --- a/apps/opencs/view/world/recordstatusdelegate.cpp +++ b/apps/opencs/view/world/recordstatusdelegate.cpp @@ -9,16 +9,16 @@ CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values, const IconList & icons, - QUndoStack &undoStack, QObject *parent) - : DataDisplayDelegate (values, icons, undoStack, + CSMDoc::Document& document, QObject *parent) + : DataDisplayDelegate (values, icons, document, "Display Format", "Record Status Display", parent) {} -CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate (QUndoStack& undoStack, - QObject *parent) const +CSVWorld::CommandDelegate *CSVWorld::RecordStatusDelegateFactory::makeDelegate ( + CSMDoc::Document& document, QObject *parent) const { - return new RecordStatusDelegate (mValues, mIcons, undoStack, parent); + return new RecordStatusDelegate (mValues, mIcons, document, parent); } CSVWorld::RecordStatusDelegateFactory::RecordStatusDelegateFactory() diff --git a/apps/opencs/view/world/recordstatusdelegate.hpp b/apps/opencs/view/world/recordstatusdelegate.hpp index 1b42223af..fbdaed538 100644 --- a/apps/opencs/view/world/recordstatusdelegate.hpp +++ b/apps/opencs/view/world/recordstatusdelegate.hpp @@ -19,7 +19,7 @@ namespace CSVWorld explicit RecordStatusDelegate(const ValueList& values, const IconList& icons, - QUndoStack& undoStack, QObject *parent = 0); + CSMDoc::Document& document, QObject *parent = 0); }; class RecordStatusDelegateFactory : public DataDisplayDelegateFactory @@ -28,7 +28,7 @@ namespace CSVWorld 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. }; diff --git a/apps/opencs/view/world/scenesubview.cpp b/apps/opencs/view/world/scenesubview.cpp index 3c5b38a22..52bd47b54 100644 --- a/apps/opencs/view/world/scenesubview.cpp +++ b/apps/opencs/view/world/scenesubview.cpp @@ -20,6 +20,7 @@ #include "../widget/scenetoolbar.hpp" #include "../widget/scenetoolmode.hpp" #include "../widget/scenetooltoggle.hpp" +#include "../widget/scenetoolrun.hpp" #include "tablebottombox.hpp" #include "creator.hpp" @@ -121,6 +122,9 @@ CSVWidget::SceneToolbar* CSVWorld::SceneSubView::makeToolbar (CSVRender::Worldsp toolbar->addTool (controlVisibilityTool); } + CSVWidget::SceneToolRun *runTool = widget->makeRunTool (toolbar); + toolbar->addTool (runTool); + return toolbar; } @@ -194,10 +198,12 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI CSVRender::UnpagedWorldspaceWidget* unPagedNewWidget = 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: - mScene->handleDrop(data); + mScene->handleDrop (data, type); break; case CSVRender::WorldspaceWidget::needPaged: @@ -205,7 +211,7 @@ void CSVWorld::SceneSubView::handleDrop (const std::vector< CSMWorld::UniversalI toolbar = makeToolbar(pagedNewWidget, widget_Paged); makeConnections(pagedNewWidget); replaceToolbarAndWorldspace(pagedNewWidget, toolbar); - mScene->handleDrop(data); + mScene->handleDrop (data, type); break; case CSVRender::WorldspaceWidget::needUnpaged: diff --git a/apps/opencs/view/world/scriptedit.cpp b/apps/opencs/view/world/scriptedit.cpp index 23bc76000..c2d94ab5d 100644 --- a/apps/opencs/view/world/scriptedit.cpp +++ b/apps/opencs/view/world/scriptedit.cpp @@ -6,14 +6,35 @@ #include #include +#include "../../model/doc/document.hpp" + #include "../../model/world/universalid.hpp" #include "../../model/world/tablemimedata.hpp" -CSVWorld::ScriptEdit::ScriptEdit (QWidget* parent, const CSMDoc::Document& document) : - QTextEdit (parent), - mDocument (document), - mWhiteListQoutes("^[a-z|_]{1}[a-z|0-9|_]{0,}$", Qt::CaseInsensitive) + +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), + 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 < (event->mimeData()); if (!mime) - QTextEdit::dragEnterEvent(event); + QPlainTextEdit::dragEnterEvent(event); else { setTextCursor (cursorForPosition (event->pos())); @@ -59,7 +95,7 @@ void CSVWorld::ScriptEdit::dragMoveEvent (QDragMoveEvent* event) { const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); if (!mime) - QTextEdit::dragMoveEvent(event); + QPlainTextEdit::dragMoveEvent(event); else { setTextCursor (cursorForPosition (event->pos())); @@ -72,7 +108,7 @@ void CSVWorld::ScriptEdit::dropEvent (QDropEvent* event) const CSMWorld::TableMimeData* mime = dynamic_cast (event->mimeData()); if (!mime) // May happen when non-records (e.g. plain text) are dragged and dropped { - QTextEdit::dropEvent(event); + QPlainTextEdit::dropEvent(event); 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… 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(); +} \ No newline at end of file diff --git a/apps/opencs/view/world/scriptedit.hpp b/apps/opencs/view/world/scriptedit.hpp index b4627c2fe..c67385816 100644 --- a/apps/opencs/view/world/scriptedit.hpp +++ b/apps/opencs/view/world/scriptedit.hpp @@ -1,11 +1,14 @@ #ifndef SCRIPTEDIT_H #define SCRIPTEDIT_H -#include +#include #include +#include #include "../../model/world/universalid.hpp" +#include "scripthighlighter.hpp" + class QWidget; class QRegExp; @@ -16,11 +19,42 @@ namespace CSMDoc namespace CSVWorld { - class ScriptEdit : public QTextEdit + class ScriptEdit : public QPlainTextEdit { Q_OBJECT + 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: QVector mAllowedTypes; @@ -34,6 +68,12 @@ namespace CSVWorld void dragMoveEvent (QDragMoveEvent* event); bool stringNeedsQuote(const std::string& id) const; + + private slots: + + void idListChanged(); + + void updateHighlighting(); }; } #endif // SCRIPTEDIT_H \ No newline at end of file diff --git a/apps/opencs/view/world/scripthighlighter.cpp b/apps/opencs/view/world/scripthighlighter.cpp index e06dab372..36cebcb76 100644 --- a/apps/opencs/view/world/scripthighlighter.cpp +++ b/apps/opencs/view/world/scripthighlighter.cpp @@ -30,6 +30,16 @@ bool CSVWorld::ScriptHighlighter::parseName (const std::string& name, const Comp bool CSVWorld::ScriptHighlighter::parseKeyword (int keyword, const Compiler::TokenLoc& loc, 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); return true; } @@ -63,8 +73,10 @@ void CSVWorld::ScriptHighlighter::highlight (const Compiler::TokenLoc& loc, Type setFormat (index, length, mScheme[type]); } -CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent) -: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data) +CSVWorld::ScriptHighlighter::ScriptHighlighter (const CSMWorld::Data& data, Mode mode, + QTextDocument *parent) +: QSyntaxHighlighter (parent), Compiler::Parser (mErrorHandler, mContext), mContext (data), + mMode (mode) { /// \todo replace this with user settings { diff --git a/apps/opencs/view/world/scripthighlighter.hpp b/apps/opencs/view/world/scripthighlighter.hpp index 495c2e6a3..953f2f953 100644 --- a/apps/opencs/view/world/scripthighlighter.hpp +++ b/apps/opencs/view/world/scripthighlighter.hpp @@ -28,12 +28,20 @@ namespace CSVWorld Type_Id }; + enum Mode + { + Mode_General, + Mode_Console, + Mode_Dialogue + }; + private: Compiler::NullErrorHandler mErrorHandler; Compiler::Extensions mExtensions; CSMWorld::ScriptContext mContext; std::map mScheme; + Mode mMode; private: @@ -74,7 +82,7 @@ namespace CSVWorld public: - ScriptHighlighter (const CSMWorld::Data& data, QTextDocument *parent); + ScriptHighlighter (const CSMWorld::Data& data, Mode mode, QTextDocument *parent); virtual void highlightBlock (const QString& text); diff --git a/apps/opencs/view/world/scriptsubview.cpp b/apps/opencs/view/world/scriptsubview.cpp index fa41151ca..df3fd87be 100644 --- a/apps/opencs/view/world/scriptsubview.cpp +++ b/apps/opencs/view/world/scriptsubview.cpp @@ -3,8 +3,6 @@ #include -#include - #include "../../model/doc/document.hpp" #include "../../model/world/universalid.hpp" #include "../../model/world/data.hpp" @@ -12,28 +10,12 @@ #include "../../model/world/commands.hpp" #include "../../model/world/idtable.hpp" -#include "scripthighlighter.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) -: SubView (id), mDocument (document), mColumn (-1), mChangeLocked (0) +: SubView (id), mDocument (document), mColumn (-1) { - setWidget (mEditor = new ScriptEdit (this, mDocument)); - - mEditor->setAcceptRichText (false); - mEditor->setLineWrapMode (QTextEdit::NoWrap); - mEditor->setTabStopWidth (4); - mEditor->setUndoRedoEnabled (false); // we use OpenCS-wide undo/redo instead + setWidget (mEditor = new ScriptEdit (mDocument, ScriptHighlighter::Mode_General, this)); mModel = &dynamic_cast ( *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)), 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) @@ -73,20 +47,12 @@ void CSVWorld::ScriptSubView::setEditLock (bool locked) mEditor->setReadOnly (locked); } -void CSVWorld::ScriptSubView::idListChanged() -{ - mHighlighter->invalidateIds(); - - if (!mUpdateTimer.isActive()) - mUpdateTimer.start (0); -} - void CSVWorld::ScriptSubView::textChanged() { - if (mChangeLocked) + if (mEditor->isChangeLocked()) return; - ChangeLock lock (*this); + ScriptEdit::ChangeLock lock (*mEditor); mDocument.getUndoStack().push (new CSMWorld::ModifyCommand (*mModel, 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) { - if (mChangeLocked) + if (mEditor->isChangeLocked()) return; - ChangeLock lock (*this); + ScriptEdit::ChangeLock lock (*mEditor); QModelIndex index = mModel->getModelIndex (getUniversalId().getId(), mColumn); @@ -118,12 +84,3 @@ void CSVWorld::ScriptSubView::rowsAboutToBeRemoved (const QModelIndex& parent, i deleteLater(); } -void CSVWorld::ScriptSubView::updateHighlighting() -{ - if (mChangeLocked) - return; - - ChangeLock lock (*this); - - mHighlighter->rehighlight(); -} \ No newline at end of file diff --git a/apps/opencs/view/world/scriptsubview.hpp b/apps/opencs/view/world/scriptsubview.hpp index 7ceab70ba..77127d9be 100644 --- a/apps/opencs/view/world/scriptsubview.hpp +++ b/apps/opencs/view/world/scriptsubview.hpp @@ -3,9 +3,6 @@ #include "../doc/subview.hpp" -#include - -class QTextEdit; class QModelIndex; namespace CSMDoc @@ -20,34 +17,16 @@ namespace CSMWorld namespace CSVWorld { - class ScriptHighlighter; + class ScriptEdit; class ScriptSubView : public CSVDoc::SubView { Q_OBJECT - QTextEdit *mEditor; + ScriptEdit *mEditor; CSMDoc::Document& mDocument; CSMWorld::IdTable *mModel; 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: @@ -57,17 +36,11 @@ namespace CSVWorld public slots: - void idListChanged(); - void textChanged(); void dataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void rowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); - - private slots: - - void updateHighlighting(); }; } diff --git a/apps/opencs/view/world/subviews.cpp b/apps/opencs/view/world/subviews.cpp index 200a26a85..f86aa34ff 100644 --- a/apps/opencs/view/world/subviews.cpp +++ b/apps/opencs/view/world/subviews.cpp @@ -3,8 +3,6 @@ #include "../doc/subviewfactoryimp.hpp" -#include "../filter/filtercreator.hpp" - #include "tablesubview.hpp" #include "dialoguesubview.hpp" #include "scriptsubview.hpp" @@ -35,7 +33,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Factions, CSMWorld::UniversalId::Type_Races, CSMWorld::UniversalId::Type_Sounds, - CSMWorld::UniversalId::Type_Scripts, CSMWorld::UniversalId::Type_Regions, CSMWorld::UniversalId::Type_Birthsigns, CSMWorld::UniversalId::Type_Spells, @@ -91,11 +88,20 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) // Other stuff (combined record tables) manager.add (CSMWorld::UniversalId::Type_RegionMap, new CSVDoc::SubViewFactory); + manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory); + + // More other stuff manager.add (CSMWorld::UniversalId::Type_Filters, new CSVDoc::SubViewFactoryWithCreator >); + CreatorFactory >); - manager.add (CSMWorld::UniversalId::Type_Scene, new CSVDoc::SubViewFactory); + manager.add (CSMWorld::UniversalId::Type_DebugProfiles, + new CSVDoc::SubViewFactoryWithCreator >); + + manager.add (CSMWorld::UniversalId::Type_Scripts, + new CSVDoc::SubViewFactoryWithCreator >); // Dialogue subviews static const CSMWorld::UniversalId::Type sTableTypes2[] = @@ -106,7 +112,6 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) CSMWorld::UniversalId::Type_Global, CSMWorld::UniversalId::Type_Race, CSMWorld::UniversalId::Type_Class, - CSMWorld::UniversalId::Type_Filter, CSMWorld::UniversalId::Type_Sound, CSMWorld::UniversalId::Type_Faction, CSMWorld::UniversalId::Type_Enchantment, @@ -147,6 +152,12 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager) manager.add (CSMWorld::UniversalId::Type_Journal, new CSVDoc::SubViewFactoryWithCreator (false)); + manager.add (CSMWorld::UniversalId::Type_DebugProfile, + new CSVDoc::SubViewFactoryWithCreator > (false)); + + manager.add (CSMWorld::UniversalId::Type_Filter, + new CSVDoc::SubViewFactoryWithCreator > (false)); + //preview manager.add (CSMWorld::UniversalId::Type_Preview, new CSVDoc::SubViewFactory); } \ No newline at end of file diff --git a/apps/opencs/view/world/table.cpp b/apps/opencs/view/world/table.cpp index 43a34e41d..57f47033d 100644 --- a/apps/opencs/view/world/table.cpp +++ b/apps/opencs/view/world/table.cpp @@ -179,7 +179,7 @@ CSVWorld::Table::Table (const CSMWorld::UniversalId& id, mModel->headerData (i, Qt::Horizontal, CSMWorld::ColumnBase::Role_Display).toInt()); CommandDelegate *delegate = CommandDelegateFactoryCollection::get().makeDelegate (display, - mDocument.getUndoStack(), this); + mDocument, this); mDelegates.push_back (delegate); setItemDelegateForColumn (i, delegate); diff --git a/apps/opencs/view/world/util.cpp b/apps/opencs/view/world/util.cpp index 8e7c0a9a2..f8847abfc 100644 --- a/apps/opencs/view/world/util.cpp +++ b/apps/opencs/view/world/util.cpp @@ -17,6 +17,8 @@ #include "../../model/world/commands.hpp" #include "../../model/world/tablemimedata.hpp" +#include "scriptedit.hpp" + CSVWorld::NastyTableModelHack::NastyTableModelHack (QAbstractItemModel& model) : mModel (model) {} @@ -78,15 +80,15 @@ void CSVWorld::CommandDelegateFactoryCollection::add (CSMWorld::ColumnBase::Disp } 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::const_iterator iter = mFactories.find (display); 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() @@ -100,7 +102,12 @@ const CSVWorld::CommandDelegateFactoryCollection& CSVWorld::CommandDelegateFacto 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, @@ -112,11 +119,11 @@ void CSVWorld::CommandDelegate::setModelDataImp (QWidget *editor, QAbstractItemM QVariant new_ = hack.getData(); 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) -: QStyledItemDelegate (parent), mUndoStack (undoStack), mEditLock (false) +CSVWorld::CommandDelegate::CommandDelegate (CSMDoc::Document& document, QObject *parent) +: QStyledItemDelegate (parent), mDocument (document), mEditLock (false) {} void CSVWorld::CommandDelegate::setModelData (QWidget *editor, QAbstractItemModel *model, @@ -162,8 +169,11 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return new QDoubleSpinBox(parent); case CSMWorld::ColumnBase::Display_LongString: - - return new QTextEdit(parent); + { + QPlainTextEdit *edit = new QPlainTextEdit(parent); + edit->setUndoRedoEnabled (false); + return edit; + } case CSMWorld::ColumnBase::Display_Boolean: @@ -188,6 +198,10 @@ QWidget *CSVWorld::CommandDelegate::createEditor (QWidget *parent, const QStyleO return new DropLineEdit(parent); + case CSMWorld::ColumnBase::Display_ScriptLines: + + return new ScriptEdit (mDocument, ScriptHighlighter::Mode_Console, parent); + default: return QStyledItemDelegate::createEditor (parent, option, index); diff --git a/apps/opencs/view/world/util.hpp b/apps/opencs/view/world/util.hpp index c95a24982..b4d972bf3 100644 --- a/apps/opencs/view/world/util.hpp +++ b/apps/opencs/view/world/util.hpp @@ -51,7 +51,8 @@ namespace CSVWorld 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. }; @@ -77,7 +78,7 @@ namespace CSVWorld /// /// 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; ///< The ownership of the returned CommandDelegate is transferred to the caller. /// @@ -110,19 +111,21 @@ namespace CSVWorld { Q_OBJECT - QUndoStack& mUndoStack; + CSMDoc::Document& mDocument; bool mEditLock; protected: QUndoStack& getUndoStack() const; + CSMDoc::Document& getDocument() const; + virtual void setModelDataImp (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; public: - CommandDelegate (QUndoStack& undoStack, QObject *parent); + CommandDelegate (CSMDoc::Document& document, QObject *parent); virtual void setModelData (QWidget *editor, QAbstractItemModel *model, const QModelIndex& index) const; diff --git a/apps/opencs/view/world/vartypedelegate.cpp b/apps/opencs/view/world/vartypedelegate.cpp index fc00f4491..c3c98b800 100644 --- a/apps/opencs/view/world/vartypedelegate.cpp +++ b/apps/opencs/view/world/vartypedelegate.cpp @@ -47,8 +47,8 @@ void CSVWorld::VarTypeDelegate::addCommands (QAbstractItemModel *model, const QM } CSVWorld::VarTypeDelegate::VarTypeDelegate (const std::vector >& values, - QUndoStack& undoStack, QObject *parent) -: EnumDelegate (values, undoStack, parent) + CSMDoc::Document& document, QObject *parent) +: EnumDelegate (values, document, parent) {} @@ -68,10 +68,10 @@ CSVWorld::VarTypeDelegateFactory::VarTypeDelegateFactory (ESM::VarType type0, add (type3); } -CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate (QUndoStack& undoStack, - QObject *parent) const +CSVWorld::CommandDelegate *CSVWorld::VarTypeDelegateFactory::makeDelegate ( + 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) diff --git a/apps/opencs/view/world/vartypedelegate.hpp b/apps/opencs/view/world/vartypedelegate.hpp index c8493f029..c86b936f6 100644 --- a/apps/opencs/view/world/vartypedelegate.hpp +++ b/apps/opencs/view/world/vartypedelegate.hpp @@ -17,7 +17,7 @@ namespace CSVWorld public: VarTypeDelegate (const std::vector >& values, - QUndoStack& undoStack, QObject *parent); + CSMDoc::Document& document, QObject *parent); }; class VarTypeDelegateFactory : public CommandDelegateFactory @@ -30,7 +30,7 @@ namespace CSVWorld ESM::VarType type1 = ESM::VT_Unknown, ESM::VarType type2 = 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. void add (ESM::VarType type); diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 9cf2c4b24..ff583fe5c 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -64,7 +64,7 @@ add_openmw_dir (mwworld cells localscripts customdata weather inventorystore ptr actionopen actionread actionequip timestamp actionalchemy cellstore actionapply actioneat 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 @@ -109,7 +109,7 @@ if (NOT ANDROID) ${APPLE_BUNDLE_RESOURCES} ) else () - add_library(openmw + add_library(openmw SHARED ${OPENMW_LIBS} ${OPENMW_LIBS_HEADER} ${OPENMW_FILES} @@ -139,18 +139,18 @@ target_link_libraries(openmw if (ANDROID) target_link_libraries(openmw - ${OGRE_STATIC_PLUGINS} + ${OGRE_STATIC_PLUGINS} EGL android log - dl + dl MyGUI.OgrePlatform MyGUIEngineStatic Plugin_StrangeButtonStatic cpufeatures BulletCollision BulletDynamics - LinearMath + LinearMath ) endif (ANDROID) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 1247ceda1..3b805da74 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -186,6 +186,7 @@ OMW::Engine::Engine(Files::ConfigurationManager& configurationManager) , mGrab(true) , mScriptBlacklistUse (true) , mExportFonts(false) + , mNewGame (false) { std::srand ( std::time(NULL) ); MWClass::registerClasses(); @@ -268,9 +269,10 @@ void OMW::Engine::setScriptsVerbosity(bool scriptsVerbosity) mVerboseScripts = scriptsVerbosity; } -void OMW::Engine::setSkipMenu (bool skipMenu) +void OMW::Engine::setSkipMenu (bool skipMenu, bool newGame) { mSkipMenu = skipMenu; + mNewGame = newGame; } std::string OMW::Engine::loadSettings (Settings::Manager & settings) @@ -474,7 +476,7 @@ void OMW::Engine::go() } else { - MWBase::Environment::get().getStateManager()->newGame (true); + MWBase::Environment::get().getStateManager()->newGame (!mNewGame); } // Start the main rendering loop diff --git a/apps/openmw/engine.hpp b/apps/openmw/engine.hpp index e5f3e5f99..0ee5a09c5 100644 --- a/apps/openmw/engine.hpp +++ b/apps/openmw/engine.hpp @@ -95,6 +95,7 @@ namespace OMW Translation::Storage mTranslationDataStorage; std::vector mScriptBlacklist; bool mScriptBlacklistUse; + bool mNewGame; Nif::Cache mNifCache; @@ -157,7 +158,11 @@ namespace OMW /// Disable or enable all sounds 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; } diff --git a/apps/openmw/main.cpp b/apps/openmw/main.cpp index 57b3e045e..ebadeb732 100644 --- a/apps/openmw/main.cpp +++ b/apps/openmw/main.cpp @@ -105,7 +105,7 @@ bool parseOptions (int argc, char** argv, OMW::Engine& engine, Files::Configurat ("help", "print help message") ("version", "print version information and quit") ("data", bpo::value()->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()->default_value(""), "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()->implicit_value(true) ->default_value(false), "skip main menu on game startup") + ("new-game", bpo::value()->implicit_value(true) + ->default_value(false), "run new game sequence (ignored if skip-menu=0)") + ("fs-strict", bpo::value()->implicit_value(true) ->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 engine.setCell(variables["start"].as()); - engine.setSkipMenu (variables["skip-menu"].as()); + engine.setSkipMenu (variables["skip-menu"].as(), variables["new-game"].as()); + if (!variables["skip-menu"].as() && variables["new-game"].as()) + std::cerr << "new-game used without skip-menu -> ignoring it" << std::endl; // scripts engine.setCompileAll(variables["script-all"].as()); diff --git a/apps/openmw/mwworld/esmstore.cpp b/apps/openmw/mwworld/esmstore.cpp index 12831e7dc..1b5d3d1e9 100644 --- a/apps/openmw/mwworld/esmstore.cpp +++ b/apps/openmw/mwworld/esmstore.cpp @@ -81,7 +81,13 @@ void ESMStore::load(ESM::ESMReader &esm, Loading::Listener* listener) mMagicEffects.load (esm); } else if (n.val == ESM::REC_SKIL) { 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; error << "Unknown record: " << n.toString(); throw std::runtime_error(error.str()); diff --git a/apps/openmw/mwworld/omwloader.cpp b/apps/openmw/mwworld/omwloader.cpp deleted file mode 100644 index 8562a4fe0..000000000 --- a/apps/openmw/mwworld/omwloader.cpp +++ /dev/null @@ -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 */ - diff --git a/apps/openmw/mwworld/omwloader.hpp b/apps/openmw/mwworld/omwloader.hpp deleted file mode 100644 index cb9faa430..000000000 --- a/apps/openmw/mwworld/omwloader.hpp +++ /dev/null @@ -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 */ diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index b27560eab..4a2f79b0d 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -51,7 +51,6 @@ #include "contentloader.hpp" #include "esmloader.hpp" -#include "omwloader.hpp" using namespace Ogre; @@ -170,12 +169,12 @@ namespace MWWorld GameContentLoader gameContentLoader(*listener); EsmLoader esmLoader(mStore, mEsm, encoder, *listener); - OmwLoader omwLoader(*listener); gameContentLoader.addLoader(".esm", &esmLoader); gameContentLoader.addLoader(".esp", &esmLoader); - gameContentLoader.addLoader(".omwgame", &omwLoader); - gameContentLoader.addLoader(".omwaddon", &omwLoader); + gameContentLoader.addLoader(".omwgame", &esmLoader); + gameContentLoader.addLoader(".omwaddon", &esmLoader); + gameContentLoader.addLoader(".project", &esmLoader); loadContentFiles(fileCollections, contentFiles, gameContentLoader); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 50d11e9bb..f5e31190e 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -45,7 +45,7 @@ add_component_dir (esm loadnpc loadpgrd loadrace loadregn loadscpt loadskil loadsndg loadsoun loadspel loadsscr loadstat 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 - npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate + npcstats creaturestats weatherstate quickkeys fogstate spellstate activespells creaturelevliststate doorstate projectilestate debugprofile aisequence magiceffects ) diff --git a/components/esm/debugprofile.cpp b/components/esm/debugprofile.cpp new file mode 100644 index 000000000..6c05fac2a --- /dev/null +++ b/components/esm/debugprofile.cpp @@ -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; +} diff --git a/components/esm/debugprofile.hpp b/components/esm/debugprofile.hpp new file mode 100644 index 000000000..b54e8ff5f --- /dev/null +++ b/components/esm/debugprofile.hpp @@ -0,0 +1,38 @@ +#ifndef COMPONENTS_ESM_DEBUGPROFILE_H +#define COMPONENTS_ESM_DEBUGPROFILE_H + +#include + +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 diff --git a/components/esm/defs.hpp b/components/esm/defs.hpp index 6ef0f77fb..67461d467 100644 --- a/components/esm/defs.hpp +++ b/components/esm/defs.hpp @@ -115,7 +115,8 @@ enum RecNameInts REC_MARK = FourCC<'M','A','R','K'>::value, // format 1 - REC_FILT = 0x544C4946 + REC_FILT = 0x544C4946, + REC_DBGP = FourCC<'D','B','G','P'>::value ///< only used in project files }; } diff --git a/components/esm/loadscpt.cpp b/components/esm/loadscpt.cpp index f3813adca..5a7d65775 100644 --- a/components/esm/loadscpt.cpp +++ b/components/esm/loadscpt.cpp @@ -124,7 +124,11 @@ void Script::save(ESMWriter &esm) const mVarNames.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"; } } diff --git a/readme.txt b/readme.txt index d66206df5..6078227c3 100644 --- a/readme.txt +++ b/readme.txt @@ -73,6 +73,8 @@ Allowed options: correctly compiled anyway 2 - treat warnings as errors --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 folding) --encoding arg (=win1252) Character encoding used in OpenMW game