Merge remote-tracking branch 'upstream/master'

Conflicts:
	apps/openmw/mwmechanics/aisequence.hpp
pull/99/head
Thomas 11 years ago
commit 645d174a96

@ -86,8 +86,6 @@ option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock fram
# Sound source selection # Sound source selection
option(USE_FFMPEG "use ffmpeg for sound" ON) option(USE_FFMPEG "use ffmpeg for sound" ON)
option(USE_AUDIERE "use audiere for sound" ON)
option(USE_MPG123 "use mpg123 + libsndfile for sound" ON)
# OS X deployment # OS X deployment
option(OPENMW_OSX_DEPLOYMENT OFF) option(OPENMW_OSX_DEPLOYMENT OFF)
@ -171,27 +169,6 @@ if (USE_FFMPEG)
endif (FFMPEG_FOUND) endif (FFMPEG_FOUND)
endif (USE_FFMPEG) endif (USE_FFMPEG)
if (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
find_package(Audiere)
if (AUDIERE_FOUND)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${AUDIERE_INCLUDE_DIR})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${AUDIERE_LIBRARY})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_AUDIERE)
set(GOT_SOUND_INPUT 1)
endif (AUDIERE_FOUND)
endif (USE_AUDIERE AND NOT GOT_SOUND_INPUT)
if (USE_MPG123 AND NOT GOT_SOUND_INPUT)
find_package(MPG123 REQUIRED)
find_package(SNDFILE REQUIRED)
if (MPG123_FOUND AND SNDFILE_FOUND)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123)
set(GOT_SOUND_INPUT 1)
endif (MPG123_FOUND AND SNDFILE_FOUND)
endif (USE_MPG123 AND NOT GOT_SOUND_INPUT)
if (NOT GOT_SOUND_INPUT) if (NOT GOT_SOUND_INPUT)
message(WARNING "--------------------") message(WARNING "--------------------")
message(WARNING "Failed to find any sound input packages") message(WARNING "Failed to find any sound input packages")
@ -368,8 +345,8 @@ configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg
"${OpenMW_BINARY_DIR}/openmw.cfg.install") "${OpenMW_BINARY_DIR}/openmw.cfg.install")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini
"${OpenMW_BINARY_DIR}/opencs.cfg") "${OpenMW_BINARY_DIR}/opencs.ini")
configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters
"${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY)
@ -450,7 +427,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}/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") 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) 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) ENDIF(BUILD_OPENCS)
# Install resources # Install resources
@ -479,7 +456,7 @@ if(WIN32)
ENDIF(BUILD_MWINIIMPORTER) ENDIF(BUILD_MWINIIMPORTER)
IF(BUILD_OPENCS) IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") 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) ENDIF(BUILD_OPENCS)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
@ -686,7 +663,7 @@ if (APPLE)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) 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}/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}/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_GENERATOR "DragNDrop")
set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION})

@ -5,11 +5,11 @@ opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG) set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc opencs_units (model/doc
document operation saving document operation saving documentmanager loader
) )
opencs_units_noqt (model/doc opencs_units_noqt (model/doc
documentmanager stage savingstate savingstages stage savingstate savingstages
) )
opencs_hdrs_noqt (model/doc opencs_hdrs_noqt (model/doc
@ -44,7 +44,7 @@ opencs_units_noqt (model/tools
opencs_units (view/doc opencs_units (view/doc
viewmanager view operations operation subview startup filedialog newgame viewmanager view operations operation subview startup filedialog newgame
filewidget adjusterwidget filewidget adjusterwidget loader
) )
@ -60,7 +60,7 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool
scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable
) )
opencs_units (view/render opencs_units (view/render
@ -97,6 +97,7 @@ opencs_units (view/settings
listview listview
rangeview rangeview
resizeablestackedwidget resizeablestackedwidget
spinbox
) )
opencs_units_noqt (view/settings opencs_units_noqt (view/settings
@ -105,7 +106,6 @@ opencs_units_noqt (view/settings
opencs_units (model/settings opencs_units (model/settings
usersettings usersettings
settingmanager
setting setting
connector connector
) )

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

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

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

@ -8,23 +8,6 @@
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#endif #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() void CSMDoc::Document::addGmsts()
{ {
static const char *gmstFloats[] = 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_) CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
: mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir), const std::vector< boost::filesystem::path >& files, bool new_,
mProjectPath ((configuration.getUserDataPath() / "projects") / const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
(savePath.filename().string() + ".project")), ToUTF8::FromType encoding)
mSaving (*this, mProjectPath) : 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"); throw std::runtime_error ("Empty content file sequence");
if (new_ && files.size()==1) if (!boost::filesystem::exists (mProjectPath))
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
{ {
boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath()); boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
locCustomFiltersPath /= "defaultfilters"; locCustomFiltersPath /= "defaultfilters";
if (boost::filesystem::exists(locCustomFiltersPath)) if (boost::filesystem::exists (locCustomFiltersPath))
{ {
boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath); boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath);
filtersFound = true;
} }
else else
{ {
boost::filesystem::path filters(mResDir); boost::filesystem::copy_file (mResDir / "defaultfilters", mProjectPath);
filters /= "defaultfilters";
if (boost::filesystem::exists(filters))
{
boost::filesystem::copy_file(filters, mProjectPath);
filtersFound = true;
}
} }
} }
if (filtersFound) if (mNew)
getData().loadFile (mProjectPath, false, true); {
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1)
createBase();
}
addOptionalGmsts(); addOptionalGmsts();
addOptionalGlobals(); 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 (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mSaving, SIGNAL (done (int)), this, SLOT (operationDone (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() CSMDoc::Document::~Document()
@ -2322,11 +2285,21 @@ const boost::filesystem::path& CSMDoc::Document::getSavePath() const
return mSavePath; return mSavePath;
} }
const boost::filesystem::path& CSMDoc::Document::getProjectPath() const
{
return mProjectPath;
}
const std::vector<boost::filesystem::path>& CSMDoc::Document::getContentFiles() const const std::vector<boost::filesystem::path>& CSMDoc::Document::getContentFiles() const
{ {
return mContentFiles; return mContentFiles;
} }
bool CSMDoc::Document::isNew() const
{
return mNew;
}
void CSMDoc::Document::save() void CSMDoc::Document::save()
{ {
if (mSaving.isRunning()) if (mSaving.isRunning())
@ -2358,10 +2331,11 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
emit stateChanged (getState(), this); 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. /// \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) void CSMDoc::Document::operationDone (int type)

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

@ -13,44 +13,88 @@
#include "document.hpp" #include "document.hpp"
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
: mConfiguration (configuration) : mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252)
{ {
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
if (!boost::filesystem::is_directory (projectPath)) if (!boost::filesystem::is_directory (projectPath))
boost::filesystem::create_directories (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() CSMDoc::DocumentManager::~DocumentManager()
{ {
mLoaderThread.quit();
mLoader.hasThingsToDo().wakeAll();
mLoaderThread.wait();
for (std::vector<Document *>::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter) for (std::vector<Document *>::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter)
delete *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_) 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); 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); std::vector<Document *>::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document);
if (iter==mDocuments.end()) if (iter==mDocuments.end())
throw std::runtime_error ("removing invalid document"); throw std::runtime_error ("removing invalid document");
mDocuments.erase (iter); mDocuments.erase (iter);
delete document; delete document;
return mDocuments.empty(); if (mDocuments.empty())
emit lastDocumentDeleted();
} }
void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir) void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir)
{ {
mResDir = boost::filesystem::system_complete(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);
}

@ -6,6 +6,13 @@
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <QObject>
#include <QThread>
#include <components/to_utf8/to_utf8.hpp>
#include "loader.hpp"
namespace Files namespace Files
{ {
class ConfigurationManager; class ConfigurationManager;
@ -15,10 +22,15 @@ namespace CSMDoc
{ {
class Document; class Document;
class DocumentManager class DocumentManager : public QObject
{ {
Q_OBJECT
std::vector<Document *> mDocuments; std::vector<Document *> mDocuments;
const Files::ConfigurationManager& mConfiguration; const Files::ConfigurationManager& mConfiguration;
QThread mLoaderThread;
Loader mLoader;
ToUTF8::FromType mEncoding;
DocumentManager (const DocumentManager&); DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&); DocumentManager& operator= (const DocumentManager&);
@ -29,20 +41,51 @@ namespace CSMDoc
~DocumentManager(); ~DocumentManager();
Document *addDocument (const std::vector< boost::filesystem::path >& files, void addDocument (const std::vector< boost::filesystem::path >& files,
const boost::filesystem::path& savePath, const boost::filesystem::path& savePath, bool new_);
bool new_); ///< \param new_ Do not load the last content file in \a files and instead create in an
///< 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
/// appropriate way. /// appropriate way.
bool removeDocument (Document *document);
///< \return last document removed?
void setResourceDir (const boost::filesystem::path& parResDir); void setResourceDir (const boost::filesystem::path& parResDir);
private: void setEncoding (ToUTF8::FromType encoding);
private:
boost::filesystem::path mResDir; 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);
}; };
} }

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

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

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

@ -5,6 +5,11 @@
#include <QThread> #include <QThread>
namespace CSMWorld
{
class UniversalId;
}
namespace CSMDoc namespace CSMDoc
{ {
class Stage; class Stage;
@ -46,7 +51,8 @@ namespace CSMDoc
void progress (int current, int max, int type); 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); void done (int type);

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

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

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

@ -39,7 +39,7 @@ namespace CSMDoc
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this stage will be appended to \a messages.
}; };
@ -57,7 +57,7 @@ namespace CSMDoc
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this stage will be appended to \a messages.
}; };
@ -75,7 +75,7 @@ namespace CSMDoc
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this stage will be appended to \a messages.
}; };
@ -92,7 +92,7 @@ namespace CSMDoc
} }
template<class CollectionT> 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; CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState;
@ -130,7 +130,7 @@ namespace CSMDoc
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this stage will be appended to \a messages.
}; };
@ -147,7 +147,7 @@ namespace CSMDoc
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< 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); 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. ///< Messages resulting from this stage will be appended to \a messages.
}; };
@ -177,7 +177,7 @@ namespace CSMDoc
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this stage will be appended to \a messages.
}; };
@ -193,7 +193,7 @@ namespace CSMDoc
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this stage will be appended to \a messages.
}; };
} }

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

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

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

@ -3,17 +3,18 @@
namespace CSMDoc namespace CSMDoc
{ {
enum State enum State
{ {
State_Modified = 1, State_Modified = 1,
State_Locked = 2, State_Locked = 2,
State_Operation = 4, State_Operation = 4,
State_Saving = 8, State_Saving = 8,
State_Verifying = 16, State_Verifying = 16,
State_Compiling = 32, // not implemented yet State_Compiling = 32, // not implemented yet
State_Searching = 64 // not implemented yet State_Searching = 64, // not implemented yet
}; State_Loading = 128 // pseudo-state; can not be encountered in a loaded document
};
} }
#endif #endif

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

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

@ -1,13 +1,8 @@
#include "setting.hpp" #include "setting.hpp"
#include "support.hpp" #include "support.hpp"
CSMSettings::Setting::Setting()
{
buildDefaultSetting();
}
CSMSettings::Setting::Setting(SettingType typ, const QString &settingName, CSMSettings::Setting::Setting(SettingType typ, const QString &settingName,
const QString &pageName, const QStringList &values) const QString &pageName)
: mIsEditorSetting (false) : mIsEditorSetting (false)
{ {
buildDefaultSetting(); buildDefaultSetting();
@ -19,10 +14,9 @@ CSMSettings::Setting::Setting(SettingType typ, const QString &settingName,
setProperty (Property_IsMultiValue, QVariant(true).toString()); setProperty (Property_IsMultiValue, QVariant(true).toString());
//view type is related to setting type by an order of magnitude //view type is related to setting type by an order of magnitude
setProperty (Property_ViewType, QVariant (settingType / 10).toString()); setProperty (Property_SettingType, QVariant (settingType).toString());
setProperty (Property_Page, pageName); setProperty (Property_Page, pageName);
setProperty (Property_Name, settingName); setProperty (Property_Name, settingName);
setProperty (Property_DeclaredValues, values);
} }
void CSMSettings::Setting::buildDefaultSetting() void CSMSettings::Setting::buildDefaultSetting()
@ -51,7 +45,7 @@ void CSMSettings::Setting::addProxy (const Setting *setting,
foreach (const QString &val, vals) foreach (const QString &val, vals)
list << (QStringList() << val); list << (QStringList() << val);
mProxies [setting->page() + '.' + setting->name()] = list; mProxies [setting->page() + '/' + setting->name()] = list;
} }
void CSMSettings::Setting::addProxy (const Setting *setting, void CSMSettings::Setting::addProxy (const Setting *setting,
@ -60,7 +54,7 @@ void CSMSettings::Setting::addProxy (const Setting *setting,
if (serializable()) if (serializable())
setProperty (Property_Serializable, false); setProperty (Property_Serializable, false);
mProxies [setting->page() + '.' + setting->name()] = list; mProxies [setting->page() + '/' + setting->name()] = list;
} }
void CSMSettings::Setting::setColumnSpan (int value) void CSMSettings::Setting::setColumnSpan (int value)
@ -73,19 +67,14 @@ int CSMSettings::Setting::columnSpan() const
return property (Property_ColumnSpan).at(0).toInt(); return property (Property_ColumnSpan).at(0).toInt();
} }
QStringList CSMSettings::Setting::declaredValues() const void CSMSettings::Setting::setDeclaredValues (QStringList list)
{ {
return property (Property_DeclaredValues); setProperty (Property_DeclaredValues, list);
} }
void CSMSettings::Setting::setDefinedValues (QStringList list) QStringList CSMSettings::Setting::declaredValues() const
{
setProperty (Property_DefinedValues, list);
}
QStringList CSMSettings::Setting::definedValues() const
{ {
return property (Property_DefinedValues); return property (Property_DeclaredValues);
} }
QStringList CSMSettings::Setting::property (SettingProperty prop) const QStringList CSMSettings::Setting::property (SettingProperty prop) const
@ -96,6 +85,16 @@ QStringList CSMSettings::Setting::property (SettingProperty prop) const
return mProperties.at(prop); return mProperties.at(prop);
} }
void CSMSettings::Setting::setDefaultValue (int value)
{
setDefaultValues (QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setDefaultValue (double value)
{
setDefaultValues (QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setDefaultValue (const QString &value) void CSMSettings::Setting::setDefaultValue (const QString &value)
{ {
setDefaultValues (QStringList() << value); setDefaultValues (QStringList() << value);
@ -165,6 +164,16 @@ bool CSMSettings::Setting::serializable() const
return (property (Property_Serializable).at(0) == "true"); return (property (Property_Serializable).at(0) == "true");
} }
void CSMSettings::Setting::setSpecialValueText(const QString &text)
{
setProperty (Property_SpecialValueText, text);
}
QString CSMSettings::Setting::specialValueText() const
{
return property (Property_SpecialValueText).at(0);
}
void CSMSettings::Setting::setName (const QString &value) void CSMSettings::Setting::setName (const QString &value)
{ {
setProperty (Property_Name, value); setProperty (Property_Name, value);
@ -185,6 +194,16 @@ QString CSMSettings::Setting::page() const
return property (Property_Page).at(0); return property (Property_Page).at(0);
} }
void CSMSettings::Setting::setPrefix (const QString &value)
{
setProperty (Property_Prefix, value);
}
QString CSMSettings::Setting::prefix() const
{
return property (Property_Prefix).at(0);
}
void CSMSettings::Setting::setRowSpan (const int value) void CSMSettings::Setting::setRowSpan (const int value)
{ {
setProperty (Property_RowSpan, value); setProperty (Property_RowSpan, value);
@ -195,15 +214,106 @@ int CSMSettings::Setting::rowSpan () const
return property (Property_RowSpan).at(0).toInt(); return property (Property_RowSpan).at(0).toInt();
} }
void CSMSettings::Setting::setViewType (int vType) void CSMSettings::Setting::setSingleStep (int value)
{ {
setProperty (Property_ViewType, vType); setProperty (Property_SingleStep, value);
}
void CSMSettings::Setting::setSingleStep (double value)
{
setProperty (Property_SingleStep, value);
}
QString CSMSettings::Setting::singleStep() const
{
return property (Property_SingleStep).at(0);
}
void CSMSettings::Setting::setSuffix (const QString &value)
{
setProperty (Property_Suffix, value);
}
QString CSMSettings::Setting::suffix() const
{
return property (Property_Suffix).at(0);
}
void CSMSettings::Setting::setTickInterval (int value)
{
setProperty (Property_TickInterval, value);
}
int CSMSettings::Setting::tickInterval () const
{
return property (Property_TickInterval).at(0).toInt();
}
void CSMSettings::Setting::setTicksAbove (bool state)
{
setProperty (Property_TicksAbove, state);
}
bool CSMSettings::Setting::ticksAbove() const
{
return (property (Property_TicksAbove).at(0) == "true");
}
void CSMSettings::Setting::setTicksBelow (bool state)
{
setProperty (Property_TicksBelow, state);
}
bool CSMSettings::Setting::ticksBelow() const
{
return (property (Property_TicksBelow).at(0) == "true");
}
void CSMSettings::Setting::setType (int settingType)
{
setProperty (Property_SettingType, settingType);
}
CSMSettings::SettingType CSMSettings::Setting::type() const
{
return static_cast <CSMSettings::SettingType> ( property (
Property_SettingType).at(0).toInt());
}
void CSMSettings::Setting::setMaximum (int value)
{
setProperty (Property_Maximum, value);
}
void CSMSettings::Setting::setMaximum (double value)
{
setProperty (Property_Maximum, value);
}
QString CSMSettings::Setting::maximum() const
{
return property (Property_Maximum).at(0);
}
void CSMSettings::Setting::setMinimum (int value)
{
setProperty (Property_Minimum, value);
}
void CSMSettings::Setting::setMinimum (double value)
{
setProperty (Property_Minimum, value);
}
QString CSMSettings::Setting::minimum() const
{
return property (Property_Minimum).at(0);
} }
CSVSettings::ViewType CSMSettings::Setting::viewType() const CSVSettings::ViewType CSMSettings::Setting::viewType() const
{ {
return static_cast <CSVSettings::ViewType> return static_cast <CSVSettings::ViewType> ( property (
(property(Property_ViewType).at(0).toInt()); Property_SettingType).at(0).toInt() / 10);
} }
void CSMSettings::Setting::setViewColumn (int value) void CSMSettings::Setting::setViewColumn (int value)
@ -241,6 +351,17 @@ int CSMSettings::Setting::widgetWidth() const
{ {
return property (Property_WidgetWidth).at(0).toInt(); return property (Property_WidgetWidth).at(0).toInt();
} }
void CSMSettings::Setting::setWrapping (bool state)
{
setProperty (Property_Wrapping, state);
}
bool CSMSettings::Setting::wrapping() const
{
return (property (Property_Wrapping).at(0) == "true");
}
void CSMSettings::Setting::setProperty (SettingProperty prop, bool value) void CSMSettings::Setting::setProperty (SettingProperty prop, bool value)
{ {
setProperty (prop, QStringList() << QVariant (value).toString()); setProperty (prop, QStringList() << QVariant (value).toString());
@ -251,6 +372,11 @@ void CSMSettings::Setting::setProperty (SettingProperty prop, int value)
setProperty (prop, QStringList() << QVariant (value).toString()); setProperty (prop, QStringList() << QVariant (value).toString());
} }
void CSMSettings::Setting::setProperty (SettingProperty prop, double value)
{
setProperty (prop, QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setProperty (SettingProperty prop, void CSMSettings::Setting::setProperty (SettingProperty prop,
const QString &value) const QString &value)
{ {
@ -263,18 +389,3 @@ void CSMSettings::Setting::setProperty (SettingProperty prop,
if (prop < mProperties.size()) if (prop < mProperties.size())
mProperties.replace (prop, value); mProperties.replace (prop, value);
} }
QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting)
{
// stream << setting.properties();
// stream << setting.proxies();
return stream;
}
QDataStream &operator >>(QDataStream& stream, CSMSettings::Setting& setting)
{
// stream >> setting.properties();
// stream >> setting.proxies();
return stream;
}

@ -7,11 +7,17 @@
namespace CSMSettings namespace CSMSettings
{ {
//Maps setting id ("page.name") to a list of corresponding proxy values. //QString is the setting id in the form of "page/name"
//Order of proxy value stringlists corresponds to order of master proxy's //QList is a list of stringlists of proxy values.
//values in it's declared value list //Order is important! Proxy stringlists are matched against
//master values by their position in the QList.
typedef QMap <QString, QList <QStringList> > ProxyValueMap; 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 class Setting
{ {
QList <QStringList> mProperties; QList <QStringList> mProperties;
@ -19,20 +25,12 @@ namespace CSMSettings
bool mIsEditorSetting; 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; ProxyValueMap mProxies;
public: public:
explicit Setting();
explicit Setting(SettingType typ, const QString &settingName, explicit Setting(SettingType typ, const QString &settingName,
const QString &pageName, const QString &pageName);
const QStringList &values = QStringList());
void addProxy (const Setting *setting, const QStringList &vals); void addProxy (const Setting *setting, const QStringList &vals);
void addProxy (const Setting *setting, const QList <QStringList> &list); void addProxy (const Setting *setting, const QList <QStringList> &list);
@ -46,9 +44,8 @@ namespace CSMSettings
void setDeclaredValues (QStringList list); void setDeclaredValues (QStringList list);
QStringList declaredValues() const; QStringList declaredValues() const;
void setDefinedValues (QStringList list); void setDefaultValue (int value);
QStringList definedValues() const; void setDefaultValue (double value);
void setDefaultValue (const QString &value); void setDefaultValue (const QString &value);
void setDefaultValues (const QStringList &values); void setDefaultValues (const QStringList &values);
@ -66,12 +63,26 @@ namespace CSMSettings
void setIsMultiValue (bool state); void setIsMultiValue (bool state);
bool isMultiValue() const; bool isMultiValue() const;
void setMask (const QString &value);
QString mask() const;
void setMaximum (int value);
void setMaximum (double value);
QString maximum() const;
void setMinimum (int value);
void setMinimum (double value);
QString minimum() const;
void setName (const QString &value); void setName (const QString &value);
QString name() const; QString name() const;
void setPage (const QString &value); void setPage (const QString &value);
QString page() const; QString page() const;
void setPrefix (const QString &value);
QString prefix() const;
void setRowSpan (const int value); void setRowSpan (const int value);
int rowSpan() const; int rowSpan() const;
@ -80,6 +91,25 @@ namespace CSMSettings
void setSerializable (bool state); void setSerializable (bool state);
bool serializable() const; bool serializable() const;
void setSpecialValueText (const QString &text);
QString specialValueText() const;
void setSingleStep (int value);
void setSingleStep (double value);
QString singleStep() const;
void setSuffix (const QString &value);
QString suffix() const;
void setTickInterval (int value);
int tickInterval() const;
void setTicksAbove (bool state);
bool ticksAbove() const;
void setTicksBelow (bool state);
bool ticksBelow() const;
void setViewColumn (int value); void setViewColumn (int value);
int viewColumn() const; int viewColumn() const;
@ -88,9 +118,14 @@ namespace CSMSettings
void setViewRow (int value); void setViewRow (int value);
int viewRow() const; int viewRow() const;
void setViewType (int vType); void setType (int settingType);
CSMSettings::SettingType type() const;
CSVSettings::ViewType viewType() const; CSVSettings::ViewType viewType() const;
void setWrapping (bool state);
bool wrapping() const;
void setWidgetWidth (int value); void setWidgetWidth (int value);
int widgetWidth() const; int widgetWidth() const;
@ -100,6 +135,7 @@ namespace CSMSettings
///boilerplate code to convert setting values of common types ///boilerplate code to convert setting values of common types
void setProperty (SettingProperty prop, bool value); void setProperty (SettingProperty prop, bool value);
void setProperty (SettingProperty prop, int value); void setProperty (SettingProperty prop, int value);
void setProperty (SettingProperty prop, double value);
void setProperty (SettingProperty prop, const QString &value); void setProperty (SettingProperty prop, const QString &value);
void setProperty (SettingProperty prop, const QStringList &value); void setProperty (SettingProperty prop, const QStringList &value);
@ -111,9 +147,4 @@ namespace CSMSettings
}; };
} }
Q_DECLARE_METATYPE(CSMSettings::Setting)
QDataStream &operator <<(QDataStream &stream, const CSMSettings::Setting& setting);
QDataStream &operator >>(QDataStream &stream, CSMSettings::Setting& setting);
#endif // CSMSETTINGS_SETTING_HPP #endif // CSMSETTINGS_SETTING_HPP

@ -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,
const QStringList &values)
{
//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, values);
//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);
}

@ -1,85 +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,
const QStringList &values = QStringList());
///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

@ -7,27 +7,15 @@
#include <QVariant> #include <QVariant>
#include <QStringList> #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 //Enums
namespace CSMSettings namespace CSMSettings
{ {
///Enumerated properties for scripting
enum SettingProperty enum SettingProperty
{ {
Property_Name = 0, Property_Name = 0,
Property_Page = 1, Property_Page = 1,
Property_ViewType = 2, Property_SettingType = 2,
Property_IsMultiValue = 3, Property_IsMultiValue = 3,
Property_IsMultiLine = 4, Property_IsMultiLine = 4,
Property_WidgetWidth = 5, Property_WidgetWidth = 5,
@ -37,14 +25,25 @@ namespace CSMSettings
Property_Serializable = 9, Property_Serializable = 9,
Property_ColumnSpan = 10, Property_ColumnSpan = 10,
Property_RowSpan = 11, Property_RowSpan = 11,
Property_Minimum = 12,
Property_Maximum = 13,
Property_SpecialValueText = 14,
Property_Prefix = 15,
Property_Suffix = 16,
Property_SingleStep = 17,
Property_Wrapping = 18,
Property_TickInterval = 19,
Property_TicksAbove = 20,
Property_TicksBelow = 21,
//Stringlists should always be the last items //Stringlists should always be the last items
Property_DefaultValues = 12, Property_DefaultValues = 22,
Property_DeclaredValues = 13, Property_DeclaredValues = 23,
Property_DefinedValues = 14, Property_DefinedValues = 24,
Property_Proxies = 15 Property_Proxies = 25
}; };
///Basic setting widget types.
enum SettingType enum SettingType
{ {
/* /*
@ -64,22 +63,19 @@ namespace CSMSettings
Type_ListView = 10, Type_ListView = 10,
Type_ComboBox = 11, Type_ComboBox = 11,
Type_SpinBox = 21, Type_SpinBox = 21,
Type_Slider = 23, Type_DoubleSpinBox = 23,
Type_Dial = 24, Type_Slider = 25,
Type_Dial = 27,
Type_TextArea = 30, Type_TextArea = 30,
Type_LineEdit = 31 Type_LineEdit = 31,
Type_Undefined = 40
}; };
enum MergeMethod
{
Merge_Accept,
Merge_Ignore,
Merge_Overwrite
};
} }
namespace CSVSettings namespace CSVSettings
{ {
///Categorical view types which encompass the setting widget types
enum ViewType enum ViewType
{ {
ViewType_Boolean = 0, ViewType_Boolean = 0,
@ -88,18 +84,12 @@ namespace CSVSettings
ViewType_Text = 3, ViewType_Text = 3,
ViewType_Undefined = 4 ViewType_Undefined = 4
}; };
enum Alignment
{
Align_Left = Qt::AlignLeft,
Align_Center = Qt::AlignHCenter,
Align_Right = Qt::AlignRight
};
} }
//
namespace CSMSettings namespace CSMSettings
{ {
///used to construct default settings in the Setting class
struct PropertyDefaultValues struct PropertyDefaultValues
{ {
int id; int id;
@ -107,28 +97,44 @@ namespace CSMSettings
QVariant value; 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[] = const QString sPropertyNames[] =
{ {
"name", "page", "view_type", "is_multi_value", "name", "page", "setting_type", "is_multi_value",
"is_multi_line", "widget_width", "view_row", "view_column", "delimiter", "is_multi_line", "widget_width", "view_row", "view_column", "delimiter",
"is_serializable","column_span", "row_span", "is_serializable","column_span", "row_span", "minimum", "maximum",
"special_value_text", "prefix", "suffix", "single_step", "wrapping",
"tick_interval", "ticks_above", "ticks_below",
"defaults", "declarations", "definitions", "proxies" "defaults", "declarations", "definitions", "proxies"
}; };
///Default values for a setting. Used in setting creation.
const QString sPropertyDefaults[] = const QString sPropertyDefaults[] =
{ {
"", //name "", //name
"", //page "", //page
"0", //view type "40", //setting type
"false", //multivalue "false", //multivalue
"false", //multiline "false", //multiline
"0", //widget width "7", //widget width
"-1", //view row "-1", //view row
"-1", //view column "-1", //view column
",", //delimiter ",", //delimiter
"true", //serialized "true", //serialized
"1", //column span "1", //column span
"1", //row span "1", //row span
"0", //value range
"0", //value minimum
"0", //value maximum
"", //special text
"", //prefix
"", //suffix
"false", //wrapping
"1", //tick interval
"false", //ticks above
"true", //ticks below
"", //default values "", //default values
"", //declared values "", //declared values
"", //defined values "", //defined values

@ -1,21 +1,14 @@
#include "usersettings.hpp" #include "usersettings.hpp"
#include <QTextStream> #include <QSettings>
#include <QDir>
#include <QString>
#include <QRegExp>
#include <QMap>
#include <QMessageBox>
#include <QTextCodec>
#include <QFile> #include <QFile>
#include <QSortFilterProxyModel>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
#include "setting.hpp" #include "setting.hpp"
#include "support.hpp" #include "support.hpp"
#include <QDebug>
/** /**
* Workaround for problems with whitespaces in paths in older versions of Boost library * 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 *CSMSettings::UserSettings::mUserSettingsInstance = 0;
CSMSettings::UserSettings::UserSettings() CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager)
: mCfgMgr (configurationManager)
{ {
assert(!mUserSettingsInstance); assert(!mUserSettingsInstance);
mUserSettingsInstance = this; mUserSettingsInstance = this;
mSettingDefinitions = 0;
buildSettingModelDefaults(); buildSettingModelDefaults();
} }
@ -51,7 +47,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
Setting *height = createSetting (Type_LineEdit, section, "Height"); Setting *height = createSetting (Type_LineEdit, section, "Height");
width->setWidgetWidth (5); width->setWidgetWidth (5);
height->setWidgetWidth (5); height->setWidgetWidth (8);
width->setDefaultValues (QStringList() << "1024"); width->setDefaultValues (QStringList() << "1024");
height->setDefaultValues (QStringList() << "768"); height->setDefaultValues (QStringList() << "768");
@ -66,13 +62,10 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
*Create the proxy setting for predefined values *Create the proxy setting for predefined values
*/ */
Setting *preDefined = createSetting (Type_ComboBox, section, Setting *preDefined = createSetting (Type_ComboBox, section,
"Pre-Defined", "Pre-Defined");
QStringList()
<< "640 x 480" preDefined->setDeclaredValues (QStringList() << "640 x 480"
<< "800 x 600" << "800 x 600" << "1024 x 768" << "1440 x 900");
<< "1024 x 768"
<< "1440 x 900"
);
preDefined->setViewLocation (1, 1); preDefined->setViewLocation (1, 1);
preDefined->setWidgetWidth (10); preDefined->setWidgetWidth (10);
@ -95,12 +88,13 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
<< defaultValue << "Icon Only" << "Text Only"; << defaultValue << "Icon Only" << "Text Only";
Setting *rsd = createSetting (Type_RadioButton, Setting *rsd = createSetting (Type_RadioButton,
section, "Record Status Display", section, "Record Status Display");
values);
Setting *ritd = createSetting (Type_RadioButton, Setting *ritd = createSetting (Type_RadioButton,
section, "Referenceable ID Type Display", section, "Referenceable ID Type Display");
values);
rsd->setDeclaredValues (values);
ritd->setDeclaredValues (values);
rsd->setEditorSetting (true); rsd->setEditorSetting (true);
ritd->setEditorSetting (true); ritd->setEditorSetting (true);
@ -108,44 +102,68 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
section = "Proxy Selection Test"; section = "Proxy Selection Test";
{ {
//create three setting objects, specifying the basic widget type, /******************************************************************
//the setting view name, the page name, and the default value * There are three types of values:
*
* Declared values
*
* Pre-determined values, typically for
* combobox drop downs and boolean (radiobutton / checkbox) labels.
* These values represent the total possible list of values that
* may define a setting. No other values are allowed.
*
* 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.
*
* 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, Setting *masterBoolean = createSetting (Type_RadioButton, section,
"Master Proxy", "Master Proxy");
QStringList()
<< "Profile One" << "Profile Two"
<< "Profile Three" << "Profile Four"
);
Setting *slaveBoolean = createSetting (Type_CheckBox, section, Setting *slaveBoolean = createSetting (Type_CheckBox, section,
"Proxy Checkboxes", "Proxy Checkboxes");
QStringList() << "One" << "Two"
<< "Three" << "Four" << "Five"
);
Setting *slaveSingleText = createSetting (Type_LineEdit, section, Setting *slaveSingleText = createSetting (Type_LineEdit, section,
"Proxy TextBox 1" "Proxy TextBox 1");
);
Setting *slaveMultiText = createSetting (Type_LineEdit, section, Setting *slaveMultiText = createSetting (Type_LineEdit, section,
"ProxyTextBox 2" "ProxyTextBox 2");
);
Setting *slaveAlphaSpinbox = createSetting (Type_SpinBox, section,
// There are three types of values: "Alpha Spinbox");
//
// Declared values - Pre-determined values, typically for Setting *slaveIntegerSpinbox = createSetting (Type_SpinBox, section,
// combobox drop downs and boolean (radiobutton / checkbox) labels. "Int Spinbox");
// These values represent the total possible list of values that may
// define a setting. No other values are allowed. Setting *slaveDoubleSpinbox = createSetting (Type_DoubleSpinBox,
// section, "Double Spinbox");
// Defined values - Values which represent the atual, current value of
// a setting. For settings with declared values, this must be one or Setting *slaveSlider = createSetting (Type_Slider, section, "Slider");
// several declared values, as appropriate.
// Setting *slaveDial = createSetting (Type_Dial, section, "Dial");
// Proxy values - values the proxy master updates the proxy slave when
// it's own definition is set / changed. These are definitions for //set declared values for selected views
// proxy slave settings, but must match any declared values the proxy masterBoolean->setDeclaredValues (QStringList()
// slave has, if any. << "Profile One" << "Profile Two"
<< "Profile Three" << "Profile Four");
slaveBoolean->setDeclaredValues (QStringList()
<< "One" << "Two" << "Three" << "Four" << "Five");
slaveAlphaSpinbox->setDeclaredValues (QStringList()
<< "One" << "Two" << "Three" << "Four");
masterBoolean->addProxy (slaveBoolean, QList <QStringList>() masterBoolean->addProxy (slaveBoolean, QList <QStringList>()
<< (QStringList() << "One" << "Three") << (QStringList() << "One" << "Three")
@ -168,11 +186,48 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
<< (QStringList() << "Two" << "Four") << (QStringList() << "Two" << "Four")
); );
masterBoolean->addProxy (slaveAlphaSpinbox, QList <QStringList>()
<< (QStringList() << "Four")
<< (QStringList() << "Three")
<< (QStringList() << "Two")
<< (QStringList() << "One"));
masterBoolean->addProxy (slaveIntegerSpinbox, QList <QStringList> ()
<< (QStringList() << "0")
<< (QStringList() << "7")
<< (QStringList() << "14")
<< (QStringList() << "21"));
masterBoolean->addProxy (slaveDoubleSpinbox, QList <QStringList> ()
<< (QStringList() << "0.17")
<< (QStringList() << "0.34")
<< (QStringList() << "0.51")
<< (QStringList() << "0.68"));
masterBoolean->addProxy (slaveSlider, QList <QStringList> ()
<< (QStringList() << "25")
<< (QStringList() << "50")
<< (QStringList() << "75")
<< (QStringList() << "100")
);
masterBoolean->addProxy (slaveDial, QList <QStringList> ()
<< (QStringList() << "25")
<< (QStringList() << "50")
<< (QStringList() << "75")
<< (QStringList() << "100")
);
//settings with proxies are not serialized by default //settings with proxies are not serialized by default
//other settings non-serialized for demo purposes //other settings non-serialized for demo purposes
slaveBoolean->setSerializable (false); slaveBoolean->setSerializable (false);
slaveSingleText->setSerializable (false); slaveSingleText->setSerializable (false);
slaveMultiText->setSerializable (false); slaveMultiText->setSerializable (false);
slaveAlphaSpinbox->setSerializable (false);
slaveIntegerSpinbox->setSerializable (false);
slaveDoubleSpinbox->setSerializable (false);
slaveSlider->setSerializable (false);
slaveDial->setSerializable (false);
slaveBoolean->setDefaultValues (QStringList() slaveBoolean->setDefaultValues (QStringList()
<< "One" << "Three" << "Five"); << "One" << "Three" << "Five");
@ -184,7 +239,39 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
slaveSingleText->setWidgetWidth (24); slaveSingleText->setWidgetWidth (24);
slaveMultiText->setWidgetWidth (24); slaveMultiText->setWidgetWidth (24);
}
slaveAlphaSpinbox->setDefaultValue ("Two");
slaveAlphaSpinbox->setWidgetWidth (20);
//slaveAlphaSpinbox->setPrefix ("No. ");
//slaveAlphaSpinbox->setSuffix ("!");
slaveAlphaSpinbox->setWrapping (true);
slaveIntegerSpinbox->setDefaultValue (14);
slaveIntegerSpinbox->setMinimum (0);
slaveIntegerSpinbox->setMaximum (58);
slaveIntegerSpinbox->setPrefix ("$");
slaveIntegerSpinbox->setSuffix (".00");
slaveIntegerSpinbox->setWidgetWidth (10);
slaveIntegerSpinbox->setSpecialValueText ("Nothing!");
slaveDoubleSpinbox->setDefaultValue (0.51);
slaveDoubleSpinbox->setSingleStep(0.17);
slaveDoubleSpinbox->setMaximum(4.0);
slaveSlider->setMinimum (0);
slaveSlider->setMaximum (100);
slaveSlider->setDefaultValue (75);
slaveSlider->setWidgetWidth (100);
slaveSlider->setTicksAbove (true);
slaveSlider->setTickInterval (25);
slaveDial->setMinimum (0);
slaveDial->setMaximum (100);
slaveDial->setSingleStep (5);
slaveDial->setDefaultValue (75);
slaveDial->setTickInterval (25);
*/
}
} }
CSMSettings::UserSettings::~UserSettings() CSMSettings::UserSettings::~UserSettings()
@ -194,86 +281,147 @@ CSMSettings::UserSettings::~UserSettings()
void CSMSettings::UserSettings::loadSettings (const QString &fileName) void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{ {
mUserFilePath = QString::fromUtf8 QString userFilePath = QString::fromUtf8
(mCfgMgr.getUserConfigPath().string().c_str()) + fileName.toUtf8(); (mCfgMgr.getUserConfigPath().string().c_str());
QString global = QString::fromUtf8 QString globalFilePath = QString::fromUtf8
(mCfgMgr.getGlobalPath().string().c_str()) + fileName.toUtf8(); (mCfgMgr.getGlobalPath().string().c_str());
QString local = QString::fromUtf8 QString otherFilePath = globalFilePath;
(mCfgMgr.getLocalPath().string().c_str()) + fileName.toUtf8();
//open user and global streams //test for local only if global fails (uninstalled copy)
QTextStream *userStream = openFilestream (mUserFilePath, true); if (!QFile (globalFilePath + fileName).exists())
QTextStream *otherStream = openFilestream (global, true); {
//if global is invalid, use the local path
otherFilePath = QString::fromUtf8
(mCfgMgr.getLocalPath().string().c_str());
}
//failed stream, try for local QSettings::setPath
if (!otherStream) (QSettings::IniFormat, QSettings::UserScope, userFilePath);
otherStream = openFilestream (local, true);
//error condition - notify and return QSettings::setPath
if (!otherStream || !userStream) (QSettings::IniFormat, QSettings::SystemScope, otherFilePath);
{
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; mSettingDefinitions = new QSettings
message += QObject::tr("<br>Local filepath: ") + local; (QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this);
message += QObject::tr("<br>User filepath: ") + mUserFilePath; }
displayFileErrorMessage ( message, true); bool CSMSettings::UserSettings::hasSettingDefinitions
return; (const QString &viewKey) const
} {
return (mSettingDefinitions->contains (viewKey));
}
void CSMSettings::UserSettings::setDefinitions
(const QString &key, const QStringList &list)
{
mSettingDefinitions->setValue (key, list);
}
void CSMSettings::UserSettings::saveDefinitions() const
{
mSettingDefinitions->sync();
}
//success condition - merge the two streams into a single map and save QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
DefinitionPageMap totalMap = readFilestream (userStream); {
DefinitionPageMap otherMap = readFilestream(otherStream); if (!mSettingDefinitions->contains (settingKey))
return QString();
//merging other settings file in and ignore duplicate settings to QStringList defs = mSettingDefinitions->value (settingKey).toStringList();
//avoid overwriting user-level settings
mergeSettings (totalMap, otherMap);
if (!totalMap.isEmpty()) if (defs.isEmpty())
addDefinitions (totalMap); return QString();
return defs.at(0);
} }
void CSMSettings::UserSettings::saveSettings CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
(const QMap <QString, QStringList> &settingMap)
{ {
for (int i = 0; i < settings().size(); i++) assert(mUserSettingsInstance);
{ return *mUserSettingsInstance;
Setting* setting = settings().at(i); }
QString key = setting->page() + '.' + setting->name(); void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
const QStringList &list)
{
mSettingDefinitions->setValue (settingKey ,list);
if (!settingMap.keys().contains(key)) emit userSettingUpdated (settingKey, list);
continue; }
setting->setDefinedValues (settingMap.value(key)); 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;
writeFilestream (openFilestream (mUserFilePath, false), settingMap); QList <Setting *>::iterator removeIterator = mSettings.begin();
while (removeIterator != mSettings.end())
{
if ((*removeIterator)->name() == settingName)
{
if ((*removeIterator)->page() == pageName)
{
mSettings.erase (removeIterator);
break;
}
}
removeIterator++;
}
} }
QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const
{ {
QStringList names = settingKey.split('.'); SettingPageMap pageMap;
foreach (Setting *setting, mSettings)
pageMap[setting->page()].append (setting);
Setting *setting = findSetting(names.at(0), names.at(1)); return pageMap;
}
if (setting) 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))
{ {
if (!setting->definedValues().isEmpty()) qWarning() << "Duplicate declaration encountered: "
return setting->definedValues().at(0); << (name + '/' + page);
return 0;
} }
return "";
Setting *setting = new Setting (typ, name, page);
//add declaration to the model
mSettings.append (setting);
return setting;
} }
CSMSettings::UserSettings& CSMSettings::UserSettings::instance() QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const
{ {
assert(mUserSettingsInstance); if (mSettingDefinitions->contains (viewKey))
return *mUserSettingsInstance; return mSettingDefinitions->value (viewKey).toStringList();
return QStringList();
} }

@ -1,14 +1,13 @@
#ifndef USERSETTINGS_HPP #ifndef USERSETTINGS_HPP
#define USERSETTINGS_HPP #define USERSETTINGS_HPP
#include <QTextStream> #include <QList>
#include <QStringList> #include <QStringList>
#include <QString> #include <QString>
#include <QMap> #include <QMap>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include "support.hpp"
#include "settingmanager.hpp"
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
@ -18,46 +17,79 @@ namespace Files { typedef std::vector<boost::filesystem::path> PathContainer;
struct ConfigurationManager;} struct ConfigurationManager;}
class QFile; class QFile;
class QSettings;
namespace CSMSettings { namespace CSMSettings {
class UserSettings: public SettingManager class Setting;
typedef QMap <QString, QList <Setting *> > SettingPageMap;
class UserSettings: public QObject
{ {
Q_OBJECT Q_OBJECT
static UserSettings *mUserSettingsInstance; static UserSettings *mUserSettingsInstance;
QString mUserFilePath; const Files::ConfigurationManager& mCfgMgr;
Files::ConfigurationManager mCfgMgr;
QString mReadOnlyMessage; QSettings *mSettingDefinitions;
QString mReadWriteMessage; QList <Setting *> mSettings;
public: public:
/// Singleton implementation /// Singleton implementation
static UserSettings& instance(); static UserSettings& instance();
UserSettings(); UserSettings (const Files::ConfigurationManager& configurationManager);
~UserSettings(); ~UserSettings();
UserSettings (UserSettings const &); //not implemented UserSettings (UserSettings const &); //not implemented
void operator= (UserSettings const &); //not implemented UserSettings& operator= (UserSettings const &); //not implemented
/// Writes settings to the last loaded settings file
bool writeSettings();
/// Retrieves the settings file at all three levels (global, local and user). /// Retrieves the settings file at all three levels (global, local and user).
void loadSettings (const QString &fileName); void loadSettings (const QString &fileName);
/// Writes settings to the user's config file path /// Updates QSettings and syncs with the ini file
void saveSettings (const QMap <QString, QStringList > &settingMap); void setDefinitions (const QString &key, const QStringList &defs);
QString settingValue (const QString &settingKey); 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: private:
void buildSettingModelDefaults(); 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 #endif // USERSETTINGS_HPP

@ -17,7 +17,7 @@ int CSMTools::BirthsignCheckStage::setup()
return mBirthsigns.getSize(); 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); 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 // test for empty name, description and texture
if (birthsign.mName.empty()) 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()) 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()) 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 /// \todo test if the texture exists

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

@ -18,7 +18,7 @@ int CSMTools::ClassCheckStage::setup()
return mClasses.getSize(); 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); 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 // test for empty name and description
if (class_.mName.empty()) 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()) 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 // test for invalid attributes
for (int i=0; i<2; ++i) 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; 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) if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1)
{ {
std::ostringstream stream; messages.push_back (std::make_pair (id, "Class lists same attribute twice"));
stream << id.toString() << "|Class lists same attribute twice";
messages.push_back (stream.str());
} }
// test for non-unique skill // 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) for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
if (iter->second>1) if (iter->second>1)
{ {
std::ostringstream stream; messages.push_back (std::make_pair (id,
ESM::Skill::indexToId (iter->first) + " is listed more than once"));
stream
<< id.toString() << "|"
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
messages.push_back (stream.str());
} }
} }

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

@ -18,7 +18,7 @@ int CSMTools::FactionCheckStage::setup()
return mFactions.getSize(); 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); 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 // test for empty name
if (faction.mName.empty()) 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 // test for invalid attributes
if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1)
{ {
std::ostringstream stream; messages.push_back (std::make_pair (id , "Faction lists same attribute twice"));
stream << id.toString() << "|Faction lists same attribute twice";
messages.push_back (stream.str());
} }
// test for non-unique skill // 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) for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter)
if (iter->second>1) if (iter->second>1)
{ {
std::ostringstream stream; messages.push_back (std::make_pair (id,
ESM::Skill::indexToId (iter->first) + " is listed more than once"));
stream
<< id.toString() << "|"
<< ESM::Skill::indexToId (iter->first) << " is listed more than once";
messages.push_back (stream.str());
} }
/// \todo check data members that can't be edited in the table view /// \todo check data members that can't be edited in the table view

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

@ -15,9 +15,10 @@ int CSMTools::MandatoryIdStage::setup()
return mIds.size(); 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 || if (mIdCollection.searchId (mIds.at (stage))==-1 ||
mIdCollection.getRecord (mIds.at (stage)).isDeleted()) 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)));
} }

@ -30,7 +30,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

@ -7,7 +7,7 @@
#include "../world/universalid.hpp" #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); 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 // test for empty name and description
if (race.mName.empty()) 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()) 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 // test for positive height
if (race.mData.mHeight.mMale<=0) 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) 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 // test for non-negative weight
if (race.mData.mWeight.mMale<0) 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) 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 // remember playable flag
if (race.mData.mFlags & 0x1) 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 /// \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); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races);
if (!mPlayable) 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) CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races)
@ -64,7 +64,7 @@ int CSMTools::RaceCheckStage::setup()
return mRaces.getSize()+1; 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()) if (stage==mRaces.getSize())
performFinal (messages); performFinal (messages);

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

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

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

@ -17,7 +17,7 @@ int CSMTools::RegionCheckStage::setup()
return mRegions.getSize(); 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); 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 // test for empty name
if (region.mName.empty()) 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 /// \todo test that the ID in mSleeplist exists

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

@ -51,16 +51,11 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true; 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()); 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(); endInsertRows();
} }

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

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

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

@ -16,7 +16,7 @@ int CSMTools::SkillCheckStage::setup()
return mSkills.getSize(); 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); 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; 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()) 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"));
} }

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

@ -16,7 +16,7 @@ int CSMTools::SoundCheckStage::setup()
return mSounds.getSize(); 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); 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); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId);
if (sound.mData.mMinRange>sound.mData.mMaxRange) 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 /// \todo check, if the sound file exists
} }

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

@ -17,7 +17,7 @@ int CSMTools::SpellCheckStage::setup()
return mSpells.getSize(); 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); 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 // test for empty name and description
if (spell.mName.empty()) 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 // test for invalid cost values
if (spell.mData.mCost<0) 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 /// \todo check data members that can't be edited in the table view
} }

@ -21,7 +21,7 @@ namespace CSMTools
virtual int setup(); virtual int setup();
///< \return number of steps ///< \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. ///< Messages resulting from this tage will be appended to \a messages.
}; };
} }

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

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

@ -55,7 +55,8 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
return number; 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 StringIdColumn<ESM::Global>);
mGlobals.addColumn (new RecordStateColumn<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) for (std::vector<QAbstractItemModel *>::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter)
delete *iter; delete *iter;
delete mReader;
} }
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
@ -453,7 +456,7 @@ CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters()
return mFilters; return mFilters;
} }
QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
{ {
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType()); std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -481,148 +484,166 @@ void CSMWorld::Data::merge()
mGlobals.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;
mReader = new ESM::ESMReader;
mReader->setEncoder (&mEncoder);
mReader->open (path.string());
/// \todo set encoding properly, once config implementation has been fixed. mBase = base;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252")); mProject = project;
reader.setEncoder (&encoder);
reader.open (path.string()); mAuthor = mReader->getAuthor();
mDescription = mReader->getDesc();
const ESM::Dialogue *dialogue = 0; return mReader->getRecordCount();
}
mAuthor = reader.getAuthor(); bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
mDescription = reader.getDesc(); {
if (!mReader)
throw std::logic_error ("can't continue loading, because no load has been started");
// Note: We do not need to send update signals here, because at this point the model is not connected if (!mReader->hasMoreRecs())
// to any view.
while (reader.hasMoreRecs())
{ {
ESM::NAME n = reader.getRecName(); delete mReader;
reader.getRecHeader(); mReader = 0;
mDialogue = 0;
return true;
}
ESM::NAME n = mReader->getRecName();
mReader->getRecHeader();
switch (n.val) 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:
{ {
case ESM::REC_GLOB: mGlobals.load (reader, base); break; std::string id = mReader->getHNOString ("NAME");
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; ESM::Dialogue record;
case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break; record.mId = id;
case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break; record.load (*mReader);
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; if (record.mType==ESM::Dialogue::Journal)
record.mId = id; {
record.load (reader); 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 (record.mType==ESM::Dialogue::Journal) if (mJournals.tryDelete (id))
{ {
mJournals.load (record, base); /// \todo handle info records
dialogue = &mJournals.getRecord (id).get();
} }
else if (record.mType==ESM::Dialogue::Deleted) else if (mTopics.tryDelete (id))
{ {
dialogue = 0; // record vector can be shuffled around which would make pointer /// \todo handle info records
// 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 else
{ {
mTopics.load (record, base); messages.push_back (std::make_pair (UniversalId::Type_None,
dialogue = &mTopics.getRecord (id).get(); "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; break;
} }
case ESM::REC_INFO: if (mDialogue->mType==ESM::Dialogue::Journal)
{ mJournalInfos.load (*mReader, mBase, *mDialogue);
if (!dialogue) else
{ mTopicInfos.load (*mReader, mBase, *mDialogue);
/// \todo INFO record without matching DIAL record -> report to user
reader.skipRecord();
break;
}
if (dialogue->mType==ESM::Dialogue::Journal) break;
mJournalInfos.load (reader, base, *dialogue); }
else
mTopicInfos.load (reader, base, *dialogue); 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; break;
} }
case ESM::REC_FILT: // fall through (filter record in a content file is an error with format 0)
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:
default: messages.push_back (std::make_pair (UniversalId::Type_None,
"Unsupported record type: " + n.toString()));
/// \todo throw an exception instead, once all records are implemented mReader->skipRecord();
/// or maybe report error and continue?
reader.skipRecord();
}
} }
return false;
} }
bool CSMWorld::Data::hasId (const std::string& id) const bool CSMWorld::Data::hasId (const std::string& id) const

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

@ -1,6 +1,9 @@
#include "tablemimedata.hpp" #include "tablemimedata.hpp"
#include <string> #include <string>
#include <QDebug>
#include "universalid.hpp" #include "universalid.hpp"
#include "columnbase.hpp" #include "columnbase.hpp"
@ -11,7 +14,7 @@ mDocument(document)
mObjectsFormats << QString::fromUtf8 (("tabledata/" + id.getTypeName()).c_str()); mObjectsFormats << QString::fromUtf8 (("tabledata/" + id.getTypeName()).c_str());
} }
CSMWorld::TableMimeData::TableMimeData (std::vector< CSMWorld::UniversalId >& id, const CSMDoc::Document& document) : CSMWorld::TableMimeData::TableMimeData (const std::vector< CSMWorld::UniversalId >& id, const CSMDoc::Document& document) :
mUniversalId (id), mDocument(document) mUniversalId (id), mDocument(document)
{ {
for (std::vector<UniversalId>::iterator it (mUniversalId.begin()); it != mUniversalId.end(); ++it) for (std::vector<UniversalId>::iterator it (mUniversalId.begin()); it != mUniversalId.end(); ++it)
@ -33,7 +36,8 @@ std::string CSMWorld::TableMimeData::getIcon() const
{ {
if (mUniversalId.empty()) if (mUniversalId.empty())
{ {
throw ("TableMimeData holds no UniversalId"); qDebug()<<"TableMimeData object does not hold any records!"; //because throwing in the event loop tends to be problematic
throw("TableMimeData object does not hold any records!");
} }
std::string tmpIcon; std::string tmpIcon;
@ -50,7 +54,7 @@ std::string CSMWorld::TableMimeData::getIcon() const
if (tmpIcon != mUniversalId[i].getIcon()) if (tmpIcon != mUniversalId[i].getIcon())
{ {
return ":/multitype.png"; //icon stolen from gnome return ":/multitype.png"; //icon stolen from gnome TODO: get new icon
} }
tmpIcon = mUniversalId[i].getIcon(); tmpIcon = mUniversalId[i].getIcon();
@ -531,4 +535,4 @@ CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::U
const CSMDoc::Document* CSMWorld::TableMimeData::getDocumentPtr() const const CSMDoc::Document* CSMWorld::TableMimeData::getDocumentPtr() const
{ {
return &mDocument; return &mDocument;
} }

@ -33,7 +33,7 @@ namespace CSMWorld
public: public:
TableMimeData(UniversalId id, const CSMDoc::Document& document); TableMimeData(UniversalId id, const CSMDoc::Document& document);
TableMimeData(std::vector<UniversalId>& id, const CSMDoc::Document& document); TableMimeData(const std::vector<UniversalId>& id, const CSMDoc::Document& document);
~TableMimeData(); ~TableMimeData();
@ -56,6 +56,7 @@ namespace CSMWorld
UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const; UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const;
static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type); static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type);
static CSMWorld::ColumnBase::Display convertEnums(CSMWorld::UniversalId::Type type); static CSMWorld::ColumnBase::Display convertEnums(CSMWorld::UniversalId::Type type);
private: private:

@ -18,7 +18,7 @@ namespace
static const TypeData sNoArg[] = 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_Globals, "Global Variables", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", 0 },
@ -64,6 +64,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell, "Cell", ":./cell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Cell_Missing, "Cell", ":./cell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Referenceable, "Referenceables", 0 },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Activator, "Activator", ":./activator.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Potion, "Potion", ":./potion.png" },
@ -100,6 +101,7 @@ namespace
static const TypeData sIndexArg[] = static const TypeData sIndexArg[] =
{ {
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 }, { 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 { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };
} }

@ -60,6 +60,7 @@ namespace CSMWorld
Type_Spell, Type_Spell,
Type_Cells, Type_Cells,
Type_Cell, Type_Cell,
Type_Cell_Missing, //For cells that does not exist yet.
Type_Referenceables, Type_Referenceables,
Type_Referenceable, Type_Referenceable,
Type_Activator, Type_Activator,
@ -96,10 +97,11 @@ namespace CSMWorld
Type_JournalInfos, Type_JournalInfos,
Type_JournalInfo, Type_JournalInfo,
Type_Scene, Type_Scene,
Type_Preview Type_Preview,
Type_LoadErrorLog
}; };
enum { NumberOfTypes = Type_Scene+1 }; enum { NumberOfTypes = Type_LoadErrorLog+1 };
private: private:

@ -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);
}

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

@ -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);
}

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

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

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

@ -84,6 +84,33 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i) for (std::size_t i=0; i<sizeof (sMapping)/sizeof (Mapping); ++i)
mDelegateFactories->add (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory ( mDelegateFactories->add (sMapping[i].mDisplay, new CSVWorld::EnumDelegateFactory (
CSMWorld::Columns::getEnums (sMapping[i].mColumnId), sMapping[i].mAllowNone)); 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() CSVDoc::ViewManager::~ViewManager()

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

@ -3,8 +3,12 @@
#include <sstream> #include <sstream>
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget *parent) #include <QtGui/qevent.h>
: WorldspaceWidget (parent)
#include <apps/opencs/model/world/tablemimedata.hpp>
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
: WorldspaceWidget (document, parent)
{} {}
void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint) void CSVRender::PagedWorldspaceWidget::useViewHint (const std::string& hint)
@ -44,4 +48,45 @@ void CSVRender::PagedWorldspaceWidget::setCellSelection (const CSMWorld::CellSel
{ {
mSelection = selection; mSelection = selection;
emit cellSelectionChanged (mSelection); emit cellSelectionChanged (mSelection);
}
std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (const std::string& record) const
{
std::istringstream stream (record.c_str());
char ignore;
int x, y;
stream >> ignore >> x >> y;
return std::make_pair(x, y);
}
void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data)
{
bool selectionChanged = false;
for (unsigned i = 0; i < data.size(); ++i)
{
std::pair<int, int> coordinates(getCoordinatesFromId(data[i].getId()));
if (mSelection.add(CSMWorld::CellCoordinates(coordinates.first, coordinates.second)))
{
selectionChanged = true;
}
}
if (selectionChanged)
{
emit cellSelectionChanged(mSelection);
}
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const
{
switch (type)
{
case cellsExterior:
return canHandle;
case cellsInterior:
return needUnpaged;
default:
return ignored;
}
} }

@ -13,17 +13,25 @@ namespace CSVRender
CSMWorld::CellSelection mSelection; CSMWorld::CellSelection mSelection;
private:
std::pair<int, int> getCoordinatesFromId(const std::string& record) const;
public: public:
PagedWorldspaceWidget (QWidget *parent); PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
///< \note Sets the cell area selection to an invalid value to indicate that currently ///< \note Sets the cell area selection to an invalid value to indicate that currently
/// no cells are displayed. The cells to be displayed will be specified later through /// no cells are displayed. The cells to be displayed will be specified later through
/// hint system. /// hint system.
virtual void useViewHint (const std::string& hint); void useViewHint (const std::string& hint);
void setCellSelection (const CSMWorld::CellSelection& selection); void setCellSelection (const CSMWorld::CellSelection& selection);
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
virtual dropRequirments getDropRequirements(dropType type) const;
signals: signals:
void cellSelectionChanged (const CSMWorld::CellSelection& selection); void cellSelectionChanged (const CSMWorld::CellSelection& selection);

@ -320,7 +320,7 @@ namespace CSVRender
} }
if (mUpdate) if (mUpdate && mWindow)
{ {
mUpdate = false; mUpdate = false;
mWindow->update(); mWindow->update();

@ -36,7 +36,7 @@ namespace CSVRender
SceneWidget(QWidget *parent); SceneWidget(QWidget *parent);
virtual ~SceneWidget(); virtual ~SceneWidget();
QPaintEngine* paintEngine() const; QPaintEngine* paintEngine() const;
CSVWorld::SceneToolMode *makeLightingSelector (CSVWorld::SceneToolbar *parent); CSVWorld::SceneToolMode *makeLightingSelector (CSVWorld::SceneToolbar *parent);
///< \attention The created tool is not added to the toolbar (via addTool). Doing that ///< \attention The created tool is not added to the toolbar (via addTool). Doing that

@ -3,10 +3,13 @@
#include <OgreColourValue.h> #include <OgreColourValue.h>
#include <QtGui/qevent.h>
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/idtable.hpp" #include "../../model/world/idtable.hpp"
#include "../../model/world/tablemimedata.hpp"
void CSVRender::UnpagedWorldspaceWidget::update() void CSVRender::UnpagedWorldspaceWidget::update()
{ {
@ -20,9 +23,8 @@ void CSVRender::UnpagedWorldspaceWidget::update()
/// \todo deal with mSunlight and mFog/mForDensity /// \todo deal with mSunlight and mFog/mForDensity
} }
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent)
CSMDoc::Document& document, QWidget *parent) : WorldspaceWidget (document, parent), mCellId (cellId)
: WorldspaceWidget (parent), mCellId (cellId)
{ {
mCellsModel = &dynamic_cast<CSMWorld::IdTable&> ( mCellsModel = &dynamic_cast<CSMWorld::IdTable&> (
*document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells)); *document.getData().getTableModel (CSMWorld::UniversalId::Type_Cells));
@ -63,4 +65,26 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI
if (cellIndex.row()>=start && cellIndex.row()<=end) if (cellIndex.row()>=start && cellIndex.row()<=end)
emit closeRequest(); emit closeRequest();
} }
void CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data)
{
mCellId = data.begin()->getId();
update();
emit cellChanged(*data.begin());
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const
{
switch(type)
{
case cellsInterior:
return canHandle;
case cellsExterior:
return needPaged;
default:
return ignored;
}
}

@ -31,13 +31,21 @@ namespace CSVRender
public: public:
UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document,
QWidget *parent); QWidget *parent);
virtual dropRequirments getDropRequirements(dropType type) const;
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
private slots: private slots:
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight); void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end); void cellRowsAboutToBeRemoved (const QModelIndex& parent, int start, int end);
signals:
void cellChanged(const CSMWorld::UniversalId& id);
}; };
} }

@ -5,15 +5,20 @@
#include <OgreSceneManager.h> #include <OgreSceneManager.h>
#include <OgreEntity.h> #include <OgreEntity.h>
#include <QtGui/qevent.h>
#include "../world/scenetoolmode.hpp" #include "../world/scenetoolmode.hpp"
#include <apps/opencs/model/world/universalid.hpp>
CSVRender::WorldspaceWidget::WorldspaceWidget (QWidget *parent) CSVRender::WorldspaceWidget::WorldspaceWidget (const CSMDoc::Document& document, QWidget* parent)
: SceneWidget (parent) : SceneWidget (parent), mDocument(document)
{ {
Ogre::Entity* ent = getSceneManager()->createEntity("cube", Ogre::SceneManager::PT_CUBE); Ogre::Entity* ent = getSceneManager()->createEntity("cube", Ogre::SceneManager::PT_CUBE);
ent->setMaterialName("BaseWhite"); ent->setMaterialName("BaseWhite");
getSceneManager()->getRootSceneNode()->attachObject(ent); getSceneManager()->getRootSceneNode()->attachObject(ent);
setAcceptDrops(true);
} }
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode) void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
@ -46,4 +51,78 @@ CSVWorld::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
this, SLOT (selectNavigationMode (const std::string&))); this, SLOT (selectNavigationMode (const std::string&)));
return tool; return tool;
}
CSVRender::WorldspaceWidget::dropType CSVRender::WorldspaceWidget::getDropType (
const std::vector< CSMWorld::UniversalId >& data)
{
dropType output = notCells;
bool firstIteration = true;
for (unsigned i = 0; i < data.size(); ++i)
{
if (data[i].getType() == CSMWorld::UniversalId::Type_Cell ||
data[i].getType() == CSMWorld::UniversalId::Type_Cell_Missing)
{
if (*(data[i].getId().begin()) == '#') //exterior
{
if (firstIteration)
{
output = cellsExterior;
firstIteration = false;
continue;
}
if (output == cellsInterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
} else //interior
{
if (firstIteration)
{
output = cellsInterior;
firstIteration = false;
continue;
}
if (output == cellsExterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
}
} else {
output = notCells;
break;
}
}
return output;
}
void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event)
{
event->accept();
}
void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
if (mime->fromDocument (mDocument))
{
emit dataDropped(mime->getData());
} //not handling drops from different documents at the moment
} }

@ -6,7 +6,13 @@
#include "navigation1st.hpp" #include "navigation1st.hpp"
#include "navigationfree.hpp" #include "navigationfree.hpp"
#include "navigationorbit.hpp" #include "navigationorbit.hpp"
#include <apps/opencs/model/doc/document.hpp>
#include <apps/opencs/model/world/tablemimedata.hpp>
namespace CSMWorld
{
class UniversalId;
}
namespace CSVWorld namespace CSVWorld
{ {
class SceneToolMode; class SceneToolMode;
@ -25,7 +31,23 @@ namespace CSVRender
public: public:
WorldspaceWidget (QWidget *parent = 0); enum dropType
{
cellsMixed,
cellsInterior,
cellsExterior,
notCells
};
enum dropRequirments
{
canHandle,
needPaged,
needUnpaged,
ignored //either mixed cells, or not cells
};
WorldspaceWidget (const CSMDoc::Document& document, QWidget *parent = 0);
CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent); CSVWorld::SceneToolMode *makeNavigationSelector (CSVWorld::SceneToolbar *parent);
///< \attention The created tool is not added to the toolbar (via addTool). Doing that ///< \attention The created tool is not added to the toolbar (via addTool). Doing that
@ -33,9 +55,26 @@ namespace CSVRender
void selectDefaultNavigationMode(); void selectDefaultNavigationMode();
static dropType getDropType(const std::vector<CSMWorld::UniversalId>& data);
virtual dropRequirments getDropRequirements(dropType type) const = 0;
virtual void useViewHint (const std::string& hint); virtual void useViewHint (const std::string& hint);
///< Default-implementation: ignored. ///< Default-implementation: ignored.
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data) = 0;
protected:
const CSMDoc::Document& mDocument; //for checking if drop comes from same document
private:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent* event);
void dragMoveEvent(QDragMoveEvent *event);
private slots: private slots:
void selectNavigationMode (const std::string& mode); void selectNavigationMode (const std::string& mode);
@ -43,6 +82,7 @@ namespace CSVRender
signals: signals:
void closeRequest(); void closeRequest();
void dataDropped(const std::vector<CSMWorld::UniversalId>& data);
}; };
} }

@ -18,10 +18,19 @@ CSVSettings::BooleanView::BooleanView (CSMSettings::Setting *setting,
{ {
QAbstractButton *button = 0; QAbstractButton *button = 0;
if (isMultiValue()) switch (setting->type())
{
case CSMSettings::Type_CheckBox:
button = new QCheckBox (value, this); button = new QCheckBox (value, this);
else break;
case CSMSettings::Type_RadioButton:
button = new QRadioButton (value, this); button = new QRadioButton (value, this);
break;
default:
break;
}
connect (button, SIGNAL (clicked (bool)), connect (button, SIGNAL (clicked (bool)),
this, SLOT (slotToggled (bool))); this, SLOT (slotToggled (bool)));

@ -76,22 +76,9 @@ void CSVSettings::Dialog::buildPages()
mStackedWidget->addWidget (&dynamic_cast<QWidget &>(*(page))); mStackedWidget->addWidget (&dynamic_cast<QWidget &>(*(page)));
} }
addDebugPage();
resize (mStackedWidget->sizeHint()); 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) void CSVSettings::Dialog::buildPageListWidget (QWidget *centralWidget)
{ {
mPageListWidget = new QListWidget (centralWidget); mPageListWidget = new QListWidget (centralWidget);
@ -122,11 +109,13 @@ void CSVSettings::Dialog::closeEvent (QCloseEvent *event)
void CSVSettings::Dialog::show() void CSVSettings::Dialog::show()
{ {
if (pages().isEmpty()) if (pages().isEmpty())
{
buildPages(); buildPages();
setViewValues();
}
QPoint screenCenter = QApplication::desktop()->screenGeometry().center(); QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move (screenCenter - geometry().center()); move (screenCenter - geometry().center());
QWidget::show(); QWidget::show();
} }

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

@ -60,8 +60,10 @@ void CSVSettings::Frame::showWidgets()
QWidget *widg = static_cast <QWidget *> (obj); QWidget *widg = static_cast <QWidget *> (obj);
if (widg->property("sizePolicy").isValid()) if (widg->property("sizePolicy").isValid())
{
widg->setSizePolicy widg->setSizePolicy
(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
}
} }
layout()->activate(); layout()->activate();
setFixedSize(minimumSizeHint()); setFixedSize(minimumSizeHint());

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

@ -7,6 +7,8 @@
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
#include "../../model/settings/connector.hpp" #include "../../model/settings/connector.hpp"
#include "../../model/settings/support.hpp"
#include "settingwindow.hpp" #include "settingwindow.hpp"
QMap <CSVSettings::ViewType, CSVSettings::IViewFactory *> QMap <CSVSettings::ViewType, CSVSettings::IViewFactory *>

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

@ -1,88 +1,195 @@
#include <QHBoxLayout> #include <QSpinBox>
#include <QVBoxLayout> #include <QDoubleSpinBox>
#include <QAbstractSpinBox>
#include <QCheckBox> #include <QAbstractSlider>
#include <QRadioButton> #include <QDial>
#include <QGroupBox> #include <QSlider>
#include <QAbstractButton>
#include "rangeview.hpp" #include "rangeview.hpp"
#include "spinbox.hpp"
#include "../../model/settings/setting.hpp" #include "../../model/settings/setting.hpp"
#include "../../model/settings/support.hpp"
#include <QDebug>
CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting, CSVSettings::RangeView::RangeView (CSMSettings::Setting *setting,
Page *parent) Page *parent)
: View (setting, parent) : mRangeWidget (0), mRangeType (setting->type()), View (setting, parent)
{ {
foreach (const QString &value, setting->declaredValues())
mRangeWidget = 0;
if (isMultiValue())
return;
switch (mRangeType)
{ {
QAbstractButton *button = 0; case CSMSettings::Type_SpinBox:
case CSMSettings::Type_DoubleSpinBox:
buildSpinBox (setting);
break;
case CSMSettings::Type_Dial:
case CSMSettings::Type_Slider:
buildSlider (setting);
break;
default:
break;
}
if (isMultiValue()) mRangeWidget->setFixedWidth (widgetWidth (setting->widgetWidth()));
button = new QCheckBox (value, this); mRangeWidget->setObjectName (setting->name());
else
button = new QRadioButton (value, this);
connect (button, SIGNAL (clicked (bool)), addWidget (mRangeWidget);
this, SLOT (slotToggled (bool))); }
button->setObjectName (value); void CSVSettings::RangeView::buildSlider (CSMSettings::Setting *setting)
{
switch (setting->type())
{
case CSMSettings::Type_Slider:
mRangeWidget = new QSlider (Qt::Horizontal, this);
mRangeWidget->setProperty ("tickInterval", setting->tickInterval());
if (setting->ticksAbove())
{
if (setting->ticksBelow())
mRangeWidget->setProperty ("tickPosition", QSlider::TicksBothSides);
else
mRangeWidget->setProperty ("tickPosition", QSlider::TicksAbove);
}
else if (setting->ticksBelow())
mRangeWidget->setProperty ("tickPosition", QSlider::TicksBelow);
else
mRangeWidget->setProperty ("tickPosition", QSlider::NoTicks);
break;
addWidget (button); case CSMSettings::Type_Dial:
mRangeWidget = new QDial (this);
mRangeWidget->setProperty ("wrapping", setting->wrapping());
mRangeWidget->setProperty ("notchesVisible",
(setting->ticksAbove() || setting->ticksBelow()));
break;
mButtons[value] = button; default:
break;
} }
mRangeWidget->setProperty ("minimum", setting->minimum());
mRangeWidget->setProperty ("maximum", setting->maximum());
mRangeWidget->setProperty ("tracking", false);
mRangeWidget->setProperty ("singleStep", setting->singleStep());
connect (mRangeWidget, SIGNAL (valueChanged (int)),
this, SLOT (slotUpdateView (int)));
} }
void CSVSettings::RangeView::slotToggled (bool state) void CSVSettings::RangeView::buildSpinBox (CSMSettings::Setting *setting)
{ {
//test only for true to avoid multiple selection updates with radiobuttons SpinBox *sb = 0;
if (!isMultiValue() && !state)
return; switch (setting->type())
{
case CSMSettings::Type_SpinBox:
sb = new SpinBox (this);
if (!setting->declaredValues().isEmpty())
sb->setValueList (setting->declaredValues());
mRangeWidget = sb;
QStringList values; connect (mRangeWidget, SIGNAL (valueChanged (int)),
this, SLOT (slotUpdateView (int)));
break;
foreach (QString key, mButtons.keys()) case CSMSettings::Type_DoubleSpinBox:
mRangeWidget = new QDoubleSpinBox (this);
connect (mRangeWidget, SIGNAL (valueChanged (double)),
this, SLOT (slotUpdateView (double)));
break;
default:
break;
}
//min / max values are set automatically in AlphaSpinBox
if (setting->declaredValues().isEmpty())
{
mRangeWidget->setProperty ("minimum", setting->minimum());
mRangeWidget->setProperty ("maximum", setting->maximum());
mRangeWidget->setProperty ("singleStep", setting->singleStep());
mRangeWidget->setProperty ("specialValueText",
setting->specialValueText());
}
mRangeWidget->setProperty ("prefix", setting->prefix());
mRangeWidget->setProperty ("suffix", setting->suffix());
mRangeWidget->setProperty ("wrapping", setting->wrapping());
}
void CSVSettings::RangeView::slotUpdateView (int value)
{
QString textValue = "";
QStringList list;
switch (mRangeType)
{ {
if (mButtons.value(key)->isChecked()) case CSMSettings::Type_SpinBox:
values.append (key); list = static_cast <SpinBox *> (mRangeWidget)->valueList();
if (!list.isEmpty())
textValue = list.at(value);
break;
default:
break;
} }
setSelectedValues (values, false);
if (textValue.isEmpty())
textValue = QVariant (value).toString();
setSelectedValue (textValue, false);
View::updateView(); View::updateView();
} }
void CSVSettings::RangeView::updateView (bool signalUpdate) const void CSVSettings::RangeView::slotUpdateView (double value)
{ {
setSelectedValue (QVariant(value).toString(), false);
QStringList values = selectedValues(); View::updateView();
}
foreach (const QString &buttonName, mButtons.keys()) void CSVSettings::RangeView::updateView (bool signalUpdate) const
{ {
QAbstractButton *button = mButtons[buttonName]; QString value;
//if the value is not found in the list, the widget is checked false if (!selectedValues().isEmpty())
bool buttonValue = values.contains(buttonName); value = selectedValues().at(0);
//skip if the butotn value will not change switch (mRangeType)
if (button->isChecked() == buttonValue) {
continue; case CSMSettings::Type_SpinBox:
static_cast <SpinBox *> (mRangeWidget)->setValue (value);
break;
//disable autoexclusive if it's enabled and we're setting case CSMSettings::Type_DoubleSpinBox:
//the button value to false static_cast <QDoubleSpinBox *> (mRangeWidget)->setValue (value.toDouble());
bool switchExclusive = (!buttonValue && button->autoExclusive()); break;
if (switchExclusive) case CSMSettings::Type_Slider:
button->setAutoExclusive (false); case CSMSettings::Type_Dial:
mRangeWidget->setProperty ("value", value.toInt());
mRangeWidget->setProperty ("sliderPosition", value.toInt());
break;
button->setChecked (buttonValue); default:
break;
if (switchExclusive)
button->setAutoExclusive(true);
} }
View::updateView (signalUpdate); View::updateView (signalUpdate);
} }

@ -1,13 +1,11 @@
#ifndef CSVSETTINGS_RANGEVIEW_HPP #ifndef CSVSETTINGS_RANGEVIEW_HPP
#define CSVSETTINGS_RANGEVIEW_HPP #define CSVSETTINGS_RANGEVIEW_HPP
#include <QWidget>
#include <QAbstractButton>
#include "view.hpp" #include "view.hpp"
#include "../../model/settings/support.hpp" #include "../../model/settings/support.hpp"
class QStringListModel; class QStringListModel;
class QAbstractSpinBox;
namespace CSVSettings namespace CSVSettings
{ {
@ -15,17 +13,30 @@ namespace CSVSettings
{ {
Q_OBJECT Q_OBJECT
QMap <QString, QAbstractButton *> mButtons; QWidget *mRangeWidget;
CSMSettings::SettingType mRangeType;
public: public:
explicit RangeView (CSMSettings::Setting *setting, explicit RangeView (CSMSettings::Setting *setting,
Page *parent); Page *parent);
protected: protected:
///virtual function called through View
void updateView (bool signalUpdate = true) const; 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: private slots:
void slotToggled (bool state);
///responds to valueChanged signals
void slotUpdateView (int value);
void slotUpdateView (double value);
}; };
class RangeViewFactory : public QObject, public IViewFactory class RangeViewFactory : public QObject, public IViewFactory

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

@ -57,7 +57,7 @@ void CSVSettings::SettingWindow::createConnections
foreach (const QString &key, proxyMap.keys()) foreach (const QString &key, proxyMap.keys())
{ {
QStringList keyPair = key.split('.'); QStringList keyPair = key.split('/');
if (keyPair.size() != 2) if (keyPair.size() != 2)
continue; 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 CSVSettings::View *CSVSettings::SettingWindow::findView
(const QString &pageName, const QString &setting) (const QString &pageName, const QString &setting)
{ {
@ -95,17 +114,19 @@ CSVSettings::View *CSVSettings::SettingWindow::findView
void CSVSettings::SettingWindow::saveSettings() 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 Page *page, mPages)
{ {
foreach (const View *view, page->views()) foreach (const View *view, page->views())
{ {
if (view->serializable()) if (!view->serializable())
settingMap[view->viewKey()] = view->selectedValues(); continue;
mModel->setDefinitions (view->viewKey(), view->selectedValues());
} }
} }
CSMSettings::UserSettings::instance().saveSettings (settingMap);
mModel->saveDefinitions();
} }
void CSVSettings::SettingWindow::closeEvent (QCloseEvent *event) void CSVSettings::SettingWindow::closeEvent (QCloseEvent *event)

@ -8,7 +8,7 @@
namespace CSMSettings { namespace CSMSettings {
class Setting; class Setting;
class SettingManager; class UserSettings;
} }
namespace CSVSettings { namespace CSVSettings {
@ -23,25 +23,36 @@ namespace CSVSettings {
Q_OBJECT Q_OBJECT
PageList mPages; PageList mPages;
CSMSettings::SettingManager *mModel; CSMSettings::UserSettings *mModel;
public: public:
explicit SettingWindow(QWidget *parent = 0); 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); 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: protected:
virtual void closeEvent (QCloseEvent *event); virtual void closeEvent (QCloseEvent *event);
///construct the pages to be displayed in the dialog
void createPages(); void createPages();
///return the list of constructed pages
const PageList &pages() const { return mPages; } const PageList &pages() const { return mPages; }
///save settings from the GUI to file
void saveSettings(); void saveSettings();
///sets the defined values for the views that have been created
void setViewValues();
private: private:
///create connections between settings (used for proxy settings)
void createConnections (const QList <CSMSettings::Setting *> &list); void createConnections (const QList <CSMSettings::Setting *> &list);
}; };
} }

@ -0,0 +1,50 @@
#include "spinbox.hpp"
#include <QLineEdit>
CSVSettings::SpinBox::SpinBox(QWidget *parent)
: mValueList(QStringList()), QSpinBox(parent)
{
setRange (0, 0);
}
QString CSVSettings::SpinBox::textFromValue(int val) const
{
if (mValueList.isEmpty())
return QVariant (val).toString();
QString value;
if (val < mValueList.size())
value = mValueList.at (val);
return value;
}
int CSVSettings::SpinBox::valueFromText(const QString &text) const
{
if (mValueList.isEmpty())
return -1;
if (mValueList.contains (text))
return mValueList.indexOf(text);
return -1;
}
void CSVSettings::SpinBox::setValue (const QString &value)
{
if (!mValueList.isEmpty())
{
lineEdit()->setText (value);
QSpinBox::setValue(valueFromText(value));
}
else
QSpinBox::setValue (value.toInt());
}
void CSVSettings::SpinBox::setValueList (const QStringList &list)
{
mValueList = list;
setMaximum (list.size() - 1);
}

@ -0,0 +1,38 @@
#ifndef CSVSETTINGS_SPINBOX_HPP
#define CSVSETTINGS_SPINBOX_HPP
#include <QObject>
#include <QStringList>
#include <QSpinBox>
namespace CSVSettings
{
class SpinBox : public QSpinBox
{
Q_OBJECT
QStringList mValueList;
public:
explicit SpinBox(QWidget *parent = 0);
///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;
};
}
#endif // CSVSETTINGS_SPINBOX_HPP

@ -28,11 +28,6 @@ bool CSVSettings::TextView::isEquivalent
return (lhs.trimmed() == rhs.trimmed()); return (lhs.trimmed() == rhs.trimmed());
} }
void CSVSettings::TextView::setWidgetText (const QString &value) const
{
mTextWidget->setProperty ("text", value);
}
void CSVSettings::TextView::slotTextEdited (QString value) void CSVSettings::TextView::slotTextEdited (QString value)
{ {
QStringList values = value.split (mDelimiter, QString::SkipEmptyParts); QStringList values = value.split (mDelimiter, QString::SkipEmptyParts);
@ -51,19 +46,14 @@ void CSVSettings::TextView::updateView(bool signalUpdate) const
{ {
QString values = selectedValues().join (mDelimiter); QString values = selectedValues().join (mDelimiter);
if (isEquivalent (widgetText(), values)) if (isEquivalent (mTextWidget->property("text").toString(), values))
return; return;
setWidgetText (values); mTextWidget->setProperty("text", values);
View::updateView (signalUpdate); View::updateView (signalUpdate);
} }
QString CSVSettings::TextView::widgetText() const
{
return mTextWidget->property("text").toString();
}
CSVSettings::TextView *CSVSettings::TextViewFactory::createView CSVSettings::TextView *CSVSettings::TextViewFactory::createView
(CSMSettings::Setting *setting, (CSMSettings::Setting *setting,
Page *parent) Page *parent)

@ -20,6 +20,7 @@ namespace CSVSettings
protected: protected:
/// virtual function called through View
void updateView (bool signalUpdate = true) const; void updateView (bool signalUpdate = true) const;
protected slots: protected slots:
@ -32,12 +33,6 @@ namespace CSVSettings
///Comparison function that returns true if the trimmed() strings ///Comparison function that returns true if the trimmed() strings
///are equal ///are equal
bool isEquivalent (const QString &lhs, const QString &rhs) const; bool isEquivalent (const QString &lhs, const QString &rhs) const;
///Convenience function to return the text of the widget
QString widgetText() const;
///Convenience function to set the text of the widget
void setWidgetText (const QString &value) const;
}; };
class TextViewFactory : public QObject, public IViewFactory class TextViewFactory : public QObject, public IViewFactory

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

@ -11,8 +11,6 @@ class QGroupBox;
class QStringList; class QStringList;
class QStandardItem; class QStandardItem;
class QItemSelection; class QItemSelection;
class QStringListModel;
class QStandardItemModel;
class QAbstractItemModel; class QAbstractItemModel;
class QItemSelectionModel; class QItemSelectionModel;
@ -42,17 +40,16 @@ namespace CSVSettings
///State indicating whether the view will allow multiple values ///State indicating whether the view will allow multiple values
bool mIsMultiValue; bool mIsMultiValue;
///'pagename.settingname' form of the view's id
QString mViewKey; QString mViewKey;
///indicates whether or not the setting is written to file
bool mSerializable; bool mSerializable;
public: public:
explicit View (CSMSettings::Setting *setting, Page *parent); 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. ///Returns the index / row of the passed value, -1 if not found.
int currentIndex () const; int currentIndex () const;
@ -74,7 +71,7 @@ namespace CSVSettings
///or signaling the view was updatedto avoid viscious cylcing. ///or signaling the view was updatedto avoid viscious cylcing.
void setSelectedValues (const QStringList &values, void setSelectedValues (const QStringList &values,
bool updateView = true, bool updateView = true,
bool signalUpdate = true); bool signalUpdate = true) const;
void setSelectedValue (const QString &value, void setSelectedValue (const QString &value,
bool updateView = true, bool updateView = true,
@ -101,7 +98,7 @@ namespace CSVSettings
void showEvent ( QShowEvent * event ); void showEvent ( QShowEvent * event );
///Virtual for updating a specific View subclass ///Virtual for updating a specific View subclass
///bool indicates whether a signal is emitted that the view was updated ///bool indicates whether viewUpdated() signal is emitted
virtual void updateView (bool signalUpdate = true) const; virtual void updateView (bool signalUpdate = true) const;
///Returns the pixel width corresponding to the specified number of ///Returns the pixel width corresponding to the specified number of

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

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

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

@ -0,0 +1,38 @@
#include <QDrag>
#include "../../model/world/tablemimedata.hpp"
#include "dragrecordtable.hpp"
void CSVWorld::DragRecordTable::startDrag (const CSVWorld::DragRecordTable& table)
{
CSMWorld::TableMimeData* mime = new CSMWorld::TableMimeData (table.getDraggedRecords(), mDocument);
if (mime)
{
QDrag* drag = new QDrag (this);
drag->setMimeData (mime);
drag->setPixmap (QString::fromUtf8 (mime->getIcon().c_str()));
drag->exec (Qt::CopyAction);
}
}
CSVWorld::DragRecordTable::DragRecordTable (CSMDoc::Document& document, QWidget* parent) :
mDocument(document),
QTableView(parent),
mEditLock(false)
{}
void CSVWorld::DragRecordTable::setEditLock (bool locked)
{
mEditLock = locked;
}
void CSVWorld::DragRecordTable::dragEnterEvent(QDragEnterEvent *event)
{
event->acceptProposedAction();
}
void CSVWorld::DragRecordTable::dragMoveEvent(QDragMoveEvent *event)
{
event->accept();
}

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

Loading…
Cancel
Save