Merge remote-tracking branch 'upstream/master'

This commit is contained in:
mrcheko 2014-05-22 10:34:04 +04:00
commit 48431c841f
285 changed files with 6155 additions and 3689 deletions

View file

@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 29)
set(OPENMW_VERSION_MINOR 30)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_VERSION_COMMITHASH "")
@ -36,18 +36,8 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}")
set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}")
if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
message(FATAL_ERROR "Silly Zini forgot to update the version again...")
else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR})
set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR})
set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE})
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
message(STATUS "OpenMW version ${OPENMW_VERSION}")
else(MATCH)
@ -345,8 +335,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg
"${OpenMW_BINARY_DIR}/opencs.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini
"${OpenMW_BINARY_DIR}/opencs.ini")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
@ -427,7 +417,7 @@ IF(NOT WIN32 AND NOT APPLE)
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
IF(BUILD_OPENCS)
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs")
ENDIF(BUILD_OPENCS)
# Install resources
@ -456,7 +446,7 @@ if(WIN32)
ENDIF(BUILD_MWINIIMPORTER)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".")
ENDIF(BUILD_OPENCS)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
@ -594,6 +584,7 @@ if (WIN32)
4706 # Assignment in conditional expression
4738 # Storing 32-bit float result in memory, possible loss of performance
4986 # Undocumented warning that occurs in the crtdbg.h file
4987 # nonstandard extension used (triggered by setjmp.h)
4996 # Function was declared deprecated
# cause by ogre extensivly
@ -610,7 +601,9 @@ if (WIN32)
4305 # Truncating value (double to float, for example)
4309 # Variable overflow, trying to store 128 in a signed char for example
4355 # Using 'this' in member initialization list
4505 # Unreferenced local function has been removed
4701 # Potentially uninitialized local variable used
4702 # Unreachable code
4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt
)
@ -618,19 +611,31 @@ if (WIN32)
set(WARNINGS "${WARNINGS} /wd${d}")
endforeach(d)
set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS})
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${SHINY_WARNINGS})
# there's an unreferenced local variable in the ogre platform, suppress it
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${SHINY_OGRE_WARNINGS})
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(oics PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_LAUNCHER)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_LAUNCHER)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_BSATOOL)
if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_BSATOOL)
endif (BUILD_BSATOOL)
if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_ESMTOOL)
if (BUILD_OPENCS)
set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_OPENCS)
if (BUILD_MWINIIMPORTER)
set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_MWINIIMPORTER)
endif(MSVC)
# Same for MinGW
@ -663,7 +668,7 @@ if (APPLE)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})

View file

@ -651,7 +651,7 @@ void Record<ESM::Dialogue>::print()
// Sadly, there are no DialInfos, because the loader dumps as it
// loads, rather than loading and then dumping. :-( Anyone mind if
// I change this?
std::vector<ESM::DialInfo>::iterator iit;
ESM::Dialogue::InfoContainer::iterator iit;
for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); iit++)
std::cout << "INFO!" << iit->mId << std::endl;
}

View file

@ -5,11 +5,11 @@ opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc
document operation saving
document operation saving documentmanager loader
)
opencs_units_noqt (model/doc
documentmanager stage savingstate savingstages
stage savingstate savingstages
)
opencs_hdrs_noqt (model/doc
@ -44,7 +44,7 @@ opencs_units_noqt (model/tools
opencs_units (view/doc
viewmanager view operations operation subview startup filedialog newgame
filewidget adjusterwidget
filewidget adjusterwidget loader
)
@ -106,7 +106,6 @@ opencs_units_noqt (view/settings
opencs_units (model/settings
usersettings
settingmanager
setting
connector
)

View file

@ -20,14 +20,14 @@
#include "model/world/data.hpp"
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
: mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager),
mIpcServerName ("org.openmw.OpenCS")
{
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
setupDataFiles (config.first);
CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg");
CSMSettings::UserSettings::instance().loadSettings ("opencs.ini");
mSettings.setModel (CSMSettings::UserSettings::instance());
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
@ -38,6 +38,11 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal);
connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)),
this, SLOT (documentAdded (CSMDoc::Document *)));
connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()),
this, SLOT (lastDocumentDeleted()));
connect (&mViewManager, SIGNAL (newGameRequest ()), this, SLOT (createGame ()));
connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ()));
connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ()));
@ -85,6 +90,9 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
mCfgMgr.readConfiguration(variables, desc);
mDocumentManager.setEncoding (
ToUTF8::calculateEncoding (variables["encoding"].as<std::string>()));
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
mFsStrict = variables["fs-strict"].as<bool>();
@ -124,11 +132,6 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
QString path = QString::fromUtf8 (iter->string().c_str());
mFileDialog.addFiles(path);
}
/*
//load the settings into the userSettings instance.
const QString settingFileName = "opencs.cfg";
CSMSettings::UserSettings::instance().loadSettings(settingFileName);
*/
return std::make_pair (dataDirs, variables["fallback-archive"].as<std::vector<std::string> >());
}
@ -163,9 +166,8 @@ void CS::Editor::openFiles (const boost::filesystem::path &savePath)
foreach (const QString &path, mFileDialog.selectedFilePaths())
files.push_back(path.toUtf8().constData());
CSMDoc::Document *document = mDocumentManager.addDocument (files, savePath, false);
mDocumentManager.addDocument (files, savePath, false);
mViewManager.addView (document);
mFileDialog.hide();
}
@ -179,9 +181,8 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath)
files.push_back(mFileDialog.filename().toUtf8().constData());
CSMDoc::Document *document = mDocumentManager.addDocument (files, savePath, true);
mDocumentManager.addDocument (files, savePath, true);
mViewManager.addView (document);
mFileDialog.hide();
}
@ -191,9 +192,7 @@ void CS::Editor::createNewGame (const boost::filesystem::path& file)
files.push_back (file);
CSMDoc::Document *document = mDocumentManager.addDocument (files, file, true);
mViewManager.addView (document);
mDocumentManager.addDocument (files, file, true);
mNewGame.hide();
}
@ -300,3 +299,13 @@ std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
return factory;
}
void CS::Editor::documentAdded (CSMDoc::Document *document)
{
mViewManager.addView (document);
}
void CS::Editor::lastDocumentDeleted()
{
exit (0);
}

View file

@ -85,6 +85,10 @@ namespace CS
void showSettings();
void documentAdded (CSMDoc::Document *document);
void lastDocumentDeleted();
private:
QString mIpcServerName;

View file

@ -3,18 +3,24 @@
#include <exception>
#include <iostream>
#include <string>
#include <QApplication>
#include <QIcon>
#include <QMetaType>
#include <extern/shiny/Main/Factory.hpp>
#include <components/ogreinit/ogreinit.hpp>
#include "model/world/universalid.hpp"
#ifdef Q_OS_MAC
#include <QDir>
#endif
Q_DECLARE_METATYPE (std::string)
class Application : public QApplication
{
private:
@ -42,6 +48,9 @@ int main(int argc, char *argv[])
{
Q_INIT_RESOURCE (resources);
qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
OgreInit::OgreInit ogreInit;
std::auto_ptr<sh::Factory> shinyFactory;

View file

@ -8,23 +8,6 @@
#include <components/files/configurationmanager.hpp>
#endif
void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin,
const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified)
{
assert (begin!=end);
std::vector<boost::filesystem::path>::const_iterator end2 (end);
if (lastAsModified)
--end2;
for (std::vector<boost::filesystem::path>::const_iterator iter (begin); iter!=end2; ++iter)
getData().loadFile (*iter, true, false);
if (lastAsModified)
getData().loadFile (*end2, false, false);
}
void CSMDoc::Document::addGmsts()
{
static const char *gmstFloats[] =
@ -2219,64 +2202,42 @@ void CSMDoc::Document::createBase()
}
}
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_)
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath)
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding)
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding), mTools (mData),
mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding)
{
if (files.empty())
if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence");
if (new_ && files.size()==1)
createBase();
else
{
std::vector<boost::filesystem::path>::const_iterator end = files.end();
if (new_)
--end;
load (files.begin(), end, !new_);
}
if (new_)
{
mData.setDescription ("");
mData.setAuthor ("");
}
bool filtersFound = false;
if (boost::filesystem::exists (mProjectPath))
{
filtersFound = true;
}
else
if (!boost::filesystem::exists (mProjectPath))
{
boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
locCustomFiltersPath /= "defaultfilters";
if (boost::filesystem::exists(locCustomFiltersPath))
if (boost::filesystem::exists (locCustomFiltersPath))
{
boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath);
filtersFound = true;
}
else
{
boost::filesystem::path filters(mResDir);
filters /= "defaultfilters";
if (boost::filesystem::exists(filters))
{
boost::filesystem::copy_file(filters, mProjectPath);
filtersFound = true;
}
boost::filesystem::copy_file (mResDir / "defaultfilters", mProjectPath);
}
}
if (filtersFound)
getData().loadFile (mProjectPath, false, true);
if (mNew)
{
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1)
createBase();
}
addOptionalGmsts();
addOptionalGlobals();
@ -2288,8 +2249,10 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, co
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 (reportMessage (const QString&, int)),
this, SLOT (reportMessage (const QString&, int)));
connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)));
}
CSMDoc::Document::~Document()
@ -2322,11 +2285,21 @@ const boost::filesystem::path& CSMDoc::Document::getSavePath() const
return mSavePath;
}
const boost::filesystem::path& CSMDoc::Document::getProjectPath() const
{
return mProjectPath;
}
const std::vector<boost::filesystem::path>& CSMDoc::Document::getContentFiles() const
{
return mContentFiles;
}
bool CSMDoc::Document::isNew() const
{
return mNew;
}
void CSMDoc::Document::save()
{
if (mSaving.isRunning())
@ -2358,10 +2331,11 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
emit stateChanged (getState(), this);
}
void CSMDoc::Document::reportMessage (const QString& message, int type)
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type)
{
/// \todo find a better way to get these messages to the user.
std::cout << message.toUtf8().constData() << std::endl;
std::cout << message << std::endl;
}
void CSMDoc::Document::operationDone (int type)

View file

@ -9,6 +9,8 @@
#include <QObject>
#include <QTimer>
#include <components/to_utf8/to_utf8.hpp>
#include "../world/data.hpp"
#include "../tools/tools.hpp"
@ -39,6 +41,7 @@ namespace CSMDoc
boost::filesystem::path mSavePath;
std::vector<boost::filesystem::path> mContentFiles;
bool mNew;
CSMWorld::Data mData;
CSMTools::Tools mTools;
boost::filesystem::path mProjectPath;
@ -53,10 +56,6 @@ namespace CSMDoc
Document (const Document&);
Document& operator= (const Document&);
void load (const std::vector<boost::filesystem::path>::const_iterator& begin,
const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified);
///< \param lastAsModified Store the last file in Modified instead of merging it into Base.
void createBase();
void addGmsts();
@ -72,9 +71,9 @@ namespace CSMDoc
public:
Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath,
const boost::filesystem::path& resDir, bool new_);
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding);
~Document();
@ -84,10 +83,15 @@ namespace CSMDoc
const boost::filesystem::path& getSavePath() const;
const boost::filesystem::path& getProjectPath() const;
const std::vector<boost::filesystem::path>& getContentFiles() const;
///< \attention The last element in this collection is the file that is being edited,
/// but with its original path instead of the save path.
bool isNew() const;
///< Is this a newly created content file?
void save();
CSMWorld::UniversalId verify();
@ -111,7 +115,8 @@ namespace CSMDoc
void modificationStateChanged (bool clean);
void reportMessage (const QString& message, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type);
void operationDone (int type);

View file

@ -13,44 +13,88 @@
#include "document.hpp"
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
: mConfiguration (configuration)
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252)
{
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
if (!boost::filesystem::is_directory (projectPath))
boost::filesystem::create_directories (projectPath);
mLoader.moveToThread (&mLoaderThread);
mLoaderThread.start();
connect (&mLoader, SIGNAL (documentLoaded (Document *)),
this, SLOT (documentLoaded (Document *)));
connect (&mLoader, SIGNAL (documentNotLoaded (Document *, const std::string&)),
this, SLOT (documentNotLoaded (Document *, const std::string&)));
connect (this, SIGNAL (loadRequest (CSMDoc::Document *)),
&mLoader, SLOT (loadDocument (CSMDoc::Document *)));
connect (&mLoader, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)),
this, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)));
connect (&mLoader, SIGNAL (nextRecord (CSMDoc::Document *)),
this, SIGNAL (nextRecord (CSMDoc::Document *)));
connect (this, SIGNAL (cancelLoading (CSMDoc::Document *)),
&mLoader, SLOT (abortLoading (CSMDoc::Document *)));
connect (&mLoader, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)),
this, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)));
}
CSMDoc::DocumentManager::~DocumentManager()
{
mLoaderThread.quit();
mLoader.hasThingsToDo().wakeAll();
mLoaderThread.wait();
for (std::vector<Document *>::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter)
delete *iter;
}
CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
bool new_)
{
Document *document = new Document (mConfiguration, files, savePath, mResDir, new_);
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding);
mDocuments.push_back (document);
return document;
emit loadRequest (document);
mLoader.hasThingsToDo().wakeAll();
}
bool CSMDoc::DocumentManager::removeDocument (Document *document)
void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document)
{
std::vector<Document *>::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document);
if (iter==mDocuments.end())
throw std::runtime_error ("removing invalid document");
throw std::runtime_error ("removing invalid document");
mDocuments.erase (iter);
delete document;
return mDocuments.empty();
if (mDocuments.empty())
emit lastDocumentDeleted();
}
void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir)
{
mResDir = boost::filesystem::system_complete(parResDir);
}
void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding)
{
mEncoding = encoding;
}
void CSMDoc::DocumentManager::documentLoaded (Document *document)
{
emit documentAdded (document);
emit loadingStopped (document, true, "");
}
void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std::string& error)
{
emit loadingStopped (document, false, error);
if (error.empty()) // do not remove the document yet, if we have an error
removeDocument (document);
}

View file

@ -6,6 +6,13 @@
#include <boost/filesystem/path.hpp>
#include <QObject>
#include <QThread>
#include <components/to_utf8/to_utf8.hpp>
#include "loader.hpp"
namespace Files
{
class ConfigurationManager;
@ -15,10 +22,15 @@ namespace CSMDoc
{
class Document;
class DocumentManager
class DocumentManager : public QObject
{
Q_OBJECT
std::vector<Document *> mDocuments;
const Files::ConfigurationManager& mConfiguration;
QThread mLoaderThread;
Loader mLoader;
ToUTF8::FromType mEncoding;
DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&);
@ -29,20 +41,51 @@ namespace CSMDoc
~DocumentManager();
Document *addDocument (const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath,
bool new_);
///< The ownership of the returned document is not transferred to the caller.
///
/// \param new_ Do not load the last content file in \a files and instead create in an
void addDocument (const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath, bool new_);
///< \param new_ Do not load the last content file in \a files and instead create in an
/// appropriate way.
bool removeDocument (Document *document);
///< \return last document removed?
void setResourceDir (const boost::filesystem::path& parResDir);
private:
void setEncoding (ToUTF8::FromType encoding);
private:
boost::filesystem::path mResDir;
private slots:
void documentLoaded (Document *document);
///< The ownership of \a document is not transferred.
void documentNotLoaded (Document *document, const std::string& error);
///< Document load has been interrupted either because of a call to abortLoading
/// or a problem during loading). In the former case error will be an empty string.
public slots:
void removeDocument (CSMDoc::Document *document);
///< Emits the lastDocumentDeleted signal, if applicable.
signals:
void documentAdded (CSMDoc::Document *document);
void loadRequest (CSMDoc::Document *document);
void lastDocumentDeleted();
void loadingStopped (CSMDoc::Document *document, bool completed,
const std::string& error);
void nextStage (CSMDoc::Document *document, const std::string& name, int steps);
void nextRecord (CSMDoc::Document *document);
void cancelLoading (CSMDoc::Document *document);
void loadMessage (CSMDoc::Document *document, const std::string& message);
};
}

View file

@ -0,0 +1,130 @@
#include "loader.hpp"
#include <QTimer>
#include "../tools/reportmodel.hpp"
#include "document.hpp"
#include "state.hpp"
CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLeft (false) {}
CSMDoc::Loader::Loader()
{
QTimer *timer = new QTimer (this);
connect (timer, SIGNAL (timeout()), this, SLOT (load()));
timer->start();
}
QWaitCondition& CSMDoc::Loader::hasThingsToDo()
{
return mThingsToDo;
}
void CSMDoc::Loader::load()
{
if (mDocuments.empty())
{
mMutex.lock();
mThingsToDo.wait (&mMutex);
mMutex.unlock();
return;
}
std::vector<std::pair<Document *, Stage> >::iterator iter = mDocuments.begin();
Document *document = iter->first;
int size = static_cast<int> (document->getContentFiles().size());
if (document->isNew())
--size;
bool done = false;
const int batchingSize = 100;
try
{
if (iter->second.mRecordsLeft)
{
CSMDoc::Stage::Messages messages;
for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals
if (document->getData().continueLoading (messages))
{
iter->second.mRecordsLeft = false;
break;
}
CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0);
for (CSMDoc::Stage::Messages::const_iterator iter (messages.begin());
iter!=messages.end(); ++iter)
{
document->getReport (log)->add (iter->first, iter->second);
emit loadMessage (document, iter->second);
}
emit nextRecord (document);
return;
}
if (iter->second.mFile<size)
{
boost::filesystem::path path = document->getContentFiles()[iter->second.mFile];
int steps = document->getData().startLoading (path, iter->second.mFile<size-1, false);
iter->second.mRecordsLeft = true;
emit nextStage (document, path.filename().string(), steps/batchingSize);
}
else if (iter->second.mFile==size)
{
int steps = document->getData().startLoading (document->getProjectPath(), false, true);
iter->second.mRecordsLeft = true;
emit nextStage (document, "Project File", steps/batchingSize);
}
else
{
done = true;
}
++(iter->second.mFile);
}
catch (const std::exception& e)
{
mDocuments.erase (iter);
emit documentNotLoaded (document, e.what());
return;
}
if (done)
{
mDocuments.erase (iter);
emit documentLoaded (document);
}
}
void CSMDoc::Loader::loadDocument (CSMDoc::Document *document)
{
mDocuments.push_back (std::make_pair (document, Stage()));
}
void CSMDoc::Loader::abortLoading (CSMDoc::Document *document)
{
for (std::vector<std::pair<Document *, Stage> >::iterator iter = mDocuments.begin();
iter!=mDocuments.end(); ++iter)
{
if (iter->first==document)
{
mDocuments.erase (iter);
emit documentNotLoaded (document, "");
break;
}
}
}

View file

@ -0,0 +1,71 @@
#ifndef CSM_DOC_LOADER_H
#define CSM_DOC_LOADER_H
#include <vector>
#include <QObject>
#include <QMutex>
#include <QWaitCondition>
namespace CSMDoc
{
class Document;
class Loader : public QObject
{
Q_OBJECT
struct Stage
{
int mFile;
bool mRecordsLeft;
Stage();
};
QMutex mMutex;
QWaitCondition mThingsToDo;
std::vector<std::pair<Document *, Stage> > mDocuments;
public:
Loader();
QWaitCondition& hasThingsToDo();
private slots:
void load();
public slots:
void loadDocument (CSMDoc::Document *document);
///< The ownership of \a document is not transferred.
void abortLoading (CSMDoc::Document *document);
///< Abort loading \a docuemnt (ignored if \a document has already finished being
/// loaded). Will result in a documentNotLoaded signal, once the Loader has finished
/// cleaning up.
signals:
void documentLoaded (Document *document);
///< The ownership of \a document is not transferred.
void documentNotLoaded (Document *document, const std::string& error);
///< Document load has been interrupted either because of a call to abortLoading
/// or a problem during loading). In the former case error will be an empty string.
void nextStage (CSMDoc::Document *document, const std::string& name, int steps);
void nextRecord (CSMDoc::Document *document);
///< \note This signal is only given once per group of records. The group size is
/// approximately the total number of records divided by the steps value of the
/// previous nextStage signal.
void loadMessage (CSMDoc::Document *document, const std::string& message);
///< Non-critical load error or warning
};
}
#endif

View file

@ -6,6 +6,8 @@
#include <QTimer>
#include "../world/universalid.hpp"
#include "state.hpp"
#include "stage.hpp"
@ -80,7 +82,7 @@ void CSMDoc::Operation::abort()
void CSMDoc::Operation::executeStage()
{
std::vector<std::string> messages;
Stage::Messages messages;
while (mCurrentStage!=mStages.end())
{
@ -97,7 +99,7 @@ void CSMDoc::Operation::executeStage()
}
catch (const std::exception& e)
{
emit reportMessage (e.what(), mType);
emit reportMessage (CSMWorld::UniversalId(), e.what(), mType);
abort();
}
@ -108,8 +110,8 @@ void CSMDoc::Operation::executeStage()
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
for (std::vector<std::string>::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter)
emit reportMessage (iter->c_str(), mType);
for (Stage::Messages::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter)
emit reportMessage (iter->first, iter->second, mType);
if (mCurrentStage==mStages.end())
exit();

View file

@ -5,6 +5,11 @@
#include <QThread>
namespace CSMWorld
{
class UniversalId;
}
namespace CSMDoc
{
class Stage;
@ -46,7 +51,8 @@ namespace CSMDoc
void progress (int current, int max, int type);
void reportMessage (const QString& message, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type);
void done (int type);

View file

@ -8,8 +8,9 @@
#include "savingstages.hpp"
#include "document.hpp"
CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath)
: Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath)
CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath,
ToUTF8::FromType encoding)
: Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath, encoding)
{
// save project file
appendStage (new OpenSaveStage (mDocument, mState, true));

View file

@ -3,6 +3,8 @@
#include <boost/filesystem/path.hpp>
#include <components/to_utf8/to_utf8.hpp>
#include "operation.hpp"
#include "savingstate.hpp"
@ -19,7 +21,8 @@ namespace CSMDoc
public:
Saving (Document& document, const boost::filesystem::path& projectPath);
Saving (Document& document, const boost::filesystem::path& projectPath,
ToUTF8::FromType encoding);
};
}

View file

@ -23,7 +23,7 @@ int CSMDoc::OpenSaveStage::setup()
return 1;
}
void CSMDoc::OpenSaveStage::perform (int stage, std::vector<std::string>& messages)
void CSMDoc::OpenSaveStage::perform (int stage, Messages& messages)
{
mState.start (mDocument, mProjectFile);
@ -43,7 +43,7 @@ int CSMDoc::WriteHeaderStage::setup()
return 1;
}
void CSMDoc::WriteHeaderStage::perform (int stage, std::vector<std::string>& messages)
void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages)
{
mState.getWriter().setVersion();
@ -96,7 +96,7 @@ int CSMDoc::WriteDialogueCollectionStage::setup()
return mTopics.getSize();
}
void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::string>& messages)
void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Dialogue>& topic = mTopics.getRecord (stage);
@ -191,7 +191,7 @@ int CSMDoc::WriteRefIdCollectionStage::setup()
return mDocument.getData().getReferenceables().getSize();
}
void CSMDoc::WriteRefIdCollectionStage::perform (int stage, std::vector<std::string>& messages)
void CSMDoc::WriteRefIdCollectionStage::perform (int stage, Messages& messages)
{
mDocument.getData().getReferenceables().save (stage, mState.getWriter());
}
@ -204,7 +204,7 @@ CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& sta
mDocument (document), mScope (scope)
{}
void CSMDoc::WriteFilterStage::perform (int stage, std::vector<std::string>& messages)
void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<CSMFilter::Filter>& record =
mDocument.getData().getFilters().getRecord (stage);
@ -223,7 +223,7 @@ int CSMDoc::CloseSaveStage::setup()
return 1;
}
void CSMDoc::CloseSaveStage::perform (int stage, std::vector<std::string>& messages)
void CSMDoc::CloseSaveStage::perform (int stage, Messages& messages)
{
mState.getStream().close();
@ -241,7 +241,7 @@ int CSMDoc::FinalSavingStage::setup()
return 1;
}
void CSMDoc::FinalSavingStage::perform (int stage, std::vector<std::string>& messages)
void CSMDoc::FinalSavingStage::perform (int stage, Messages& messages)
{
if (mState.hasError())
{

View file

@ -39,7 +39,7 @@ namespace CSMDoc
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
@ -57,7 +57,7 @@ namespace CSMDoc
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
@ -75,7 +75,7 @@ namespace CSMDoc
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
@ -92,7 +92,7 @@ namespace CSMDoc
}
template<class CollectionT>
void WriteCollectionStage<CollectionT>::perform (int stage, std::vector<std::string>& messages)
void WriteCollectionStage<CollectionT>::perform (int stage, Messages& messages)
{
CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState;
@ -130,7 +130,7 @@ namespace CSMDoc
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
@ -147,7 +147,7 @@ namespace CSMDoc
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
@ -161,7 +161,7 @@ namespace CSMDoc
WriteFilterStage (Document& document, SavingState& state, CSMFilter::Filter::Scope scope);
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
@ -177,7 +177,7 @@ namespace CSMDoc
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
@ -193,7 +193,7 @@ namespace CSMDoc
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
}

View file

@ -4,11 +4,9 @@
#include "operation.hpp"
#include "document.hpp"
CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath)
: mOperation (operation),
/// \todo set encoding properly, once config implementation has been fixed.
mEncoder (ToUTF8::calculateEncoding ("win1252")),
mProjectPath (projectPath), mProjectFile (false)
CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath,
ToUTF8::FromType encoding)
: mOperation (operation), mEncoder (encoding), mProjectPath (projectPath), mProjectFile (false)
{
mWriter.setEncoder (&mEncoder);
}

View file

@ -7,6 +7,8 @@
#include <components/esm/esmwriter.hpp>
#include <components/to_utf8/to_utf8.hpp>
namespace CSMDoc
{
class Operation;
@ -25,7 +27,8 @@ namespace CSMDoc
public:
SavingState (Operation& operation, const boost::filesystem::path& projectPath);
SavingState (Operation& operation, const boost::filesystem::path& projectPath,
ToUTF8::FromType encoding);
bool hasError() const;

View file

@ -4,18 +4,22 @@
#include <vector>
#include <string>
#include "../world/universalid.hpp"
namespace CSMDoc
{
class Stage
{
public:
typedef std::vector<std::pair<CSMWorld::UniversalId, std::string> > Messages;
virtual ~Stage();
virtual int setup() = 0;
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages) = 0;
virtual void perform (int stage, Messages& messages) = 0;
///< Messages resulting from this stage will be appended to \a messages.
};
}

View file

@ -3,17 +3,18 @@
namespace CSMDoc
{
enum State
{
State_Modified = 1,
State_Locked = 2,
State_Operation = 4,
enum State
{
State_Modified = 1,
State_Locked = 2,
State_Operation = 4,
State_Saving = 8,
State_Verifying = 16,
State_Compiling = 32, // not implemented yet
State_Searching = 64 // not implemented yet
};
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
};
}
#endif

View file

@ -81,6 +81,7 @@ void CSMSettings::Connector::slotUpdateMaster() const
}
QString masterValue = mMasterView->value (masterColumn);
mMasterView->setSelectedValue (masterValue);
}

View file

@ -20,34 +20,46 @@ namespace CSMSettings {
CSVSettings::View *mMasterView;
//map using the view pointer as a key to it's index value
///map using the view pointer as a key to it's index value
QList <CSVSettings::View *> mSlaveViews;
//list of proxy values for each master value.
//value list order is indexed to the master value index.
///list of proxy values for each master value.
///value list order is indexed to the master value index.
QMap < QString, QList <QStringList> > mProxyListMap;
public:
explicit Connector(CSVSettings::View *master,
QObject *parent = 0);
///Set the view which acts as a proxy for other setting views
void setMasterView (CSVSettings::View *view);
///Add a view to be updated / update to the master
void addSlaveView (CSVSettings::View *view,
QList <QStringList> &masterProxyValues);
private:
///loosely matches lists of proxy values across registered slaves
///against a proxy value list for a given master value
bool proxyListsMatch (const QList <QStringList> &list1,
const QList <QStringList> &list2) const;
///loosely matches two string lists
bool stringListsMatch (const QStringList &list1,
const QStringList &list2) const;
///retrieves current values of registered slave views
QList <QStringList> getSlaveViewValues() const;
public slots:
///updates slave views with proxy values associated with current
///master value
void slotUpdateSlaves() const;
///updates master value associated with the currently selected
///slave values, if applicable.
void slotUpdateMaster() const;
};
}

View file

@ -45,7 +45,7 @@ void CSMSettings::Setting::addProxy (const Setting *setting,
foreach (const QString &val, vals)
list << (QStringList() << val);
mProxies [setting->page() + '.' + setting->name()] = list;
mProxies [setting->page() + '/' + setting->name()] = list;
}
void CSMSettings::Setting::addProxy (const Setting *setting,
@ -54,7 +54,7 @@ void CSMSettings::Setting::addProxy (const Setting *setting,
if (serializable())
setProperty (Property_Serializable, false);
mProxies [setting->page() + '.' + setting->name()] = list;
mProxies [setting->page() + '/' + setting->name()] = list;
}
void CSMSettings::Setting::setColumnSpan (int value)
@ -77,16 +77,6 @@ QStringList CSMSettings::Setting::declaredValues() const
return property (Property_DeclaredValues);
}
void CSMSettings::Setting::setDefinedValues (QStringList list)
{
setProperty (Property_DefinedValues, list);
}
QStringList CSMSettings::Setting::definedValues() const
{
return property (Property_DefinedValues);
}
QStringList CSMSettings::Setting::property (SettingProperty prop) const
{
if (prop >= mProperties.size())

View file

@ -7,11 +7,17 @@
namespace CSMSettings
{
//Maps setting id ("page.name") to a list of corresponding proxy values.
//Order of proxy value stringlists corresponds to order of master proxy's
//values in it's declared value list
//QString is the setting id in the form of "page/name"
//QList is a list of stringlists of proxy values.
//Order is important! Proxy stringlists are matched against
//master values by their position in the QList.
typedef QMap <QString, QList <QStringList> > ProxyValueMap;
///Setting class is the interface for the User Settings. It contains
///a great deal of boiler plate to provide the core API functions, as
///well as the property() functions which use enumeration to be iterable.
///This makes the Setting class capable of being manipulated by script.
///See CSMSettings::support.hpp for enumerations / string values.
class Setting
{
QList <QStringList> mProperties;
@ -19,10 +25,6 @@ namespace CSMSettings
bool mIsEditorSetting;
//QString is the setting id in the form of "page.name"
//QList is a list of stringlists of proxy values.
//Order is important! Proxy stringlists are matched against
//master values by their position in the QList.
ProxyValueMap mProxies;
public:
@ -42,9 +44,6 @@ namespace CSMSettings
void setDeclaredValues (QStringList list);
QStringList declaredValues() const;
void setDefinedValues (QStringList list);
QStringList definedValues() const;
void setDefaultValue (int value);
void setDefaultValue (double value);
void setDefaultValue (const QString &value);

View file

@ -1,342 +0,0 @@
#include <QFile>
#include <QTextCodec>
#include <QMessageBox>
#include <QDebug>
#include <QList>
#include "setting.hpp"
#include "settingmanager.hpp"
CSMSettings::SettingManager::SettingManager(QObject *parent) :
QObject(parent)
{
mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for \
writing</b><br><br> Please make sure you have the right\
permissions and try again.<br>");
mReadOnlyMessage = QObject::tr("<br><b>Could not open file for \
reading</b><br><br> Please make sure you have the \
right permissions and try again.<br>");
}
void CSMSettings::SettingManager::dumpModel()
{
foreach (Setting *setting, mSettings)
{
if (setting->proxyLists().isEmpty())
continue;
}
}
CSMSettings::Setting *CSMSettings::SettingManager::createSetting
(CSMSettings::SettingType typ, const QString &page, const QString &name)
{
//get list of all settings for the current setting name
if (findSetting (page, name))
{
qWarning() << "Duplicate declaration encountered: "
<< (name + '.' + page);
return 0;
}
Setting *setting = new Setting (typ, name, page);
//add declaration to the model
mSettings.append (setting);
return setting;
}
CSMSettings::DefinitionPageMap
CSMSettings::SettingManager::readFilestream (QTextStream *stream)
{
//regEx's for page names and keys / values
QRegExp pageRegEx ("^\\[([^]]+)\\]");
QRegExp keyRegEx ("^([^=]+)\\s*=\\s*(.+)$");
QString currPage = "Unassigned";
DefinitionPageMap pageMap;
if (!stream)
{
displayFileErrorMessage(mReadWriteMessage, false);
return pageMap;
}
if (stream->atEnd())
return pageMap;
DefinitionMap *settingMap = new DefinitionMap();
pageMap[currPage] = settingMap;
while (!stream->atEnd())
{
QString line = stream->readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
//page name found
if (pageRegEx.exactMatch(line))
{
currPage = pageRegEx.cap(1).simplified().trimmed();
settingMap = new DefinitionMap();
pageMap[currPage] = settingMap;
continue;
}
//setting definition found
if ( (keyRegEx.indexIn(line) != -1))
{
QString settingName = keyRegEx.cap(1).simplified();
QString settingValue = keyRegEx.cap(2).simplified();
if (!settingMap->contains (settingName))
settingMap->insert (settingName, new QStringList());
settingMap->value(settingName)->append(settingValue);
}
}
//return empty map if no settings were ever added to
if (pageMap.size() == 1)
{
QString pageKey = pageMap.keys().at(0);
if (pageMap[pageKey]->size() == 0)
pageMap.clear();
}
return pageMap;
}
bool CSMSettings::SettingManager::writeFilestream(QTextStream *stream,
const QMap <QString, QStringList > &settingListMap)
{
if (!stream)
{
displayFileErrorMessage(mReadWriteMessage, false);
return false;
}
//disabled after rolling selector class into view. Need to
//iterate views to get setting definitions before writing to file
QStringList sectionKeys;
foreach (const QString &key, settingListMap.keys())
{
QStringList names = key.split('.');
QString section = names.at(0);
if (!sectionKeys.contains(section))
if (!settingListMap.value(key).isEmpty())
sectionKeys.append (section);
}
foreach (const QString &section, sectionKeys)
{
*stream << '[' << section << "]\n";
foreach (const QString &key, settingListMap.keys())
{
QStringList names = key.split('.');
if (names.at(0) != section)
continue;
QStringList list = settingListMap.value(key);
if (list.isEmpty())
continue;
QString name = names.at(1);
foreach (const QString value, list)
{
if (value.isEmpty())
continue;
*stream << name << " = " << value << '\n';
}
}
}
destroyStream (stream);
return true;
}
void CSMSettings::SettingManager::mergeSettings(DefinitionPageMap &destMap, DefinitionPageMap &srcMap)
{
if (srcMap.isEmpty())
return;
foreach (const QString &pageKey, srcMap.keys())
{
DefinitionMap *srcSetting = srcMap.value(pageKey);
//Unique Page:
//insertfrom the source map
if (!destMap.keys().contains (pageKey))
{
destMap.insert (pageKey, srcSetting);
continue;
}
DefinitionMap *destSetting = destMap.value(pageKey);
//Duplicate Page:
//iterate the settings in the source and check for duplicates in the
//destination
foreach (const QString &srcKey, srcSetting->keys())
{
//insert into destination if unique
if (!destSetting->keys().contains (srcKey))
destSetting->insert(srcKey, srcSetting->value (srcKey));
}
}
}
QTextStream *CSMSettings::SettingManager::openFilestream (const QString &filePath,
bool isReadOnly) const
{
QIODevice::OpenMode openFlags = QIODevice::Text;
if (isReadOnly)
openFlags = QIODevice::ReadOnly | openFlags;
else
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
QFile *file = new QFile(filePath);
QTextStream *stream = 0;
if (file->open(openFlags))
stream = new QTextStream(file);
if (stream)
stream->setCodec(QTextCodec::codecForName("UTF-8"));
return stream;
}
void CSMSettings::SettingManager::destroyStream(QTextStream *stream) const
{
stream->device()->close();
delete stream;
}
void CSMSettings::SettingManager::displayFileErrorMessage(const QString &message,
bool isReadOnly) const
{
// File cannot be opened or created
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
if (!isReadOnly)
msgBox.setText (mReadWriteMessage + message);
else
msgBox.setText (message);
msgBox.exec();
}
void CSMSettings::SettingManager::addDefinitions (DefinitionPageMap &pageMap)
{
foreach (QString pageName, pageMap.keys())
{
DefinitionMap *settingMap = pageMap.value (pageName);
foreach (QString settingName, (*settingMap).keys())
{
QStringList *values = settingMap->value (settingName);
Setting *setting = findSetting (pageName, settingName);
if (!setting)
{
qWarning() << "Found definitions for undeclared setting "
<< pageName << "." << settingName;
continue;
}
if (values->size() == 0)
values->append (setting->defaultValues());
setting->setDefinedValues (*values);
}
}
}
QList <CSMSettings::Setting *> CSMSettings::SettingManager::findSettings
(const QStringList &list)
{
QList <CSMSettings::Setting *> settings;
foreach (const QString &value, list)
{
QStringList names = value.split(".", QString::SkipEmptyParts);
if (names.size() != 2)
continue;
Setting *setting = findSetting (names.at(0), names.at(1));
if (!setting)
continue;
settings.append (setting);
}
return settings;
}
CSMSettings::Setting *CSMSettings::SettingManager::findSetting
(const QString &pageName, const QString &settingName)
{
foreach (Setting *setting, mSettings)
{
if (setting->name() == settingName)
{
if (setting->page() == pageName)
return setting;
}
}
return 0;
}
QList <CSMSettings::Setting *> CSMSettings::SettingManager::findSettings
(const QString &pageName)
{
QList <CSMSettings::Setting *> settings;
foreach (Setting *setting, mSettings)
{
if (setting->page() == pageName)
settings.append (setting);
}
return settings;
}
CSMSettings::SettingPageMap CSMSettings::SettingManager::settingPageMap() const
{
SettingPageMap pageMap;
foreach (Setting *setting, mSettings)
pageMap[setting->page()].append (setting);
return pageMap;
}
void CSMSettings::SettingManager::updateUserSetting(const QString &settingKey,
const QStringList &list)
{
QStringList names = settingKey.split('.');
Setting *setting = findSetting (names.at(0), names.at(1));
setting->setDefinedValues (list);
emit userSettingUpdated (settingKey, list);
}

View file

@ -1,84 +0,0 @@
#ifndef CSMSETTINGS_SETTINGMANAGER_HPP
#define CSMSETTINGS_SETTINGMANAGER_HPP
#include <QObject>
#include <QMap>
#include <QStringList>
#include <QTextStream>
#include "support.hpp"
#include "setting.hpp"
namespace CSMSettings
{
typedef QMap <QString, QStringList *> DefinitionMap;
typedef QMap <QString, DefinitionMap *> DefinitionPageMap;
typedef QMap <QString, QList <Setting *> > SettingPageMap;
class SettingManager : public QObject
{
Q_OBJECT
QString mReadOnlyMessage;
QString mReadWriteMessage;
QList <Setting *> mSettings;
public:
explicit SettingManager(QObject *parent = 0);
///retrieve a setting object from a given page and setting name
Setting *findSetting
(const QString &pageName, const QString &settingName);
///retrieve all settings for a specified page
QList <Setting *> findSettings (const QString &pageName);
///retrieve all settings named in the attached list.
///Setting names are specified in "PageName.SettingName" format.
QList <Setting *> findSettings (const QStringList &list);
///Retreive a map of the settings, keyed by page name
SettingPageMap settingPageMap() const;
protected:
///add a new setting to the model and return it
Setting *createSetting (CSMSettings::SettingType typ,
const QString &page, const QString &name);
///add definitions to the settings specified in the page map
void addDefinitions (DefinitionPageMap &pageMap);
///read setting definitions from file
DefinitionPageMap readFilestream(QTextStream *stream);
///write setting definitions to file
bool writeFilestream (QTextStream *stream,
const QMap <QString, QStringList > &settingMap);
///merge PageMaps of settings when loading from multiple files
void mergeSettings (DefinitionPageMap &destMap, DefinitionPageMap &srcMap);
QTextStream *openFilestream (const QString &filePath,
bool isReadOnly) const;
void destroyStream(QTextStream *stream) const;
void displayFileErrorMessage(const QString &message,
bool isReadOnly) const;
QList <Setting *> settings() const { return mSettings; }
void dumpModel();
signals:
void userSettingUpdated (const QString &, const QStringList &);
public slots:
void updateUserSetting (const QString &, const QStringList &);
};
}
#endif // CSMSETTINGS_SETTINGMANAGER_HPP

View file

@ -7,22 +7,10 @@
#include <QVariant>
#include <QStringList>
//Typedefs
namespace CSMSettings
{
// Definition / Declaration model typedefs
// "Pair" = Setting name and specific data
// "ListItem" = Page name and associated setting pair
typedef QPair <QString, QString> StringPair;
typedef QPair <QString, QStringList> StringListPair;
typedef QList <StringListPair> StringListPairs;
}
//Enums
namespace CSMSettings
{
///Enumerated properties for scripting
enum SettingProperty
{
Property_Name = 0,
@ -55,6 +43,7 @@ namespace CSMSettings
Property_Proxies = 25
};
///Basic setting widget types.
enum SettingType
{
/*
@ -82,16 +71,11 @@ namespace CSMSettings
Type_Undefined = 40
};
enum MergeMethod
{
Merge_Accept,
Merge_Ignore,
Merge_Overwrite
};
}
namespace CSVSettings
{
///Categorical view types which encompass the setting widget types
enum ViewType
{
ViewType_Boolean = 0,
@ -100,18 +84,12 @@ namespace CSVSettings
ViewType_Text = 3,
ViewType_Undefined = 4
};
enum Alignment
{
Align_Left = Qt::AlignLeft,
Align_Center = Qt::AlignHCenter,
Align_Right = Qt::AlignRight
};
}
namespace CSMSettings
{
///used to construct default settings in the Setting class
struct PropertyDefaultValues
{
int id;
@ -119,6 +97,9 @@ namespace CSMSettings
QVariant value;
};
///strings which correspond to setting values. These strings represent
///the script language keywords which would be used to declare setting
///views for 3rd party addons
const QString sPropertyNames[] =
{
"name", "page", "setting_type", "is_multi_value",
@ -129,6 +110,7 @@ namespace CSMSettings
"defaults", "declarations", "definitions", "proxies"
};
///Default values for a setting. Used in setting creation.
const QString sPropertyDefaults[] =
{
"", //name

View file

@ -1,21 +1,14 @@
#include "usersettings.hpp"
#include <QTextStream>
#include <QDir>
#include <QString>
#include <QRegExp>
#include <QMap>
#include <QMessageBox>
#include <QTextCodec>
#include <QSettings>
#include <QFile>
#include <QSortFilterProxyModel>
#include <components/files/configurationmanager.hpp>
#include <boost/version.hpp>
#include "setting.hpp"
#include "support.hpp"
#include <QDebug>
/**
* Workaround for problems with whitespaces in paths in older versions of Boost library
@ -35,11 +28,14 @@ namespace boost
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0;
CSMSettings::UserSettings::UserSettings()
CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager)
: mCfgMgr (configurationManager)
{
assert(!mUserSettingsInstance);
mUserSettingsInstance = this;
mSettingDefinitions = 0;
buildSettingModelDefaults();
}
@ -119,18 +115,19 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
* Defined values
*
* Values which represent the actual, current value of
* a setting. For settings with declared values, this must be one or
* several declared values, as appropriate.
* a setting. For settings with declared values, this must be one
* or several declared values, as appropriate.
*
* Proxy values - values the proxy master updates the proxy slave when
* it's own definition is set / changed. These are definitions for
* proxy slave settings, but must match any declared values the proxy
* slave has, if any.
* Proxy values
* Values the proxy master updates the proxy slave when
* it's own definition is set / changed. These are definitions for
* proxy slave settings, but must match any declared values the
* proxy slave has, if any.
*******************************************************************/
/*
//create setting objects, specifying the basic widget type,
//the page name, and the view name
/*
Setting *masterBoolean = createSetting (Type_RadioButton, section,
"Master Proxy");
@ -230,6 +227,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
slaveIntegerSpinbox->setSerializable (false);
slaveDoubleSpinbox->setSerializable (false);
slaveSlider->setSerializable (false);
slaveDial->setSerializable (false);
slaveBoolean->setDefaultValues (QStringList()
<< "One" << "Three" << "Five");
@ -283,82 +281,60 @@ CSMSettings::UserSettings::~UserSettings()
void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{
mUserFilePath = QString::fromUtf8
(mCfgMgr.getUserConfigPath().string().c_str()) + fileName.toUtf8();
QString userFilePath = QString::fromUtf8
(mCfgMgr.getUserConfigPath().string().c_str());
QString global = QString::fromUtf8
(mCfgMgr.getGlobalPath().string().c_str()) + fileName.toUtf8();
QString globalFilePath = QString::fromUtf8
(mCfgMgr.getGlobalPath().string().c_str());
QString local = QString::fromUtf8
(mCfgMgr.getLocalPath().string().c_str()) + fileName.toUtf8();
QString otherFilePath = globalFilePath;
//open user and global streams
QTextStream *userStream = openFilestream (mUserFilePath, true);
QTextStream *otherStream = openFilestream (global, true);
//failed stream, try for local
if (!otherStream)
otherStream = openFilestream (local, true);
//error condition - notify and return
if (!otherStream || !userStream)
//test for local only if global fails (uninstalled copy)
if (!QFile (globalFilePath + fileName).exists())
{
QString message = QObject::tr("<br><b>An error was encountered loading \
user settings files.</b><br><br> One or several files could not \
be read. This may be caused by a missing configuration file, \
incorrect file permissions or a corrupted installation of \
OpenCS.<br>");
message += QObject::tr("<br>Global filepath: ") + global;
message += QObject::tr("<br>Local filepath: ") + local;
message += QObject::tr("<br>User filepath: ") + mUserFilePath;
displayFileErrorMessage ( message, true);
return;
//if global is invalid, use the local path
otherFilePath = QString::fromUtf8
(mCfgMgr.getLocalPath().string().c_str());
}
//success condition - merge the two streams into a single map and save
DefinitionPageMap totalMap = readFilestream (userStream);
DefinitionPageMap otherMap = readFilestream(otherStream);
QSettings::setPath
(QSettings::IniFormat, QSettings::UserScope, userFilePath);
//merging other settings file in and ignore duplicate settings to
//avoid overwriting user-level settings
mergeSettings (totalMap, otherMap);
QSettings::setPath
(QSettings::IniFormat, QSettings::SystemScope, otherFilePath);
if (!totalMap.isEmpty())
addDefinitions (totalMap);
mSettingDefinitions = new QSettings
(QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this);
}
void CSMSettings::UserSettings::saveSettings
(const QMap <QString, QStringList> &settingMap)
bool CSMSettings::UserSettings::hasSettingDefinitions
(const QString &viewKey) const
{
for (int i = 0; i < settings().size(); i++)
{
Setting* setting = settings().at(i);
return (mSettingDefinitions->contains (viewKey));
}
QString key = setting->page() + '.' + setting->name();
void CSMSettings::UserSettings::setDefinitions
(const QString &key, const QStringList &list)
{
mSettingDefinitions->setValue (key, list);
}
if (!settingMap.keys().contains(key))
continue;
setting->setDefinedValues (settingMap.value(key));
}
writeFilestream (openFilestream (mUserFilePath, false), settingMap);
void CSMSettings::UserSettings::saveDefinitions() const
{
mSettingDefinitions->sync();
}
QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
{
QStringList names = settingKey.split('.');
if (!mSettingDefinitions->contains (settingKey))
return QString();
Setting *setting = findSetting(names.at(0), names.at(1));
QStringList defs = mSettingDefinitions->value (settingKey).toStringList();
if (setting)
{
if (!setting->definedValues().isEmpty())
return setting->definedValues().at(0);
}
return "";
if (defs.isEmpty())
return QString();
return defs.at(0);
}
CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
@ -366,3 +342,86 @@ CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
assert(mUserSettingsInstance);
return *mUserSettingsInstance;
}
void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
const QStringList &list)
{
mSettingDefinitions->setValue (settingKey ,list);
emit userSettingUpdated (settingKey, list);
}
CSMSettings::Setting *CSMSettings::UserSettings::findSetting
(const QString &pageName, const QString &settingName)
{
foreach (Setting *setting, mSettings)
{
if (setting->name() == settingName)
{
if (setting->page() == pageName)
return setting;
}
}
return 0;
}
void CSMSettings::UserSettings::removeSetting
(const QString &pageName, const QString &settingName)
{
if (mSettings.isEmpty())
return;
QList <Setting *>::iterator removeIterator = mSettings.begin();
while (removeIterator != mSettings.end())
{
if ((*removeIterator)->name() == settingName)
{
if ((*removeIterator)->page() == pageName)
{
mSettings.erase (removeIterator);
break;
}
}
removeIterator++;
}
}
CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const
{
SettingPageMap pageMap;
foreach (Setting *setting, mSettings)
pageMap[setting->page()].append (setting);
return pageMap;
}
CSMSettings::Setting *CSMSettings::UserSettings::createSetting
(CSMSettings::SettingType typ, const QString &page, const QString &name)
{
//get list of all settings for the current setting name
if (findSetting (page, name))
{
qWarning() << "Duplicate declaration encountered: "
<< (name + '/' + page);
return 0;
}
Setting *setting = new Setting (typ, name, page);
//add declaration to the model
mSettings.append (setting);
return setting;
}
QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const
{
if (mSettingDefinitions->contains (viewKey))
return mSettingDefinitions->value (viewKey).toStringList();
return QStringList();
}

View file

@ -1,14 +1,13 @@
#ifndef USERSETTINGS_HPP
#define USERSETTINGS_HPP
#include <QTextStream>
#include <QList>
#include <QStringList>
#include <QString>
#include <QMap>
#include <boost/filesystem/path.hpp>
#include "settingmanager.hpp"
#include "support.hpp"
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
@ -18,46 +17,79 @@ namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
struct ConfigurationManager;}
class QFile;
class QSettings;
namespace CSMSettings {
class UserSettings: public SettingManager
class Setting;
typedef QMap <QString, QList <Setting *> > SettingPageMap;
class UserSettings: public QObject
{
Q_OBJECT
static UserSettings *mUserSettingsInstance;
QString mUserFilePath;
Files::ConfigurationManager mCfgMgr;
const Files::ConfigurationManager& mCfgMgr;
QString mReadOnlyMessage;
QString mReadWriteMessage;
QSettings *mSettingDefinitions;
QList <Setting *> mSettings;
public:
/// Singleton implementation
static UserSettings& instance();
UserSettings();
UserSettings (const Files::ConfigurationManager& configurationManager);
~UserSettings();
UserSettings (UserSettings const &); //not implemented
void operator= (UserSettings const &); //not implemented
/// Writes settings to the last loaded settings file
bool writeSettings();
UserSettings (UserSettings const &); //not implemented
UserSettings& operator= (UserSettings const &); //not implemented
/// Retrieves the settings file at all three levels (global, local and user).
void loadSettings (const QString &fileName);
/// Writes settings to the user's config file path
void saveSettings (const QMap <QString, QStringList > &settingMap);
/// Updates QSettings and syncs with the ini file
void setDefinitions (const QString &key, const QStringList &defs);
QString settingValue (const QString &settingKey);
///retrieve a setting object from a given page and setting name
Setting *findSetting
(const QString &pageName, const QString &settingName = QString());
///remove a setting from the list
void removeSetting
(const QString &pageName, const QString &settingName);
///Retreive a map of the settings, keyed by page name
SettingPageMap settingPageMap() const;
///Returns a string list of defined vlaues for the specified setting
///in "page/name" format.
QStringList definitions (const QString &viewKey) const;
///Test to indicate whether or not a setting has any definitions
bool hasSettingDefinitions (const QString &viewKey) const;
///Save any unsaved changes in the QSettings object
void saveDefinitions() const;
private:
void buildSettingModelDefaults();
///add a new setting to the model and return it
Setting *createSetting (CSMSettings::SettingType typ,
const QString &page, const QString &name);
signals:
void userSettingUpdated (const QString &, const QStringList &);
public slots:
void updateUserSetting (const QString &, const QStringList &);
};
}
#endif // USERSETTINGS_HPP

View file

@ -17,7 +17,7 @@ int CSMTools::BirthsignCheckStage::setup()
return mBirthsigns.getSize();
}
void CSMTools::BirthsignCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::BirthsignCheckStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::BirthSign>& record = mBirthsigns.getRecord (stage);
@ -30,13 +30,13 @@ void CSMTools::BirthsignCheckStage::perform (int stage, std::vector<std::string>
// test for empty name, description and texture
if (birthsign.mName.empty())
messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty name");
messages.push_back (std::make_pair (id, birthsign.mId + " has an empty name"));
if (birthsign.mDescription.empty())
messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty description");
messages.push_back (std::make_pair (id, birthsign.mId + " has an empty description"));
if (birthsign.mTexture.empty())
messages.push_back (id.toString() + "|" + birthsign.mId + " is missing a texture");
messages.push_back (std::make_pair (id, birthsign.mId + " is missing a texture"));
/// \todo test if the texture exists

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -18,7 +18,7 @@ int CSMTools::ClassCheckStage::setup()
return mClasses.getSize();
}
void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::ClassCheckStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Class>& record = mClasses.getRecord (stage);
@ -31,10 +31,10 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& me
// test for empty name and description
if (class_.mName.empty())
messages.push_back (id.toString() + "|" + class_.mId + " has an empty name");
messages.push_back (std::make_pair (id, class_.mId + " has an empty name"));
if (class_.mDescription.empty())
messages.push_back (id.toString() + "|" + class_.mId + " has an empty description");
messages.push_back (std::make_pair (id, class_.mId + " has an empty description"));
// test for invalid attributes
for (int i=0; i<2; ++i)
@ -42,18 +42,14 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& me
{
std::ostringstream stream;
stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set";
stream << "Attribute #" << i << " of " << class_.mId << " is not set";
messages.push_back (stream.str());
messages.push_back (std::make_pair (id, stream.str()));
}
if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1)
{
std::ostringstream stream;
stream << id.toString() << "|Class lists same attribute twice";
messages.push_back (stream.str());
messages.push_back (std::make_pair (id, "Class lists same attribute twice"));
}
// test for non-unique skill
@ -66,12 +62,7 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& me
for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
if (iter->second>1)
{
std::ostringstream stream;
stream
<< id.toString() << "|"
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
messages.push_back (stream.str());
messages.push_back (std::make_pair (id,
ESM::Skill::indexToId (iter->first) + " is listed more than once"));
}
}

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -18,7 +18,7 @@ int CSMTools::FactionCheckStage::setup()
return mFactions.getSize();
}
void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::FactionCheckStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Faction>& record = mFactions.getRecord (stage);
@ -31,16 +31,12 @@ void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>&
// test for empty name
if (faction.mName.empty())
messages.push_back (id.toString() + "|" + faction.mId + " has an empty name");
messages.push_back (std::make_pair (id, faction.mId + " has an empty name"));
// test for invalid attributes
if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1)
{
std::ostringstream stream;
stream << id.toString() << "|Faction lists same attribute twice";
messages.push_back (stream.str());
messages.push_back (std::make_pair (id , "Faction lists same attribute twice"));
}
// test for non-unique skill
@ -53,13 +49,8 @@ void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>&
for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
if (iter->second>1)
{
std::ostringstream stream;
stream
<< id.toString() << "|"
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
messages.push_back (stream.str());
messages.push_back (std::make_pair (id,
ESM::Skill::indexToId (iter->first) + " is listed more than once"));
}
/// \todo check data members that can't be edited in the table view

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -15,9 +15,10 @@ int CSMTools::MandatoryIdStage::setup()
return mIds.size();
}
void CSMTools::MandatoryIdStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::MandatoryIdStage::perform (int stage, Messages& messages)
{
if (mIdCollection.searchId (mIds.at (stage))==-1 ||
mIdCollection.getRecord (mIds.at (stage)).isDeleted())
messages.push_back (mCollectionId.toString() + "|Missing mandatory record: " + mIds.at (stage));
messages.push_back (std::make_pair (mCollectionId,
"Missing mandatory record: " + mIds.at (stage)));
}

View file

@ -30,7 +30,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -7,7 +7,7 @@
#include "../world/universalid.hpp"
void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::string>& messages)
void CSMTools::RaceCheckStage::performPerRecord (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Race>& record = mRaces.getRecord (stage);
@ -20,24 +20,24 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::str
// test for empty name and description
if (race.mName.empty())
messages.push_back (id.toString() + "|" + race.mId + " has an empty name");
messages.push_back (std::make_pair (id, race.mId + " has an empty name"));
if (race.mDescription.empty())
messages.push_back (id.toString() + "|" + race.mId + " has an empty description");
messages.push_back (std::make_pair (id, race.mId + " has an empty description"));
// test for positive height
if (race.mData.mHeight.mMale<=0)
messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height");
messages.push_back (std::make_pair (id, "male " + race.mId + " has non-positive height"));
if (race.mData.mHeight.mFemale<=0)
messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height");
messages.push_back (std::make_pair (id, "female " + race.mId + " has non-positive height"));
// test for non-negative weight
if (race.mData.mWeight.mMale<0)
messages.push_back (id.toString() + "|male " + race.mId + " has negative weight");
messages.push_back (std::make_pair (id, "male " + race.mId + " has negative weight"));
if (race.mData.mWeight.mFemale<0)
messages.push_back (id.toString() + "|female " + race.mId + " has negative weight");
messages.push_back (std::make_pair (id, "female " + race.mId + " has negative weight"));
// remember playable flag
if (race.mData.mFlags & 0x1)
@ -46,12 +46,12 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::str
/// \todo check data members that can't be edited in the table view
}
void CSMTools::RaceCheckStage::performFinal (std::vector<std::string>& messages)
void CSMTools::RaceCheckStage::performFinal (Messages& messages)
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races);
if (!mPlayable)
messages.push_back (id.toString() + "|No playable race");
messages.push_back (std::make_pair (id, "No playable race"));
}
CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races)
@ -64,7 +64,7 @@ int CSMTools::RaceCheckStage::setup()
return mRaces.getSize()+1;
}
void CSMTools::RaceCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::RaceCheckStage::perform (int stage, Messages& messages)
{
if (stage==mRaces.getSize())
performFinal (messages);

View file

@ -15,9 +15,9 @@ namespace CSMTools
const CSMWorld::IdCollection<ESM::Race>& mRaces;
bool mPlayable;
void performPerRecord (int stage, std::vector<std::string>& messages);
void performPerRecord (int stage, Messages& messages);
void performFinal (std::vector<std::string>& messages);
void performFinal (Messages& messages);
public:
@ -26,7 +26,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -1,7 +1,9 @@
#include "referenceablecheck.hpp"
#include <components/misc/stringops.hpp>
#include "../world/record.hpp"
#include "../world/universalid.hpp"
#include <components/misc/stringops.hpp>
CSMTools::ReferenceableCheckStage::ReferenceableCheckStage(
const CSMWorld::RefIdData& referenceable, const CSMWorld::IdCollection<ESM::Race >& races,
@ -16,7 +18,7 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage(
{
}
void CSMTools::ReferenceableCheckStage::perform(int stage, std::vector< std::string >& messages)
void CSMTools::ReferenceableCheckStage::perform (int stage, Messages& messages)
{
//Checks for books, than, when stage is above mBooksSize goes to other checks, with (stage - PrevSum) as stage.
const int bookSize(mReferencables.getBooks().getSize());
@ -206,11 +208,11 @@ void CSMTools::ReferenceableCheckStage::perform(int stage, std::vector< std::str
staticCheck(stage, mReferencables.getStatics(), messages);
return;
}
stage -= staticSize;
const int creatureSize(mReferencables.getCreatures().getSize());
if (stage < creatureSize)
{
creatureCheck(stage, mReferencables.getCreatures(), messages);
@ -230,7 +232,7 @@ int CSMTools::ReferenceableCheckStage::setup()
void CSMTools::ReferenceableCheckStage::bookCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Book >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -248,7 +250,7 @@ void CSMTools::ReferenceableCheckStage::bookCheck(
void CSMTools::ReferenceableCheckStage::activatorCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Activator >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -262,15 +264,13 @@ void CSMTools::ReferenceableCheckStage::activatorCheck(
//Checking for model, IIRC all activators should have a model
if (activator.mModel.empty())
{
messages.push_back(id.toString() + "|" + activator.mId + " has no model");
}
messages.push_back (std::make_pair (id, activator.mId + " has no model"));
}
void CSMTools::ReferenceableCheckStage::potionCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Potion >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -290,7 +290,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck(
void CSMTools::ReferenceableCheckStage::apparatusCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Apparatus >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -310,7 +310,7 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck(
void CSMTools::ReferenceableCheckStage::armorCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Armor >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -326,21 +326,17 @@ void CSMTools::ReferenceableCheckStage::armorCheck(
//checking for armor class, armor should have poistive armor class, but 0 is considered legal
if (armor.mData.mArmor < 0)
{
messages.push_back(id.toString() + "|" + armor.mId + " has negative armor class");
}
messages.push_back (std::make_pair (id, armor.mId + " has negative armor class"));
//checking for health. Only positive numbers are allowed, or 0 is illegal
if (armor.mData.mHealth <= 0)
{
messages.push_back(id.toString() + "|" + armor.mId + " has non positive health");
}
messages.push_back (std::make_pair (id, armor.mId + " has non positive health"));
}
void CSMTools::ReferenceableCheckStage::clothingCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Clothing >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -357,7 +353,7 @@ void CSMTools::ReferenceableCheckStage::clothingCheck(
void CSMTools::ReferenceableCheckStage::containerCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Container >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -371,153 +367,109 @@ void CSMTools::ReferenceableCheckStage::containerCheck(
//Checking for model, IIRC all containers should have a model
if (container.mModel.empty())
{
messages.push_back(id.toString() + "|" + container.mId + " has no model");
}
messages.push_back (std::make_pair (id, container.mId + " has no model"));
//Checking for capacity (weight)
if (container.mWeight < 0) //0 is allowed
{
messages.push_back(id.toString() + "|" + container.mId + " has negative weight (capacity)");
}
messages.push_back (std::make_pair (id,
container.mId + " has negative weight (capacity)"));
//checking for name
if (container.mName.empty())
{
messages.push_back(id.toString() + "|" + container.mId + " has an empty name");
}
messages.push_back (std::make_pair (id, container.mId + " has an empty name"));
}
void CSMTools::ReferenceableCheckStage::creatureCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Creature >& records,
std::vector< std::string >& messages)
void CSMTools::ReferenceableCheckStage::creatureCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::Creature >& records,
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
{
return;
}
const ESM::Creature& creature = (dynamic_cast<const CSMWorld::Record<ESM::Creature>&>(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Creature, creature.mId);
if (creature.mModel.empty())
{
messages.push_back(id.toString() + "|" + creature.mId + " has no model");
}
messages.push_back (std::make_pair (id, creature.mId + " has no model"));
if (creature.mName.empty())
{
messages.push_back(id.toString() + "|" + creature.mId + " has an empty name");
}
messages.push_back (std::make_pair (id, creature.mId + " has an empty name"));
//stats checks
if (creature.mData.mLevel < 1)
{
messages.push_back(id.toString() + "|" + creature.mId + " has non-postive level");
}
messages.push_back (std::make_pair (id, creature.mId + " has non-postive level"));
if (creature.mData.mStrength < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative strength");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative strength"));
if (creature.mData.mIntelligence < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative intelligence");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative intelligence"));
if (creature.mData.mWillpower < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative willpower");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative willpower"));
if (creature.mData.mAgility < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative agility");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative agility"));
if (creature.mData.mSpeed < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative speed");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative speed"));
if (creature.mData.mEndurance < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative endurance");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative endurance"));
if (creature.mData.mPersonality < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative personality");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative personality"));
if (creature.mData.mLuck < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative luck");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative luck"));
if (creature.mData.mHealth < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative health");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative health"));
if (creature.mData.mSoul < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative soul value");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative soul value"));
for (int i = 0; i < 6; ++i)
{
if (creature.mData.mAttack[i] < 0)
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative attack strength");
messages.push_back (std::make_pair (id,
creature.mId + " has negative attack strength"));
break;
}
}
//TODO, find meaning of other values
if (creature.mData.mGold < 0) //It seems that this is for gold in merchant creatures
{
messages.push_back(id.toString() + "|" + creature.mId + " has negative gold ");
}
messages.push_back (std::make_pair (id, creature.mId + " has negative gold "));
}
void CSMTools::ReferenceableCheckStage::doorCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Door >& records,
std::vector< std::string >& messages)
int stage, const CSMWorld::RefIdDataContainer< ESM::Door >& records,
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
{
return;
}
const ESM::Door& Door = (dynamic_cast<const CSMWorld::Record<ESM::Door>&>(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Door, Door.mId);
//usual, name or model
if (Door.mName.empty())
{
messages.push_back(id.toString() + "|" + Door.mId + " has an empty name");
}
messages.push_back (std::make_pair (id, Door.mId + " has an empty name"));
if (Door.mModel.empty())
{
messages.push_back(id.toString() + "|" + Door.mId + " has no model");
}
//TODO, check what static unsigned int sRecordId; is for
messages.push_back (std::make_pair (id, Door.mId + " has no model"));
}
void CSMTools::ReferenceableCheckStage::ingredientCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Ingredient >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -535,7 +487,7 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck(
void CSMTools::ReferenceableCheckStage::creaturesLevListCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::CreatureLevList >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -553,7 +505,7 @@ void CSMTools::ReferenceableCheckStage::creaturesLevListCheck(
void CSMTools::ReferenceableCheckStage::itemLevelledListCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::ItemLevList >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -569,40 +521,33 @@ void CSMTools::ReferenceableCheckStage::itemLevelledListCheck(
}
void CSMTools::ReferenceableCheckStage::lightCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Light >& records,
std::vector< std::string >& messages)
int stage, const CSMWorld::RefIdDataContainer< ESM::Light >& records,
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
{
return;
}
const ESM::Light& light = (dynamic_cast<const CSMWorld::Record<ESM::Light>& >(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Light, light.mId);
if (light.mData.mRadius < 0)
{
messages.push_back(id.toString() + "|" + light.mId + " has negative light radius");
}
messages.push_back (std::make_pair (id, light.mId + " has negative light radius"));
if (light.mData.mFlags & ESM::Light::Carry)
{
inventoryItemCheck<ESM::Light>(light, messages, id.toString());
if (light.mData.mTime == 0)
{
messages.push_back(id.toString() + "|" + light.mId + " has zero duration");
}
messages.push_back (std::make_pair (id, light.mId + " has zero duration"));
}
}
void CSMTools::ReferenceableCheckStage::lockpickCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Lockpick >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -622,7 +567,7 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck(
void CSMTools::ReferenceableCheckStage::miscCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Miscellaneous >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -637,20 +582,17 @@ void CSMTools::ReferenceableCheckStage::miscCheck(
inventoryItemCheck<ESM::Miscellaneous>(miscellaneous, messages, id.toString());
}
void CSMTools::ReferenceableCheckStage::npcCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::NPC >& records,
std::vector< std::string >& messages)
void CSMTools::ReferenceableCheckStage::npcCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::NPC >& records,
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
if (baseRecord.isDeleted())
{
return;
}
const ESM::NPC& npc = (dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Npc, npc.mId);
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Npc, npc.mId);
short level(npc.mNpdt52.mLevel);
char disposition(npc.mNpdt52.mDisposition);
@ -661,15 +603,13 @@ void CSMTools::ReferenceableCheckStage::npcCheck(
//Detect if player is present
if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl?
{
mPlayerPresent = true;
}
if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated
{
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0008 = autocalculated flag
{
messages.push_back(id.toString() + "|" + npc.mId + " mNpdtType or flags mismatch!"); //should not happend?
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
return;
}
@ -682,145 +622,100 @@ void CSMTools::ReferenceableCheckStage::npcCheck(
else
{
if (npc.mNpdt52.mMana < 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " mana has negative value");
}
messages.push_back (std::make_pair (id, npc.mId + " mana has negative value"));
if (npc.mNpdt52.mFatigue < 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " fatigue has negative value");
}
messages.push_back (std::make_pair (id, npc.mId + " fatigue has negative value"));
if (npc.mNpdt52.mAgility == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " agility has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " agility has zero value"));
if (npc.mNpdt52.mEndurance == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " endurance has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " endurance has zero value"));
if (npc.mNpdt52.mIntelligence == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " intelligence has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " intelligence has zero value"));
if (npc.mNpdt52.mLuck == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " luck has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " luck has zero value"));
if (npc.mNpdt52.mPersonality == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " personality has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " personality has zero value"));
if (npc.mNpdt52.mStrength == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " strength has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " strength has zero value"));
if (npc.mNpdt52.mSpeed == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " speed has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " speed has zero value"));
if (npc.mNpdt52.mWillpower == 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " willpower has zero value");
}
messages.push_back (std::make_pair (id, npc.mId + " willpower has zero value"));
}
if (level < 1)
{
messages.push_back(id.toString() + "|" + npc.mId + " level is non positive");
}
messages.push_back (std::make_pair (id, npc.mId + " level is non positive"));
if (gold < 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " gold has negative value");
}
messages.push_back (std::make_pair (id, npc.mId + " gold has negative value"));
if (npc.mName.empty())
{
messages.push_back(id.toString() + "|" + npc.mId + " has any empty name");
}
messages.push_back (std::make_pair (id, npc.mId + " has any empty name"));
if (npc.mClass.empty())
{
messages.push_back(id.toString() + "|" + npc.mId + " has any empty class");
messages.push_back (std::make_pair (id, npc.mId + " has any empty class"));
}
else //checking if there is such class
else if (mClasses.searchId (npc.mClass) == -1)
{
if (mClasses.searchId(npc.mClass) == -1)
{
messages.push_back(id.toString() + "|" + npc.mId + " has invalid class");
}
messages.push_back (std::make_pair (id, npc.mId + " has invalid class"));
}
if (npc.mRace.empty())
{
messages.push_back(id.toString() + "|" + npc.mId + " has any empty race");
messages.push_back (std::make_pair (id, npc.mId + " has any empty race"));
}
else //checking if there is a such race
else if (mRaces.searchId (npc.mRace) == -1)
{
if (mRaces.searchId(npc.mRace) == -1)
{
messages.push_back(id.toString() + "|" + npc.mId + " has invalid race");
}
messages.push_back (std::make_pair (id, npc.mId + " has invalid race"));
}
if (disposition < 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " has negative disposition");
}
messages.push_back (std::make_pair (id, npc.mId + " has negative disposition"));
if (reputation < 0) //It seems that no character in Morrowind.esm have negative reputation. I'm assuming that negative reputation is invalid
{
messages.push_back(id.toString() + "|" + npc.mId + " has negative reputation");
messages.push_back (std::make_pair (id, npc.mId + " has negative reputation"));
}
if (npc.mFaction.empty() == false)
if (!npc.mFaction.empty())
{
if (rank < 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " has negative rank");
}
messages.push_back (std::make_pair (id, npc.mId + " has negative rank"));
if (mFactions.searchId(npc.mFaction) == -1)
{
messages.push_back(id.toString() + "|" + npc.mId + " has invalid faction");
}
messages.push_back (std::make_pair (id, npc.mId + " has invalid faction"));
}
if (npc.mHead.empty())
{
messages.push_back(id.toString() + "|" + npc.mId + " has no head");
}
messages.push_back (std::make_pair (id, npc.mId + " has no head"));
if (npc.mHair.empty())
{
messages.push_back(id.toString() + "|" + npc.mId + " has no hair");
}
messages.push_back (std::make_pair (id, npc.mId + " has no hair"));
//TODO: reputation, Disposition, rank, everything else
}
void CSMTools::ReferenceableCheckStage::weaponCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Weapon >& records,
std::vector< std::string >& messages)
int stage, const CSMWorld::RefIdDataContainer< ESM::Weapon >& records,
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
if (baseRecord.isDeleted())
{
return;
}
const ESM::Weapon& weapon = (dynamic_cast<const CSMWorld::Record<ESM::Weapon>& >(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Weapon, weapon.mId);
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Weapon, weapon.mId);
//TODO, It seems that this stuff for spellcasting is obligatory and In fact We should check if records are present
if
@ -860,20 +755,17 @@ void CSMTools::ReferenceableCheckStage::weaponCheck(
weapon.mData.mType == ESM::Weapon::Bolt))
{
if (weapon.mData.mSlash[0] > weapon.mData.mSlash[1])
{
messages.push_back(id.toString() + "|" + weapon.mId + " has minimum slash damage higher than maximum");
}
messages.push_back (std::make_pair (id,
weapon.mId + " has minimum slash damage higher than maximum"));
if (weapon.mData.mThrust[0] > weapon.mData.mThrust[1])
{
messages.push_back(id.toString() + "|" + weapon.mId + " has minimum thrust damage higher than maximum");
}
messages.push_back (std::make_pair (id,
weapon.mId + " has minimum thrust damage higher than maximum"));
}
if (weapon.mData.mChop[0] > weapon.mData.mChop[1])
{
messages.push_back(id.toString() + "|" + weapon.mId + " has minimum chop damage higher than maximum");
}
messages.push_back (std::make_pair (id,
weapon.mId + " has minimum chop damage higher than maximum"));
if (!(weapon.mData.mType == ESM::Weapon::Arrow ||
weapon.mData.mType == ESM::Weapon::Bolt ||
@ -881,14 +773,10 @@ void CSMTools::ReferenceableCheckStage::weaponCheck(
{
//checking of health
if (weapon.mData.mHealth <= 0)
{
messages.push_back(id.toString() + "|" + weapon.mId + " has non-positivie health");
}
messages.push_back (std::make_pair (id, weapon.mId + " has non-positivie health"));
if (weapon.mData.mReach < 0)
{
messages.push_back(id.toString() + "|" + weapon.mId + " has negative reach");
}
messages.push_back (std::make_pair (id, weapon.mId + " has negative reach"));
}
}
}
@ -896,7 +784,7 @@ void CSMTools::ReferenceableCheckStage::weaponCheck(
void CSMTools::ReferenceableCheckStage::probeCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Probe >& records,
std::vector< std::string >& messages)
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
@ -912,184 +800,128 @@ void CSMTools::ReferenceableCheckStage::probeCheck(
toolCheck<ESM::Probe>(probe, messages, id.toString(), true);
}
void CSMTools::ReferenceableCheckStage::repairCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Repair >& records,
std::vector< std::string >& messages)
void CSMTools::ReferenceableCheckStage::repairCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::Repair >& records,
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
if (baseRecord.isDeleted())
{
return;
}
const ESM::Repair& repair = (dynamic_cast<const CSMWorld::Record<ESM::Repair>& >(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Repair, repair.mId);
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Repair, repair.mId);
inventoryItemCheck<ESM::Repair>(repair, messages, id.toString());
toolCheck<ESM::Repair>(repair, messages, id.toString(), true);
inventoryItemCheck<ESM::Repair> (repair, messages, id.toString());
toolCheck<ESM::Repair> (repair, messages, id.toString(), true);
}
void CSMTools::ReferenceableCheckStage::staticCheck(
int stage,
const CSMWorld::RefIdDataContainer< ESM::Static >& records,
std::vector< std::string >& messages)
void CSMTools::ReferenceableCheckStage::staticCheck (
int stage, const CSMWorld::RefIdDataContainer< ESM::Static >& records,
Messages& messages)
{
const CSMWorld::RecordBase& baseRecord = records.getRecord(stage);
const CSMWorld::RecordBase& baseRecord = records.getRecord (stage);
if (baseRecord.isDeleted())
{
return;
}
const ESM::Static& staticElement = (dynamic_cast<const CSMWorld::Record<ESM::Static>& >(baseRecord)).get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Static, staticElement.mId);
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Static, staticElement.mId);
if (staticElement.mModel.empty())
{
messages.push_back(id.toString() + "|" + staticElement.mId + " has no model");
}
messages.push_back (std::make_pair (id, staticElement.mId + " has no model"));
}
//final check
void CSMTools::ReferenceableCheckStage::finalCheck(std::vector< std::string >& messages)
void CSMTools::ReferenceableCheckStage::finalCheck (Messages& messages)
{
if (!mPlayerPresent)
{
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Npc);
messages.push_back(id.toString() + "| There is no player record");
}
messages.push_back (std::make_pair (CSMWorld::UniversalId::Type_Referenceables,
"There is no player record"));
}
//Templates begins here
template<typename ITEM> void CSMTools::ReferenceableCheckStage::inventoryItemCheck(
const ITEM& someItem,
std::vector< std::string >& messages,
const std::string& someID, bool enchantable)
template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck (
const Item& someItem, Messages& messages, const std::string& someID, bool enchantable)
{
if (someItem.mName.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has an empty name");
}
messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name"));
//Checking for weight
if (someItem.mData.mWeight < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative weight");
}
messages.push_back (std::make_pair (someID, someItem.mId + " has negative weight"));
//Checking for value
if (someItem.mData.mValue < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative value");
}
//checking for model
if (someItem.mModel.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has no model");
}
//checking for icon
if (someItem.mIcon.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has no icon");
}
if (enchantable)
{
if (someItem.mData.mEnchant < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative enchantment");
}
}
}
template<typename ITEM> void CSMTools::ReferenceableCheckStage::inventoryItemCheck(
const ITEM& someItem,
std::vector< std::string >& messages,
const std::string& someID)
{
if (someItem.mName.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has an empty name");
}
//Checking for weight
if (someItem.mData.mWeight < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative weight");
}
//Checking for value
if (someItem.mData.mValue < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative value");
}
messages.push_back (std::make_pair (someID, someItem.mId + " has negative value"));
//checking for model
if (someItem.mModel.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has no model");
}
messages.push_back (std::make_pair (someID, someItem.mId + " has no model"));
//checking for icon
if (someItem.mIcon.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has no icon");
}
messages.push_back (std::make_pair (someID, someItem.mId + " has no icon"));
if (enchantable && someItem.mData.mEnchant < 0)
messages.push_back (std::make_pair (someID, someItem.mId + " has negative enchantment"));
}
template<typename TOOL> void CSMTools::ReferenceableCheckStage::toolCheck(
const TOOL& someTool,
std::vector< std::string >& messages,
const std::string& someID, bool canBeBroken)
template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck (
const Item& someItem, Messages& messages, const std::string& someID)
{
if (someItem.mName.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name"));
//Checking for weight
if (someItem.mData.mWeight < 0)
messages.push_back (std::make_pair (someID, someItem.mId + " has negative weight"));
//Checking for value
if (someItem.mData.mValue < 0)
messages.push_back (std::make_pair (someID, someItem.mId + " has negative value"));
//checking for model
if (someItem.mModel.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has no model"));
//checking for icon
if (someItem.mIcon.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has no icon"));
}
template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck (
const Tool& someTool, Messages& messages, const std::string& someID, bool canBeBroken)
{
if (someTool.mData.mQuality <= 0)
{
messages.push_back(someID + "|" + someTool.mId + " has non-positive quality");
}
messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality"));
if (canBeBroken)
{
if (someTool.mData.mUses <= 0)
{
messages.push_back(someID + "|" + someTool.mId + " has non-positive uses count");
}
}
if (canBeBroken && someTool.mData.mUses<=0)
messages.push_back (std::make_pair (someID,
someTool.mId + " has non-positive uses count"));
}
template<typename TOOL> void CSMTools::ReferenceableCheckStage::toolCheck(
const TOOL& someTool,
std::vector< std::string >& messages,
const std::string& someID)
template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck (
const Tool& someTool, Messages& messages, const std::string& someID)
{
if (someTool.mData.mQuality <= 0)
{
messages.push_back(someID + "|" + someTool.mId + " has non-positive quality");
}
messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality"));
}
template<typename LIST> void CSMTools::ReferenceableCheckStage::listCheck(
const LIST& someList,
std::vector< std::string >& messages,
const std::string& someID)
template<typename List> void CSMTools::ReferenceableCheckStage::listCheck (
const List& someList, Messages& messages, const std::string& someID)
{
for (unsigned i = 0; i < someList.mList.size(); ++i)
{
if (mReferencables.searchId(someList.mList[i].mId).first == -1)
{
messages.push_back(someID + "|" + someList.mId + " contains item without referencable");
}
messages.push_back (std::make_pair (someID,
someList.mId + " contains item without referencable"));
if (someList.mList[i].mLevel < 1)
{
messages.push_back(someID + "|" + someList.mId + " contains item with non-positive level");
}
messages.push_back (std::make_pair (someID,
someList.mId + " contains item with non-positive level"));
}
}
// kate: indent-mode cstyle; indent-width 4; replace-tabs on;

View file

@ -11,63 +11,64 @@ namespace CSMTools
class ReferenceableCheckStage : public CSMDoc::Stage
{
public:
ReferenceableCheckStage(const CSMWorld::RefIdData& referenceable,
const CSMWorld::IdCollection<ESM::Race>& races,
const CSMWorld::IdCollection<ESM::Class>& classes,
const CSMWorld::IdCollection<ESM::Faction>& factions);
virtual void perform(int stage, std::vector< std::string >& messages);
ReferenceableCheckStage (const CSMWorld::RefIdData& referenceable,
const CSMWorld::IdCollection<ESM::Race>& races,
const CSMWorld::IdCollection<ESM::Class>& classes,
const CSMWorld::IdCollection<ESM::Faction>& factions);
virtual void perform(int stage, Messages& messages);
virtual int setup();
private:
//CONCRETE CHECKS
void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, std::vector< std::string >& messages);
void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, std::vector< std::string >& messages);
void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, std::vector<std::string>& messages);
void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, std::vector<std::string>& messages);
void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, std::vector<std::string>& messages);
void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, std::vector<std::string>& messages);
void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, std::vector<std::string>& messages);
void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, std::vector<std::string>& messages);
void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, std::vector<std::string>& messages);
void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, std::vector<std::string>& messages);
void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, std::vector<std::string>& messages);
void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, std::vector<std::string>& messages);
void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, std::vector<std::string>& messages);
void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, std::vector<std::string>& messages);
void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, std::vector<std::string>& messages);
void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, std::vector<std::string>& messages);
void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, std::vector<std::string>& messages);
void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, std::vector<std::string>& messages);
void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, std::vector<std::string>& messages);
void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, std::vector<std::string>& messages);
void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, Messages& messages);
void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, Messages& messages);
void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, Messages& messages);
void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, Messages& messages);
void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, Messages& messages);
void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, Messages& messages);
void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, Messages& messages);
void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, Messages& messages);
void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, Messages& messages);
void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, Messages& messages);
void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, Messages& messages);
void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, Messages& messages);
void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, Messages& messages);
void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, Messages& messages);
void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, Messages& messages);
void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, Messages& messages);
void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, Messages& messages);
void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, Messages& messages);
void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, Messages& messages);
void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, Messages& messages);
//FINAL CHECK
void finalCheck(std::vector<std::string>& messages);
void finalCheck (Messages& messages);
//TEMPLATE CHECKS
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
std::vector<std::string>& messages,
Messages& messages,
const std::string& someID,
bool enchantable); //for all enchantable items.
template<typename ITEM> void inventoryItemCheck(const ITEM& someItem,
std::vector<std::string>& messages,
Messages& messages,
const std::string& someID); //for non-enchantable items.
template<typename TOOL> void toolCheck(const TOOL& someTool,
std::vector<std::string>& messages,
Messages& messages,
const std::string& someID,
bool canbebroken); //for tools with uses.
template<typename TOOL> void toolCheck(const TOOL& someTool,
std::vector<std::string>& messages,
Messages& messages,
const std::string& someID); //for tools without uses.
template<typename LIST> void listCheck(const LIST& someList,
std::vector< std::string >& messages,
Messages& messages,
const std::string& someID);
const CSMWorld::RefIdData& mReferencables;
const CSMWorld::IdCollection<ESM::Race>& mRaces;
const CSMWorld::IdCollection<ESM::Class>& mClasses;

View file

@ -17,7 +17,7 @@ int CSMTools::RegionCheckStage::setup()
return mRegions.getSize();
}
void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::RegionCheckStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Region>& record = mRegions.getRecord (stage);
@ -30,7 +30,7 @@ void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& m
// test for empty name
if (region.mName.empty())
messages.push_back (id.toString() + "|" + region.mId + " has an empty name");
messages.push_back (std::make_pair (id, region.mId + " has an empty name"));
/// \todo test that the ID in mSleeplist exists

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -51,16 +51,11 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true;
}
void CSMTools::ReportModel::add (const std::string& row)
void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message)
{
std::string::size_type index = row.find ('|');
if (index==std::string::npos)
throw std::logic_error ("invalid report message");
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (std::make_pair (row.substr (0, index), row.substr (index+1)));
mRows.push_back (std::make_pair (id, message));
endInsertRows();
}

View file

@ -28,7 +28,7 @@ namespace CSMTools
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void add (const std::string& row);
void add (const CSMWorld::UniversalId& id, const std::string& message);
const CSMWorld::UniversalId& getUniversalId (int row) const;
};

View file

@ -16,8 +16,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
stream << id.toString() << "|";
if (type==ErrorMessage)
stream << "error ";
else
@ -28,25 +26,15 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
<< ", line " << loc.mLine << ", column " << loc.mColumn
<< " (" << loc.mLiteral << "): " << message;
mMessages->push_back (stream.str());
mMessages->push_back (std::make_pair (id, stream.str()));
}
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
{
std::ostringstream stream;
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
stream << id.toString() << "|";
if (type==ErrorMessage)
stream << "error: ";
else
stream << "warning: ";
stream << message;
mMessages->push_back (stream.str());
mMessages->push_back (std::make_pair (id,
(type==ErrorMessage ? "error: " : "warning: ") + message));
}
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data)
@ -68,7 +56,7 @@ int CSMTools::ScriptCheckStage::setup()
return mData.getScripts().getSize();
}
void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::ScriptCheckStage::perform (int stage, Messages& messages)
{
mMessages = &messages;
mId = mData.getScripts().getId (stage);
@ -90,13 +78,10 @@ void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& m
}
catch (const std::exception& error)
{
std::ostringstream stream;
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
stream << id.toString() << "|Critical compile error: " << error.what();
messages.push_back (stream.str());
messages.push_back (std::make_pair (id,
std::string ("Critical compile error: ") + error.what()));
}
mMessages = 0;

View file

@ -18,7 +18,7 @@ namespace CSMTools
CSMWorld::ScriptContext mContext;
std::string mId;
std::string mFile;
std::vector<std::string> *mMessages;
Messages *mMessages;
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user.
@ -33,7 +33,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -16,7 +16,7 @@ int CSMTools::SkillCheckStage::setup()
return mSkills.getSize();
}
void CSMTools::SkillCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::SkillCheckStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Skill>& record = mSkills.getRecord (stage);
@ -32,11 +32,11 @@ void CSMTools::SkillCheckStage::perform (int stage, std::vector<std::string>& me
{
std::ostringstream stream;
stream << id.toString() << "|Use value #" << i << " of " << skill.mId << " is negative";
stream << "Use value #" << i << " of " << skill.mId << " is negative";
messages.push_back (stream.str());
messages.push_back (std::make_pair (id, stream.str()));
}
if (skill.mDescription.empty())
messages.push_back (id.toString() + "|" + skill.mId + " has an empty description");
messages.push_back (std::make_pair (id, skill.mId + " has an empty description"));
}

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -16,7 +16,7 @@ int CSMTools::SoundCheckStage::setup()
return mSounds.getSize();
}
void CSMTools::SoundCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::SoundCheckStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Sound>& record = mSounds.getRecord (stage);
@ -28,7 +28,7 @@ void CSMTools::SoundCheckStage::perform (int stage, std::vector<std::string>& me
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId);
if (sound.mData.mMinRange>sound.mData.mMaxRange)
messages.push_back (id.toString() + "|Maximum range larger than minimum range");
messages.push_back (std::make_pair (id, "Maximum range larger than minimum range"));
/// \todo check, if the sound file exists
}

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -17,7 +17,7 @@ int CSMTools::SpellCheckStage::setup()
return mSpells.getSize();
}
void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& messages)
void CSMTools::SpellCheckStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<ESM::Spell>& record = mSpells.getRecord (stage);
@ -30,11 +30,11 @@ void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& me
// test for empty name and description
if (spell.mName.empty())
messages.push_back (id.toString() + "|" + spell.mId + " has an empty name");
messages.push_back (std::make_pair (id, spell.mId + " has an empty name"));
// test for invalid cost values
if (spell.mData.mCost<0)
messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs");
messages.push_back (std::make_pair (id, spell.mId + " has a negative spell costs"));
/// \todo check data members that can't be edited in the table view
}

View file

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}

View file

@ -45,8 +45,9 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
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 (reportMessage (const QString&, int)),
this, SLOT (verifierMessage (const QString&, int)));
connect (mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int)));
std::vector<std::string> mandatoryIds; // I want C++11, damn it!
mandatoryIds.push_back ("Day");
@ -87,13 +88,17 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0)
{
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
delete iter->second;
// index 0: load error log
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));
mActiveReports.insert (std::make_pair (CSMDoc::State_Loading, 0));
}
CSMTools::Tools::~Tools()
{
delete mVerifier;
for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter)
delete iter->second;
}
CSMWorld::UniversalId CSMTools::Tools::runVerifier()
@ -132,17 +137,19 @@ int CSMTools::Tools::getRunningOperations() const
CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id)
{
if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults)
if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults &&
id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog)
throw std::logic_error ("invalid request for report model: " + id.toString());
return mReports.at (id.getIndex());
}
void CSMTools::Tools::verifierMessage (const QString& message, int type)
void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type)
{
std::map<int, int>::iterator iter = mActiveReports.find (type);
if (iter!=mActiveReports.end())
mReports[iter->second]->add (message.toUtf8().constData());
mReports[iter->second]->add (id, message);
}

View file

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

View file

@ -55,7 +55,8 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
return number;
}
CSMWorld::Data::Data() : mRefs (mCells)
CSMWorld::Data::Data (ToUTF8::FromType encoding)
: mEncoder (encoding), mRefs (mCells), mReader (0), mDialogue (0)
{
mGlobals.addColumn (new StringIdColumn<ESM::Global>);
mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
@ -260,6 +261,8 @@ CSMWorld::Data::~Data()
{
for (std::vector<QAbstractItemModel *>::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter)
delete *iter;
delete mReader;
}
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
@ -481,148 +484,166 @@ void CSMWorld::Data::merge()
mGlobals.merge();
}
void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, bool project)
int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base, bool project)
{
ESM::ESMReader reader;
delete mReader;
mReader = 0;
mDialogue = 0;
/// \todo set encoding properly, once config implementation has been fixed.
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252"));
reader.setEncoder (&encoder);
mReader = new ESM::ESMReader;
mReader->setEncoder (&mEncoder);
mReader->open (path.string());
reader.open (path.string());
mBase = base;
mProject = project;
const ESM::Dialogue *dialogue = 0;
mAuthor = mReader->getAuthor();
mDescription = mReader->getDesc();
mAuthor = reader.getAuthor();
mDescription = reader.getDesc();
return mReader->getRecordCount();
}
// Note: We do not need to send update signals here, because at this point the model is not connected
// to any view.
while (reader.hasMoreRecs())
bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
{
if (!mReader)
throw std::logic_error ("can't continue loading, because no load has been started");
if (!mReader->hasMoreRecs())
{
ESM::NAME n = reader.getRecName();
reader.getRecHeader();
switch (n.val)
{
case ESM::REC_GLOB: mGlobals.load (reader, base); break;
case ESM::REC_GMST: mGmsts.load (reader, base); break;
case ESM::REC_SKIL: mSkills.load (reader, base); break;
case ESM::REC_CLAS: mClasses.load (reader, base); break;
case ESM::REC_FACT: mFactions.load (reader, base); break;
case ESM::REC_RACE: mRaces.load (reader, base); break;
case ESM::REC_SOUN: mSounds.load (reader, base); break;
case ESM::REC_SCPT: mScripts.load (reader, base); break;
case ESM::REC_REGN: mRegions.load (reader, base); break;
case ESM::REC_BSGN: mBirthsigns.load (reader, base); break;
case ESM::REC_SPEL: mSpells.load (reader, base); break;
case ESM::REC_CELL:
mCells.load (reader, base);
mRefs.load (reader, mCells.getSize()-1, base);
break;
case ESM::REC_ACTI: mReferenceables.load (reader, base, UniversalId::Type_Activator); break;
case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break;
case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break;
case ESM::REC_ARMO: mReferenceables.load (reader, base, UniversalId::Type_Armor); break;
case ESM::REC_BOOK: mReferenceables.load (reader, base, UniversalId::Type_Book); break;
case ESM::REC_CLOT: mReferenceables.load (reader, base, UniversalId::Type_Clothing); break;
case ESM::REC_CONT: mReferenceables.load (reader, base, UniversalId::Type_Container); break;
case ESM::REC_CREA: mReferenceables.load (reader, base, UniversalId::Type_Creature); break;
case ESM::REC_DOOR: mReferenceables.load (reader, base, UniversalId::Type_Door); break;
case ESM::REC_INGR: mReferenceables.load (reader, base, UniversalId::Type_Ingredient); break;
case ESM::REC_LEVC:
mReferenceables.load (reader, base, UniversalId::Type_CreatureLevelledList); break;
case ESM::REC_LEVI:
mReferenceables.load (reader, base, UniversalId::Type_ItemLevelledList); break;
case ESM::REC_LIGH: mReferenceables.load (reader, base, UniversalId::Type_Light); break;
case ESM::REC_LOCK: mReferenceables.load (reader, base, UniversalId::Type_Lockpick); break;
case ESM::REC_MISC:
mReferenceables.load (reader, base, UniversalId::Type_Miscellaneous); break;
case ESM::REC_NPC_: mReferenceables.load (reader, base, UniversalId::Type_Npc); break;
case ESM::REC_PROB: mReferenceables.load (reader, base, UniversalId::Type_Probe); break;
case ESM::REC_REPA: mReferenceables.load (reader, base, UniversalId::Type_Repair); break;
case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break;
case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break;
case ESM::REC_DIAL:
{
std::string id = reader.getHNOString ("NAME");
ESM::Dialogue record;
record.mId = id;
record.load (reader);
if (record.mType==ESM::Dialogue::Journal)
{
mJournals.load (record, base);
dialogue = &mJournals.getRecord (id).get();
}
else if (record.mType==ESM::Dialogue::Deleted)
{
dialogue = 0; // record vector can be shuffled around which would make pointer
// to record invalid
if (mJournals.tryDelete (id))
{
/// \todo handle info records
}
else if (mTopics.tryDelete (id))
{
/// \todo handle info records
}
else
{
/// \todo report deletion of non-existing record
}
}
else
{
mTopics.load (record, base);
dialogue = &mTopics.getRecord (id).get();
}
break;
}
case ESM::REC_INFO:
{
if (!dialogue)
{
/// \todo INFO record without matching DIAL record -> report to user
reader.skipRecord();
break;
}
if (dialogue->mType==ESM::Dialogue::Journal)
mJournalInfos.load (reader, base, *dialogue);
else
mTopicInfos.load (reader, base, *dialogue);
break;
}
case ESM::REC_FILT:
if (project)
{
mFilters.load (reader, base);
mFilters.setData (mFilters.getSize()-1,
mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
static_cast<int> (CSMFilter::Filter::Scope_Project));
break;
}
// fall through (filter record in a content file is an error with format 0)
default:
/// \todo throw an exception instead, once all records are implemented
/// or maybe report error and continue?
reader.skipRecord();
}
delete mReader;
mReader = 0;
mDialogue = 0;
return true;
}
ESM::NAME n = mReader->getRecName();
mReader->getRecHeader();
switch (n.val)
{
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break;
case ESM::REC_SKIL: mSkills.load (*mReader, mBase); break;
case ESM::REC_CLAS: mClasses.load (*mReader, mBase); break;
case ESM::REC_FACT: mFactions.load (*mReader, mBase); break;
case ESM::REC_RACE: mRaces.load (*mReader, mBase); break;
case ESM::REC_SOUN: mSounds.load (*mReader, mBase); break;
case ESM::REC_SCPT: mScripts.load (*mReader, mBase); break;
case ESM::REC_REGN: mRegions.load (*mReader, mBase); break;
case ESM::REC_BSGN: mBirthsigns.load (*mReader, mBase); break;
case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break;
case ESM::REC_CELL:
mCells.load (*mReader, mBase);
mRefs.load (*mReader, mCells.getSize()-1, mBase);
break;
case ESM::REC_ACTI: mReferenceables.load (*mReader, mBase, UniversalId::Type_Activator); break;
case ESM::REC_ALCH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Potion); break;
case ESM::REC_APPA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Apparatus); break;
case ESM::REC_ARMO: mReferenceables.load (*mReader, mBase, UniversalId::Type_Armor); break;
case ESM::REC_BOOK: mReferenceables.load (*mReader, mBase, UniversalId::Type_Book); break;
case ESM::REC_CLOT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Clothing); break;
case ESM::REC_CONT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Container); break;
case ESM::REC_CREA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Creature); break;
case ESM::REC_DOOR: mReferenceables.load (*mReader, mBase, UniversalId::Type_Door); break;
case ESM::REC_INGR: mReferenceables.load (*mReader, mBase, UniversalId::Type_Ingredient); break;
case ESM::REC_LEVC:
mReferenceables.load (*mReader, mBase, UniversalId::Type_CreatureLevelledList); break;
case ESM::REC_LEVI:
mReferenceables.load (*mReader, mBase, UniversalId::Type_ItemLevelledList); break;
case ESM::REC_LIGH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Light); break;
case ESM::REC_LOCK: mReferenceables.load (*mReader, mBase, UniversalId::Type_Lockpick); break;
case ESM::REC_MISC:
mReferenceables.load (*mReader, mBase, UniversalId::Type_Miscellaneous); break;
case ESM::REC_NPC_: mReferenceables.load (*mReader, mBase, UniversalId::Type_Npc); break;
case ESM::REC_PROB: mReferenceables.load (*mReader, mBase, UniversalId::Type_Probe); break;
case ESM::REC_REPA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Repair); break;
case ESM::REC_STAT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Static); break;
case ESM::REC_WEAP: mReferenceables.load (*mReader, mBase, UniversalId::Type_Weapon); break;
case ESM::REC_DIAL:
{
std::string id = mReader->getHNOString ("NAME");
ESM::Dialogue record;
record.mId = id;
record.load (*mReader);
if (record.mType==ESM::Dialogue::Journal)
{
mJournals.load (record, mBase);
mDialogue = &mJournals.getRecord (id).get();
}
else if (record.mType==ESM::Dialogue::Deleted)
{
mDialogue = 0; // record vector can be shuffled around which would make pointer
// to record invalid
if (mJournals.tryDelete (id))
{
/// \todo handle info records
}
else if (mTopics.tryDelete (id))
{
/// \todo handle info records
}
else
{
messages.push_back (std::make_pair (UniversalId::Type_None,
"Trying to delete dialogue record " + id + " which does not exist"));
}
}
else
{
mTopics.load (record, mBase);
mDialogue = &mTopics.getRecord (id).get();
}
break;
}
case ESM::REC_INFO:
{
if (!mDialogue)
{
messages.push_back (std::make_pair (UniversalId::Type_None,
"Found info record not following a dialogue record"));
mReader->skipRecord();
break;
}
if (mDialogue->mType==ESM::Dialogue::Journal)
mJournalInfos.load (*mReader, mBase, *mDialogue);
else
mTopicInfos.load (*mReader, mBase, *mDialogue);
break;
}
case ESM::REC_FILT:
if (mProject)
{
mFilters.load (*mReader, mBase);
mFilters.setData (mFilters.getSize()-1,
mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
static_cast<int> (CSMFilter::Filter::Scope_Project));
break;
}
// fall through (filter record in a content file is an error with format 0)
default:
messages.push_back (std::make_pair (UniversalId::Type_None,
"Unsupported record type: " + n.toString()));
mReader->skipRecord();
}
return false;
}
bool CSMWorld::Data::hasId (const std::string& id) const

View file

@ -22,8 +22,12 @@
#include <components/esm/loadspel.hpp>
#include <components/esm/loaddial.hpp>
#include <components/to_utf8/to_utf8.hpp>
#include "../filter/filter.hpp"
#include "../doc/stage.hpp"
#include "idcollection.hpp"
#include "universalid.hpp"
#include "cell.hpp"
@ -33,12 +37,19 @@
class QAbstractItemModel;
namespace ESM
{
class ESMReader;
struct Dialogue;
}
namespace CSMWorld
{
class Data : public QObject
{
Q_OBJECT
ToUTF8::Utf8Encoder mEncoder;
IdCollection<ESM::Global> mGlobals;
IdCollection<ESM::GameSetting> mGmsts;
IdCollection<ESM::Skill> mSkills;
@ -62,6 +73,10 @@ namespace CSMWorld
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
std::string mAuthor;
std::string mDescription;
ESM::ESMReader *mReader;
const ESM::Dialogue *mDialogue; // last loaded dialogue
bool mBase;
bool mProject;
// not implemented
Data (const Data&);
@ -78,7 +93,7 @@ namespace CSMWorld
public:
Data();
Data (ToUTF8::FromType encoding);
virtual ~Data();
@ -167,10 +182,15 @@ namespace CSMWorld
void merge();
///< Merge modified into base.
void loadFile (const boost::filesystem::path& path, bool base, bool project);
///< Merging content of a file into base or modified.
int startLoading (const boost::filesystem::path& path, bool base, bool project);
///< Begin merging content of a file into base or modified.
///
/// \param project load project file instead of content file
///
///< \return estimated number of records
bool continueLoading (CSMDoc::Stage::Messages& messages);
///< \return Finished?
bool hasId (const std::string& id) const;

View file

@ -18,7 +18,7 @@ namespace
static const TypeData sNoArg[] =
{
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "-", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", 0 },
@ -101,6 +101,7 @@ namespace
static const TypeData sIndexArg[] =
{
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 },
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
}

View file

@ -97,10 +97,11 @@ namespace CSMWorld
Type_JournalInfos,
Type_JournalInfo,
Type_Scene,
Type_Preview
Type_Preview,
Type_LoadErrorLog
};
enum { NumberOfTypes = Type_Scene+1 };
enum { NumberOfTypes = Type_LoadErrorLog+1 };
private:

View file

@ -0,0 +1,193 @@
#include "loader.hpp"
#include <QVBoxLayout>
#include <QLabel>
#include <QProgressBar>
#include <QCursor>
#include <QDialogButtonBox>
#include <QCloseEvent>
#include <QListWidget>
#include "../../model/doc/document.hpp"
void CSVDoc::LoadingDocument::closeEvent (QCloseEvent *event)
{
event->ignore();
cancel();
}
CSVDoc::LoadingDocument::LoadingDocument (CSMDoc::Document *document)
: mDocument (document), mAborted (false), mMessages (0)
{
setWindowTitle (("Opening " + document->getSavePath().filename().string()).c_str());
setMinimumWidth (400);
mLayout = new QVBoxLayout (this);
// file progress
mFile = new QLabel (this);
mLayout->addWidget (mFile);
mFileProgress = new QProgressBar (this);
mLayout->addWidget (mFileProgress);
int size = static_cast<int> (document->getContentFiles().size())+1;
if (document->isNew())
--size;
mFileProgress->setMinimum (0);
mFileProgress->setMaximum (size);
mFileProgress->setTextVisible (true);
mFileProgress->setValue (0);
// record progress
mLayout->addWidget (new QLabel ("Records", this));
mRecordProgress = new QProgressBar (this);
mLayout->addWidget (mRecordProgress);
mRecordProgress->setMinimum (0);
mRecordProgress->setTextVisible (true);
mRecordProgress->setValue (0);
// error message
mError = new QLabel (this);
mError->setWordWrap (true);
mLayout->addWidget (mError);
// buttons
mButtons = new QDialogButtonBox (QDialogButtonBox::Cancel, Qt::Horizontal, this);
mLayout->addWidget (mButtons);
setLayout (mLayout);
move (QCursor::pos());
show();
connect (mButtons, SIGNAL (rejected()), this, SLOT (cancel()));
}
void CSVDoc::LoadingDocument::nextStage (const std::string& name, int steps)
{
mFile->setText (QString::fromUtf8 (("Loading: " + name).c_str()));
mFileProgress->setValue (mFileProgress->value()+1);
mRecordProgress->setValue (0);
mRecordProgress->setMaximum (steps>0 ? steps : 1);
}
void CSVDoc::LoadingDocument::nextRecord()
{
int value = mRecordProgress->value()+1;
if (value<=mRecordProgress->maximum())
mRecordProgress->setValue (value);
}
void CSVDoc::LoadingDocument::abort (const std::string& error)
{
mAborted = true;
mError->setText (QString::fromUtf8 (("Loading failed: " + error).c_str()));
mButtons->setStandardButtons (QDialogButtonBox::Close);
}
void CSVDoc::LoadingDocument::addMessage (const std::string& message)
{
if (!mMessages)
{
mMessages = new QListWidget (this);
mLayout->insertWidget (4, mMessages);
}
new QListWidgetItem (QString::fromUtf8 (message.c_str()), mMessages);
}
void CSVDoc::LoadingDocument::cancel()
{
if (!mAborted)
emit cancel (mDocument);
else
{
emit close (mDocument);
deleteLater();
}
}
CSVDoc::Loader::Loader() {}
CSVDoc::Loader::~Loader()
{
for (std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter (mDocuments.begin());
iter!=mDocuments.end(); ++iter)
delete iter->second;
}
void CSVDoc::Loader::add (CSMDoc::Document *document)
{
LoadingDocument *loading = new LoadingDocument (document);
mDocuments.insert (std::make_pair (document, loading));
connect (loading, SIGNAL (cancel (CSMDoc::Document *)),
this, SIGNAL (cancel (CSMDoc::Document *)));
connect (loading, SIGNAL (close (CSMDoc::Document *)),
this, SIGNAL (close (CSMDoc::Document *)));
}
void CSVDoc::Loader::loadingStopped (CSMDoc::Document *document, bool completed,
const std::string& error)
{
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.begin();
for (; iter!=mDocuments.end(); ++iter)
if (iter->first==document)
break;
if (iter==mDocuments.end())
return;
if (completed || error.empty())
{
delete iter->second;
mDocuments.erase (iter);
}
else if (!completed && !error.empty())
{
iter->second->abort (error);
// Leave the window open for now (wait for the user to close it)
mDocuments.erase (iter);
}
}
void CSVDoc::Loader::nextStage (CSMDoc::Document *document, const std::string& name, int steps)
{
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.find (document);
if (iter!=mDocuments.end())
iter->second->nextStage (name, steps);
}
void CSVDoc::Loader::nextRecord (CSMDoc::Document *document)
{
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.find (document);
if (iter!=mDocuments.end())
iter->second->nextRecord();
}
void CSVDoc::Loader::loadMessage (CSMDoc::Document *document, const std::string& message)
{
std::map<CSMDoc::Document *, LoadingDocument *>::iterator iter = mDocuments.find (document);
if (iter!=mDocuments.end())
iter->second->addMessage (message);
}

View file

@ -0,0 +1,99 @@
#ifndef CSV_DOC_LOADER_H
#define CSV_DOC_LOADER_H
#include <map>
#include <QObject>
#include <QWidget>
#include <QSignalMapper>
class QLabel;
class QProgressBar;
class QDialogButtonBox;
class QListWidget;
class QVBoxLayout;
namespace CSMDoc
{
class Document;
}
namespace CSVDoc
{
class LoadingDocument : public QWidget
{
Q_OBJECT
CSMDoc::Document *mDocument;
QLabel *mFile;
QProgressBar *mFileProgress;
QProgressBar *mRecordProgress;
bool mAborted;
QDialogButtonBox *mButtons;
QLabel *mError;
QListWidget *mMessages;
QVBoxLayout *mLayout;
private:
void closeEvent (QCloseEvent *event);
public:
LoadingDocument (CSMDoc::Document *document);
void nextStage (const std::string& name, int steps);
void nextRecord();
void abort (const std::string& error);
void addMessage (const std::string& message);
private slots:
void cancel();
signals:
void cancel (CSMDoc::Document *document);
///< Stop loading process.
void close (CSMDoc::Document *document);
///< Close stopped loading process.
};
class Loader : public QObject
{
Q_OBJECT
std::map<CSMDoc::Document *, LoadingDocument *> mDocuments;
public:
Loader();
virtual ~Loader();
signals:
void cancel (CSMDoc::Document *document);
void close (CSMDoc::Document *document);
public slots:
void add (CSMDoc::Document *document);
void loadingStopped (CSMDoc::Document *document, bool completed,
const std::string& error);
void nextStage (CSMDoc::Document *document, const std::string& name, int steps);
void nextRecord (CSMDoc::Document *document);
void loadMessage (CSMDoc::Document *document, const std::string& message);
};
}
#endif

View file

@ -1,62 +0,0 @@
#include <QVBoxLayout>
#include <QDialogButtonBox>
#include <components/fileorderlist/datafileslist.hpp>
#include "opendialog.hpp"
OpenDialog::OpenDialog(QWidget * parent) : QDialog(parent)
{
QVBoxLayout *layout = new QVBoxLayout(this);
mFileSelector = new DataFilesList(mCfgMgr, this);
layout->addWidget(mFileSelector);
/// \todo move config to Editor class and add command line options.
// We use the Configuration Manager to retrieve the configuration values
boost::program_options::variables_map variables;
boost::program_options::options_description desc;
desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252"));
boost::program_options::notify(variables);
mCfgMgr.readConfiguration(variables, desc);
Files::PathContainer mDataDirs, mDataLocal;
if (!variables["data"].empty()) {
mDataDirs = Files::PathContainer(variables["data"].as<Files::PathContainer>());
}
std::string local = variables["data-local"].as<std::string>();
if (!local.empty()) {
mDataLocal.push_back(Files::PathContainer::value_type(local));
}
mCfgMgr.processPaths(mDataDirs);
mCfgMgr.processPaths(mDataLocal);
// Set the charset for reading the esm/esp files
QString encoding = QString::fromUtf8 (variables["encoding"].as<std::string>().c_str());
Files::PathContainer dataDirs;
dataDirs.insert(dataDirs.end(), mDataDirs.begin(), mDataDirs.end());
dataDirs.insert(dataDirs.end(), mDataLocal.begin(), mDataLocal.end());
mFileSelector->setupDataFiles(dataDirs, encoding);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Open | QDialogButtonBox::Cancel, Qt::Horizontal, this);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
layout->addWidget(buttonBox);
setLayout(layout);
setWindowTitle(tr("Open"));
}
void OpenDialog::getFileList(std::vector<boost::filesystem::path>& paths)
{
mFileSelector->selectedFiles(paths);
}

View file

@ -1,17 +0,0 @@
#include <qdialog.h>
#include <components/files/configurationmanager.hpp>
class DataFilesList;
class QDialogButtonBox;
class OpenDialog : public QDialog {
Q_OBJECT
public:
OpenDialog(QWidget * parent = 0);
void getFileList(std::vector<boost::filesystem::path>& paths);
private:
DataFilesList * mFileSelector;
QDialogButtonBox * buttonBox;
Files::ConfigurationManager mCfgMgr;
};

View file

@ -10,9 +10,12 @@
#include <QtGui/QApplication>
#include "../../model/doc/document.hpp"
#include "../world/subviews.hpp"
#include "../tools/subviews.hpp"
#include "../../model/settings/usersettings.hpp"
#include "../world/subviews.hpp"
#include "../tools/subviews.hpp"
#include "viewmanager.hpp"
#include "operations.hpp"
#include "subview.hpp"
@ -47,6 +50,10 @@ void CSVDoc::View::setupFileMenu()
connect (mVerify, SIGNAL (triggered()), this, SLOT (verify()));
file->addAction (mVerify);
QAction *loadErrors = new QAction (tr ("Load Error Log"), this);
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
file->addAction (loadErrors);
QAction *close = new QAction (tr ("&Close"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close);
@ -236,10 +243,10 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
mViewTotal (totalViews)
{
QString width = CSMSettings::UserSettings::instance().settingValue
("Window Size.Width");
("Window Size/Width");
QString height = CSMSettings::UserSettings::instance().settingValue
("Window Size.Height");
("Window Size/Height");
resize (width.toInt(), height.toInt());
@ -502,3 +509,8 @@ void CSVDoc::View::toggleShowStatusBar (bool show)
subView->setStatusBar (show);
}
}
void CSVDoc::View::loadErrorLog()
{
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_LoadErrorLog, 0));
}

View file

@ -179,6 +179,8 @@ namespace CSVDoc
void addJournalInfosSubView();
void toggleShowStatusBar (bool show);
void loadErrorLog();
};
}

View file

@ -84,6 +84,33 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
mDelegateFactories->add (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory (
CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone));
connect (&mDocumentManager, SIGNAL (loadRequest (CSMDoc::Document *)),
&mLoader, SLOT (add (CSMDoc::Document *)));
connect (
&mDocumentManager, SIGNAL (loadingStopped (CSMDoc::Document *, bool, const std::string&)),
&mLoader, SLOT (loadingStopped (CSMDoc::Document *, bool, const std::string&)));
connect (
&mDocumentManager, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)),
&mLoader, SLOT (nextStage (CSMDoc::Document *, const std::string&, int)));
connect (
&mDocumentManager, SIGNAL (nextRecord (CSMDoc::Document *)),
&mLoader, SLOT (nextRecord (CSMDoc::Document *)));
connect (
&mDocumentManager, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)),
&mLoader, SLOT (loadMessage (CSMDoc::Document *, const std::string&)));
connect (
&mLoader, SIGNAL (cancel (CSMDoc::Document *)),
&mDocumentManager, SIGNAL (cancelLoading (CSMDoc::Document *)));
connect (
&mLoader, SIGNAL (close (CSMDoc::Document *)),
&mDocumentManager, SLOT (removeDocument (CSMDoc::Document *)));
}
CSVDoc::ViewManager::~ViewManager()

View file

@ -5,6 +5,8 @@
#include <QObject>
#include "loader.hpp"
namespace CSMDoc
{
class Document;
@ -29,6 +31,7 @@ namespace CSVDoc
CSVWorld::CommandDelegateFactoryCollection *mDelegateFactories;
bool mExitOnSaveStateChange;
bool mUserWarned;
Loader mLoader;
// not implemented
ViewManager (const ViewManager&);

View file

@ -86,8 +86,11 @@ namespace CSVRender
}
std::stringstream windowHandle;
#ifdef WIN32
windowHandle << Ogre::StringConverter::toString((unsigned long)(this->winId()));
#else
windowHandle << this->winId();
#endif
std::stringstream windowTitle;
static int count=0;
windowTitle << ++count;

View file

@ -76,22 +76,9 @@ void CSVSettings::Dialog::buildPages()
mStackedWidget->addWidget (&dynamic_cast<QWidget &>(*(page)));
}
addDebugPage();
resize (mStackedWidget->sizeHint());
}
void CSVSettings::Dialog::addDebugPage()
{
/*
QTreeView *tree = new QTreeView();
//tree->setModel( &CSMSettings::UserSettings::instance().model() );
mStackedWidget->addWidget(tree);
new QListWidgetItem ("Standard Item Model", mPageListWidget);*/
}
void CSVSettings::Dialog::buildPageListWidget (QWidget *centralWidget)
{
mPageListWidget = new QListWidget (centralWidget);
@ -122,7 +109,11 @@ void CSVSettings::Dialog::closeEvent (QCloseEvent *event)
void CSVSettings::Dialog::show()
{
if (pages().isEmpty())
{
buildPages();
setViewValues();
}
QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move (screenCenter - geometry().center());

View file

@ -41,7 +41,6 @@ namespace CSVSettings {
void buildPages();
void buildPageListWidget (QWidget *centralWidget);
void buildStackedWidget (QWidget *centralWidget);
void addDebugPage();
public slots:

View file

@ -44,11 +44,13 @@ namespace CSVSettings
void setHLayout() { mIsHorizontal = true; }
void setVLayout() { mIsHorizontal = false; }
///show / hide widgets (when stacked widget page changes)
void showWidgets();
void hideWidgets();
private:
///functions which return the index for the next layout row / column
int getNextColumn() const;
int getNextRow() const;

View file

@ -1,7 +1,6 @@
#ifndef CSVSETTINGS_PAGE_HPP
#define CSVSETTINGS_PAGE_HPP
#include <QSizePolicy>
#include <QWidget>
#include <QMap>
#include <QList>
@ -40,6 +39,7 @@ namespace CSVSettings
///and returns it.
View *findView (const QString &page, const QString &setting) const;
///returns the list of views associated with the page
const QList <View *> &views () const { return mViews; }
private:

View file

@ -1,6 +1,3 @@
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QAbstractSpinBox>

View file

@ -21,13 +21,19 @@ namespace CSVSettings
Page *parent);
protected:
///virtual function called through View
void updateView (bool signalUpdate = true) const;
///construct a slider-based view
void buildSlider (CSMSettings::Setting *setting);
///construct a spinbox-based view
void buildSpinBox (CSMSettings::Setting *setting);
private slots:
///responds to valueChanged signals
void slotUpdateView (int value);
void slotUpdateView (double value);

View file

@ -14,8 +14,10 @@ namespace CSVSettings
public:
explicit ResizeableStackedWidget(QWidget *parent = 0);
///add a widget to the stacked widget
void addWidget(QWidget* pWidget);
///called whenever the stacked widget page is changed
void changePage (int, int);
};
}

View file

@ -57,7 +57,7 @@ void CSVSettings::SettingWindow::createConnections
foreach (const QString &key, proxyMap.keys())
{
QStringList keyPair = key.split('.');
QStringList keyPair = key.split('/');
if (keyPair.size() != 2)
continue;
@ -82,6 +82,25 @@ void CSVSettings::SettingWindow::createConnections
}
}
void CSVSettings::SettingWindow::setViewValues()
{
//iterate each page and view, setting their definintions
//if they exist in the model
foreach (const Page *page, mPages)
{
foreach (const View *view, page->views())
{
//testing beforehand prevents overwriting a proxy setting
if (!mModel->hasSettingDefinitions (view->viewKey()))
continue;
QStringList defs = mModel->definitions (view->viewKey());
view->setSelectedValues(defs);
}
}
}
CSVSettings::View *CSVSettings::SettingWindow::findView
(const QString &pageName, const QString &setting)
{
@ -95,17 +114,19 @@ CSVSettings::View *CSVSettings::SettingWindow::findView
void CSVSettings::SettingWindow::saveSettings()
{
QMap <QString, QStringList> settingMap;
//setting the definition in the model automatically syncs with the file
foreach (const Page *page, mPages)
{
foreach (const View *view, page->views())
{
if (view->serializable())
settingMap[view->viewKey()] = view->selectedValues();
if (!view->serializable())
continue;
mModel->setDefinitions (view->viewKey(), view->selectedValues());
}
}
CSMSettings::UserSettings::instance().saveSettings (settingMap);
mModel->saveDefinitions();
}
void CSVSettings::SettingWindow::closeEvent (QCloseEvent *event)

View file

@ -8,7 +8,7 @@
namespace CSMSettings {
class Setting;
class SettingManager;
class UserSettings;
}
namespace CSVSettings {
@ -23,25 +23,36 @@ namespace CSVSettings {
Q_OBJECT
PageList mPages;
CSMSettings::SettingManager *mModel;
CSMSettings::UserSettings *mModel;
public:
explicit SettingWindow(QWidget *parent = 0);
///retrieve a reference to a view based on it's page and setting name
View *findView (const QString &pageName, const QString &setting);
void setModel (CSMSettings::SettingManager &model) { mModel = &model; }
///set the model the view uses (instance of UserSettings)
void setModel (CSMSettings::UserSettings &model) { mModel = &model; }
protected:
virtual void closeEvent (QCloseEvent *event);
///construct the pages to be displayed in the dialog
void createPages();
///return the list of constructed pages
const PageList &pages() const { return mPages; }
///save settings from the GUI to file
void saveSettings();
///sets the defined values for the views that have been created
void setViewValues();
private:
///create connections between settings (used for proxy settings)
void createConnections (const QList <CSMSettings::Setting *> &list);
};
}

View file

@ -1,6 +1,5 @@
#include "spinbox.hpp"
#include <QSpinBox>
#include <QLineEdit>
CSVSettings::SpinBox::SpinBox(QWidget *parent)
@ -14,7 +13,7 @@ QString CSVSettings::SpinBox::textFromValue(int val) const
if (mValueList.isEmpty())
return QVariant (val).toString();
QString value = "";
QString value;
if (val < mValueList.size())
value = mValueList.at (val);

View file

@ -16,15 +16,22 @@ namespace CSVSettings
public:
explicit SpinBox(QWidget *parent = 0);
void setObjectName (const QString &name);
///set the value displayed in the spin box
void setValue (const QString &value);
///set the stringlist that's used as a list of pre-defined values
///to be displayed as the user scrolls
void setValueList (const QStringList &list);
///returns the pre-defined value list.
const QStringList &valueList() const { return mValueList; }
protected:
///converts an index value to corresponding text to be displayed
QString textFromValue (int val) const;
///converts a text value to a corresponding index
int valueFromText (const QString &text) const;
};
}

View file

@ -20,6 +20,7 @@ namespace CSVSettings
protected:
/// virtual function called through View
void updateView (bool signalUpdate = true) const;
protected slots:

View file

@ -1,7 +1,8 @@
#include <QStringListModel>
#include <QSortFilterProxyModel>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QApplication>
#include <QItemSelectionModel>
#include <QStringListModel>
#include "view.hpp"
#include "../../model/settings/support.hpp"
@ -14,7 +15,7 @@ CSVSettings::View::View(CSMSettings::Setting *setting,
: mDataModel(0), mParentPage (parent),
mHasFixedValues (!setting->declaredValues().isEmpty()),
mIsMultiValue (setting->isMultiValue()),
mViewKey (setting->page() + '.' + setting->name()),
mViewKey (setting->page() + '/' + setting->name()),
mSerializable (setting->serializable()),
Frame(true, setting->name(), parent)
{
@ -25,10 +26,7 @@ CSVSettings::View::View(CSMSettings::Setting *setting,
void CSVSettings::View::buildModel (const CSMSettings::Setting *setting)
{
QStringList values = setting->definedValues();
if (values.isEmpty())
values.append (setting->defaultValues());
QStringList values = setting->defaultValues();
if (mHasFixedValues)
buildFixedValueModel (setting->declaredValues());
@ -42,24 +40,22 @@ void CSVSettings::View::buildModel (const CSMSettings::Setting *setting)
void CSVSettings::View::buildFixedValueModel (const QStringList &values)
{
//fixed value models are simple string list models, since they are read-only
mDataModel = new QStringListModel (values, this);
}
void CSVSettings::View::buildUpdatableValueModel (const QStringList &values)
{
//updateable models are standard item models because they support
//replacing entire columns
QList <QStandardItem *> itemList;
foreach (const QString &value, values)
itemList.append (new QStandardItem(value));
// QSortFilterProxyModel *filter = new QSortFilterProxyModel (this);
QStandardItemModel *model = new QStandardItemModel (this);
model->appendColumn (itemList);
// filter->setSourceModel (model);
/* filter->setFilterRegExp ("*");
filter->setFilterKeyColumn (0);
filter->setFilterRole (Qt::DisplayRole);*/
mDataModel = model;
}
@ -117,7 +113,7 @@ void CSVSettings::View::setSelectedValue (const QString &value,
}
void CSVSettings::View::setSelectedValues (const QStringList &list,
bool doViewUpdate, bool signalUpdate)
bool doViewUpdate, bool signalUpdate) const
{
QItemSelection selection;
@ -151,9 +147,6 @@ void CSVSettings::View::setSelectedValues (const QStringList &list,
}
select (selection);
//push changes to model side
//update the view if the selection was set from the model side, not by the
//user
if (doViewUpdate)
@ -192,7 +185,6 @@ bool CSVSettings::View::stringListsMatch (
QList <QStandardItem *> CSVSettings::View::toStandardItemList
(const QStringList &list) const
{
QList <QStandardItem *> itemList;
foreach (const QString &value, list)
@ -212,12 +204,12 @@ QString CSVSettings::View::value (int row) const
if (row > -1 && row < mDataModel->rowCount())
return mDataModel->data (mDataModel->index(row, 0)).toString();
return "";
return QString();
}
int CSVSettings::View::widgetWidth(int characterCount) const
{
QString widthToken = QString().fill ('P', characterCount);
QString widthToken = QString().fill ('m', characterCount);
QFontMetrics fm (QApplication::font());
return (fm.width (widthToken));

View file

@ -11,8 +11,6 @@ class QGroupBox;
class QStringList;
class QStandardItem;
class QItemSelection;
class QStringListModel;
class QStandardItemModel;
class QAbstractItemModel;
class QItemSelectionModel;
@ -42,17 +40,16 @@ namespace CSVSettings
///State indicating whether the view will allow multiple values
bool mIsMultiValue;
///'pagename.settingname' form of the view's id
QString mViewKey;
///indicates whether or not the setting is written to file
bool mSerializable;
public:
explicit View (CSMSettings::Setting *setting, Page *parent);
///Physical frame in which the view UI is contained
void addViewWidget (QWidget *widget, int row = -1, int col = -1) const;
///Returns the index / row of the passed value, -1 if not found.
int currentIndex () const;
@ -74,7 +71,7 @@ namespace CSVSettings
///or signaling the view was updatedto avoid viscious cylcing.
void setSelectedValues (const QStringList &values,
bool updateView = true,
bool signalUpdate = true);
bool signalUpdate = true) const;
void setSelectedValue (const QString &value,
bool updateView = true,

View file

@ -9,4 +9,6 @@ void CSVTools::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
{
manager.add (CSMWorld::UniversalId::Type_VerificationResults,
new CSVDoc::SubViewFactory<ReportSubView>);
manager.add (CSMWorld::UniversalId::Type_LoadErrorLog,
new CSVDoc::SubViewFactory<ReportSubView>);
}

View file

@ -7,18 +7,19 @@
CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
const IconList &icons,
QUndoStack &undoStack,
const QString &settingKey,
const QString &pageName,
const QString &settingName,
QObject *parent)
: EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly),
mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3),
mTextLeftOffset(8), mSettingKey (settingKey)
mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName)
{
mTextAlignment.setAlignment (Qt::AlignLeft | Qt::AlignVCenter );
buildPixmaps();
QString value =
CSMSettings::UserSettings::instance().settingValue (settingKey);
CSMSettings::UserSettings::instance().settingValue (mSettingKey);
updateDisplayMode(value);
}
@ -140,7 +141,7 @@ CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (Q
QObject *parent) const
{
return new DataDisplayDelegate (mValues, mIcons, undoStack, "", parent);
return new DataDisplayDelegate (mValues, mIcons, undoStack, "", "", parent);
}

View file

@ -41,7 +41,8 @@ namespace CSVWorld
explicit DataDisplayDelegate (const ValueList & values,
const IconList & icons,
QUndoStack& undoStack,
const QString &settingKey,
const QString &pageName,
const QString &settingName,
QObject *parent);
~DataDisplayDelegate();

View file

@ -5,7 +5,7 @@
CSVWorld::IdTypeDelegate::IdTypeDelegate
(const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent)
: DataDisplayDelegate (values, icons, undoStack,
"Display Format.Referenceable ID Type Display",
"Display Format", "Referenceable ID Type Display",
parent)
{}

View file

@ -11,7 +11,7 @@ CSVWorld::RecordStatusDelegate::RecordStatusDelegate(const ValueList& values,
const IconList & icons,
QUndoStack &undoStack, QObject *parent)
: DataDisplayDelegate (values, icons, undoStack,
"Display Format.Record Status Display",
"Display Format", "Record Status Display",
parent)
{}

View file

@ -111,13 +111,17 @@ void CSVWorld::TableSubView::createFilterRequest (std::vector< CSMWorld::Univers
{
std::vector<std::pair<std::string, std::vector<std::string> > > filterSource;
for (std::vector<CSMWorld::UniversalId>::iterator it = types.begin(); it != types.end(); ++it)
for (std::vector<CSMWorld::UniversalId>::iterator it(types.begin()); it != types.end(); ++it)
{
std::pair<std::string, std::vector<std::string> > pair( //splited long line
std::make_pair(it->getId(), mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(it->getType()))));
std::make_pair(it->getId(), mTable->getColumnsWithDisplay(CSMWorld::TableMimeData::convertEnums(it->getType()))));
filterSource.push_back(pair);
if(!pair.second.empty())
{
filterSource.push_back(pair);
}
}
mFilterBox->createFilterRequest(filterSource, action);
}

View file

@ -79,7 +79,7 @@ void CSVWorld::VarTypeDelegateFactory::add (ESM::VarType type)
std::vector<std::string> enums =
CSMWorld::Columns::getEnums (CSMWorld::Columns::ColumnId_ValueType);
if (type<0 && type>=enums.size())
if (static_cast<size_t>(type) >= enums.size())
throw std::logic_error ("Unsupported variable type");
mValues.push_back (std::make_pair (type, QString::fromUtf8 (enums[type].c_str())));

View file

@ -48,7 +48,7 @@ add_openmw_dir (mwscript
)
add_openmw_dir (mwsound
soundmanagerimp openal_output ffmpeg_decoder
soundmanagerimp openal_output ffmpeg_decoder sound
)
add_openmw_dir (mwworld
@ -57,7 +57,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
contentloader esmloader omwloader actiontrap cellreflist projectilemanager
)
add_openmw_dir (mwclass
@ -67,7 +67,7 @@ add_openmw_dir (mwclass
add_openmw_dir (mwmechanics
mechanicsmanagerimp stat character creaturestats magiceffects movement actors objects
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow
drawstate spells activespells npcstats aipackage aisequence aipursue alchemy aiwander aitravel aifollow aiavoiddoor
aiescort aiactivate aicombat repair enchanting pathfinding pathgrid security spellsuccess spellcasting
disease pickpocket levelledlist combat steering obstacle
)

View file

@ -66,9 +66,13 @@ void OMW::Engine::executeLocalScripts()
bool OMW::Engine::frameStarted (const Ogre::FrameEvent& evt)
{
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame, paused);
MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame);
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
bool paused = MWBase::Environment::get().getWindowManager()->isGuiMode();
MWBase::Environment::get().getWorld()->frameStarted(evt.timeSinceLastFrame, paused);
MWBase::Environment::get().getWindowManager ()->frameStarted(evt.timeSinceLastFrame);
}
return true;
}
@ -110,8 +114,12 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
// update actors
MWBase::Environment::get().getMechanicsManager()->update(frametime,
paused);
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
MWBase::Environment::get().getMechanicsManager()->update(frametime,
paused);
}
if (MWBase::Environment::get().getStateManager()->getState()==
MWBase::StateManager::State_Running)
@ -122,16 +130,24 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt)
}
// update world
MWBase::Environment::get().getWorld()->update(frametime, paused);
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
MWBase::Environment::get().getWorld()->update(frametime, paused);
}
// update GUI
Ogre::RenderWindow* window = mOgre->getWindow();
unsigned int tri, batch;
MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch);
MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
if (MWBase::Environment::get().getStateManager()->getState()!=
MWBase::StateManager::State_NoGame)
{
Ogre::RenderWindow* window = mOgre->getWindow();
unsigned int tri, batch;
MWBase::Environment::get().getWorld()->getTriangleBatchCount(tri, batch);
MWBase::Environment::get().getWindowManager()->wmUpdateFps(window->getLastFPS(), tri, batch);
MWBase::Environment::get().getWindowManager()->onFrame(frametime);
MWBase::Environment::get().getWindowManager()->update();
MWBase::Environment::get().getWindowManager()->onFrame(frametime);
MWBase::Environment::get().getWindowManager()->update();
}
}
catch (const std::exception& e)
{
@ -364,7 +380,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// Create the world
mEnvironment.setWorld( new MWWorld::World (*mOgre, mFileCollections, mContentFiles,
mResDir, mCfgMgr.getCachePath(), mEncoder, mFallbackMap,
mActivationDistanceOverride, mCellName));
mActivationDistanceOverride, mCellName, mStartupScript));
MWBase::Environment::get().getWorld()->setupPlayer();
input->setPlayer(&mEnvironment.getWorld()->getPlayer());
@ -393,10 +409,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
mEnvironment.setJournal (new MWDialogue::Journal);
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mVerboseScripts, mTranslationDataStorage));
mEnvironment.getWorld()->renderPlayer();
mechanics->buildPlayer();
window->updatePlayer();
mOgre->getRoot()->addFrameListener (this);
// scripts
@ -450,10 +462,9 @@ void OMW::Engine::go()
catch (...) {}
}
else
{
MWBase::Environment::get().getStateManager()->newGame (true);
if (!mStartupScript.empty())
MWBase::Environment::get().getWindowManager()->executeInConsole (mStartupScript);
}
// Start the main rendering loop
while (!mEnvironment.get().getStateManager()->hasQuitRequest())

View file

@ -37,7 +37,7 @@ namespace MWBase
typedef std::deque<MWDialogue::StampedJournalEntry> TEntryContainer;
typedef TEntryContainer::const_iterator TEntryIter;
typedef std::map<std::string, MWDialogue::Quest> TQuestContainer; // topc, quest
typedef std::map<std::string, MWDialogue::Quest> TQuestContainer; // topic, quest
typedef TQuestContainer::const_iterator TQuestIter;
typedef std::map<std::string, MWDialogue::Topic> TTopicContainer; // topic-id, topic-content
typedef TTopicContainer::const_iterator TTopicIter;

View file

@ -96,6 +96,9 @@ namespace MWBase
/// Check if \a observer is potentially aware of \a ptr. Does not do a line of sight check!
virtual bool awarenessCheck (const MWWorld::Ptr& ptr, const MWWorld::Ptr& observer) = 0;
/// Makes \a ptr fight \a target. Also shouts a combat taunt.
virtual void startCombat (const MWWorld::Ptr& ptr, const MWWorld::Ptr& target) = 0;
enum OffenseType
{
OT_Theft, // Taking items owned by an NPC or a faction you are not a member of

View file

@ -110,18 +110,25 @@ namespace MWBase
///< Play a sound, independently of 3D-position
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
virtual SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
float volume, float pitch, PlayType type=Play_TypeSfx,
PlayMode mode=Play_Normal, float offset=0) = 0;
///< Play a sound from an object
virtual MWBase::SoundPtr playSound3D(const MWWorld::Ptr &reference, const std::string& soundId,
float volume, float pitch, PlayType type=Play_TypeSfx,
PlayMode mode=Play_Normal, float offset=0) = 0;
///< Play a 3D sound attached to an MWWorld::Ptr. Will be updated automatically with the Ptr's position, unless Play_NoTrack is specified.
///< @param offset Value from [0,1] meaning from which fraction the sound the playback starts.
virtual MWBase::SoundPtr playManualSound3D(const Ogre::Vector3& initialPos, const std::string& soundId,
float volume, float pitch, PlayType type, PlayMode mode, float offset=0) = 0;
///< Play a 3D sound at \a initialPos. If the sound should be moving, it must be updated manually using Sound::setPosition.
virtual void stopSound3D(const MWWorld::Ptr &reference, const std::string& soundId) = 0;
///< Stop the given object from playing the given sound,
virtual void stopSound3D(const MWWorld::Ptr &reference) = 0;
///< Stop the given object from playing all sounds.
virtual void stopSound(MWBase::SoundPtr sound) = 0;
///< Stop the given sound handle
virtual void stopSound(const MWWorld::CellStore *cell) = 0;
///< Stop all sounds for the given cell.

View file

@ -193,15 +193,15 @@ namespace MWBase
virtual void setDragDrop(bool dragDrop) = 0;
virtual bool getWorldMouseOver() = 0;
virtual void toggleFogOfWar() = 0;
virtual bool toggleFogOfWar() = 0;
virtual void toggleFullHelp() = 0;
virtual bool toggleFullHelp() = 0;
///< show extra info in item tooltips (owner, script)
virtual bool getFullHelp() const = 0;
virtual void setInteriorMapTexture(const int x, const int y) = 0;
///< set the index of the map texture that should be used (for interiors)
virtual void setActiveMap(int x, int y, bool interior) = 0;
///< set the indices of the map texture that should be used
/// sets the visibility of the drowning bar
virtual void setDrowningBarVisibility(bool visible) = 0;

View file

@ -126,7 +126,7 @@ namespace MWBase
virtual void setWaterHeight(const float height) = 0;
virtual void toggleWater() = 0;
virtual bool toggleWater() = 0;
virtual void adjustSky() = 0;
@ -200,6 +200,9 @@ namespace MWBase
virtual MWWorld::Ptr searchPtrViaHandle (const std::string& handle) = 0;
///< Return a pointer to a liveCellRef with the given Ogre handle or Ptr() if not found
virtual MWWorld::Ptr searchPtrViaActorId (int actorId) = 0;
///< Search is limited to the active cells.
/// \todo enable reference in the OGRE scene
virtual void enable (const MWWorld::Ptr& ptr) = 0;
@ -252,7 +255,8 @@ namespace MWBase
virtual void changeToExteriorCell (const ESM::Position& position) = 0;
///< Move to exterior cell.
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position) = 0;
virtual void changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool detectWorldSpaceChange=true) = 0;
///< @param detectWorldSpaceChange if true, clean up worldspace-specific data when the world space changes
virtual const ESM::Cell *getExterior (const std::string& cellName) const = 0;
///< Return a cell matching the given name or a 0-pointer, if there is no such cell.
@ -351,15 +355,14 @@ namespace MWBase
virtual void update (float duration, bool paused) = 0;
virtual bool placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
virtual MWWorld::Ptr placeObject (const MWWorld::Ptr& object, float cursorX, float cursorY, int amount) = 0;
///< copy and place an object into the gameworld at the specified cursor position
/// @param object
/// @param cursor X (relative 0-1)
/// @param cursor Y (relative 0-1)
/// @param number of objects to place
/// @return true if the object was placed, or false if it was rejected because the position is too far away
virtual void dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount) = 0;
virtual MWWorld::Ptr dropObjectOnGround (const MWWorld::Ptr& actor, const MWWorld::Ptr& object, int amount) = 0;
///< copy and place an object into the gameworld at the given actor's position
/// @param actor giving the dropped object position
/// @param object
@ -390,10 +393,10 @@ namespace MWBase
virtual void setupPlayer() = 0;
virtual void renderPlayer() = 0;
virtual bool getOpenOrCloseDoor(const MWWorld::Ptr& door) = 0;
///< if activated, should this door be opened or closed?
/// open or close a non-teleport door (depending on current state)
virtual void activateDoor(const MWWorld::Ptr& door) = 0;
///< activate (open or close) an non-teleport door
/// open or close a non-teleport door as specified
virtual void activateDoor(const MWWorld::Ptr& door, bool open) = 0;
virtual bool getPlayerStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if the player is standing on \a object
virtual bool getActorStandingOn (const MWWorld::Ptr& object) = 0; ///< @return true if any actor is standing on \a object
@ -465,7 +468,8 @@ namespace MWBase
virtual void castSpell (const MWWorld::Ptr& actor) = 0;
virtual void launchMagicBolt (const std::string& id, bool stack, const ESM::EffectList& effects,
virtual void launchMagicBolt (const std::string& model, const std::string& sound, const std::string& spellId,
float speed, bool stack, const ESM::EffectList& effects,
const MWWorld::Ptr& actor, const std::string& sourceName) = 0;
virtual void launchProjectile (MWWorld::Ptr actor, MWWorld::Ptr projectile,
const Ogre::Vector3& worldPos, const Ogre::Quaternion& orient, MWWorld::Ptr bow, float speed) = 0;
@ -511,7 +515,7 @@ namespace MWBase
/// Spawn a blood effect for \a ptr at \a worldPosition
virtual void spawnBloodEffect (const MWWorld::Ptr& ptr, const Ogre::Vector3& worldPosition) = 0;
virtual void explodeSpell (const Ogre::Vector3& origin, const MWWorld::Ptr& object, const ESM::EffectList& effects,
virtual void explodeSpell (const Ogre::Vector3& origin, const ESM::EffectList& effects,
const MWWorld::Ptr& caster, const std::string& id, const std::string& sourceName) = 0;
};
}

View file

@ -60,6 +60,24 @@ namespace MWClass
}
}
void Container::respawn(const MWWorld::Ptr &ptr) const
{
MWWorld::LiveCellRef<ESM::Container> *ref =
ptr.get<ESM::Container>();
if (ref->mBase->mFlags & ESM::Container::Respawn)
{
ptr.getRefData().setCustomData(NULL);
}
}
void Container::restock(const MWWorld::Ptr& ptr) const
{
MWWorld::LiveCellRef<ESM::Container> *ref = ptr.get<ESM::Container>();
const ESM::InventoryList& list = ref->mBase->mInventory;
MWWorld::ContainerStore& store = getContainerStore(ptr);
store.restock(list, ptr, ptr.getCellRef().mOwner, ptr.getCellRef().mFaction);
}
void Container::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const
{
const std::string model = getModel(ptr);

View file

@ -64,6 +64,10 @@ namespace MWClass
static void registerSelf();
virtual void respawn (const MWWorld::Ptr& ptr) const;
virtual void restock (const MWWorld::Ptr &ptr) const;
virtual std::string getModel(const MWWorld::Ptr &ptr) const;
};
}

Some files were not shown because too many files have changed in this diff Show more