Merge branch 'master' into bug1196jumpdialog

Conflicts:
	apps/openmw/mwinput/inputmanagerimp.cpp
deque
Fil Krynicki 11 years ago
commit bbb7ceab43

@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
message(STATUS "Configuring OpenMW...") message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 29) set(OPENMW_VERSION_MINOR 30)
set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_COMMITHASH "")
@ -36,18 +36,8 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}") string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}")
string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}") string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}")
set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}") set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
message(FATAL_ERROR "Silly Zini forgot to update the version again...")
else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR})
set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR})
set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE})
set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}")
set(OPENMW_VERSION_TAGHASH "${TAGHASH}")
endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION})
message(STATUS "OpenMW version ${OPENMW_VERSION}") message(STATUS "OpenMW version ${OPENMW_VERSION}")
else(MATCH) else(MATCH)
@ -86,8 +76,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)
@ -131,6 +119,7 @@ set(OENGINE_OGRE
) )
set(OENGINE_GUI set(OENGINE_GUI
${LIBDIR}/openengine/gui/loglistener.cpp
${LIBDIR}/openengine/gui/manager.cpp ${LIBDIR}/openengine/gui/manager.cpp
${LIBDIR}/openengine/gui/layout.hpp ${LIBDIR}/openengine/gui/layout.hpp
) )
@ -171,27 +160,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")
@ -257,6 +225,9 @@ endif ()
set(BOOST_COMPONENTS system filesystem program_options) set(BOOST_COMPONENTS system filesystem program_options)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
IF(BOOST_STATIC) IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
@ -368,8 +339,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)
@ -434,7 +405,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install licenses # Install licenses
INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" ) INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "OFL.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" ) INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
ENDIF (DPKG_PROGRAM) ENDIF (DPKG_PROGRAM)
@ -451,7 +421,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
@ -480,7 +450,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 ".")
@ -618,6 +588,7 @@ if (WIN32)
4706 # Assignment in conditional expression 4706 # Assignment in conditional expression
4738 # Storing 32-bit float result in memory, possible loss of performance 4738 # Storing 32-bit float result in memory, possible loss of performance
4986 # Undocumented warning that occurs in the crtdbg.h file 4986 # Undocumented warning that occurs in the crtdbg.h file
4987 # nonstandard extension used (triggered by setjmp.h)
4996 # Function was declared deprecated 4996 # Function was declared deprecated
# cause by ogre extensivly # cause by ogre extensivly
@ -634,7 +605,9 @@ if (WIN32)
4305 # Truncating value (double to float, for example) 4305 # Truncating value (double to float, for example)
4309 # Variable overflow, trying to store 128 in a signed char for example 4309 # Variable overflow, trying to store 128 in a signed char for example
4355 # Using 'this' in member initialization list 4355 # Using 'this' in member initialization list
4505 # Unreferenced local function has been removed
4701 # Potentially uninitialized local variable used 4701 # Potentially uninitialized local variable used
4702 # Unreachable code
4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt 4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt
) )
@ -642,19 +615,31 @@ if (WIN32)
set(WARNINGS "${WARNINGS} /wd${d}") set(WARNINGS "${WARNINGS} /wd${d}")
endforeach(d) endforeach(d)
set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${WARNINGS}) # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS}) set(SHINY_WARNINGS "${WARNINGS} /wd4245")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${SHINY_WARNINGS})
# there's an unreferenced local variable in the ogre platform, suppress it
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${SHINY_OGRE_WARNINGS})
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(oics PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_LAUNCHER) if (BUILD_LAUNCHER)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_LAUNCHER) endif (BUILD_LAUNCHER)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
if (BUILD_BSATOOL) if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_BSATOOL) endif (BUILD_BSATOOL)
if (BUILD_ESMTOOL) if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_ESMTOOL) endif (BUILD_ESMTOOL)
if (BUILD_OPENCS)
set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_OPENCS)
if (BUILD_MWINIIMPORTER)
set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_MWINIIMPORTER)
endif(MSVC) endif(MSVC)
# Same for MinGW # Same for MinGW
@ -687,7 +672,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})

@ -333,7 +333,7 @@ int load(Arguments& info)
// Is the user interested in this record type? // Is the user interested in this record type?
bool interested = true; bool interested = true;
if (info.types.size() > 0) if (!info.types.empty())
{ {
std::vector<std::string>::iterator match; std::vector<std::string>::iterator match;
match = std::find(info.types.begin(), info.types.end(), match = std::find(info.types.begin(), info.types.end(),

@ -387,7 +387,7 @@ std::string magicEffectLabel(int idx)
"sEffectSummonCreature04", "sEffectSummonCreature04",
"sEffectSummonCreature05" "sEffectSummonCreature05"
}; };
if (idx >= 0 && idx <= 143) if (idx >= 0 && idx <= 142)
return magicEffectLabels[idx]; return magicEffectLabels[idx];
else else
return "Invalid"; return "Invalid";
@ -471,7 +471,7 @@ std::string skillLabel(int idx)
"Speechcraft", "Speechcraft",
"Hand-to-hand" "Hand-to-hand"
}; };
if (idx >= 0 && idx <= 27) if (idx >= 0 && idx <= 26)
return skillLabels[idx]; return skillLabels[idx];
else else
return "Invalid"; return "Invalid";
@ -498,7 +498,7 @@ std::string rangeTypeLabel(int idx)
"Touch", "Touch",
"Target" "Target"
}; };
if (idx >= 0 && idx <= 3) if (idx >= 0 && idx <= 2)
return rangeTypeLabels[idx]; return rangeTypeLabels[idx];
else else
return "Invalid"; return "Invalid";

@ -124,7 +124,7 @@ void printEffectList(ESM::EffectList effects)
{ {
int i = 0; int i = 0;
std::vector<ESM::ENAMstruct>::iterator eit; std::vector<ESM::ENAMstruct>::iterator eit;
for (eit = effects.mList.begin(); eit != effects.mList.end(); eit++) for (eit = effects.mList.begin(); eit != effects.mList.end(); ++eit)
{ {
std::cout << " Effect[" << i << "]: " << magicEffectLabel(eit->mEffectID) std::cout << " Effect[" << i << "]: " << magicEffectLabel(eit->mEffectID)
<< " (" << eit->mEffectID << ")" << std::endl; << " (" << eit->mEffectID << ")" << std::endl;
@ -651,7 +651,7 @@ void Record<ESM::Dialogue>::print()
// Sadly, there are no DialInfos, because the loader dumps as it // Sadly, there are no DialInfos, because the loader dumps as it
// loads, rather than loading and then dumping. :-( Anyone mind if // loads, rather than loading and then dumping. :-( Anyone mind if
// I change this? // I change this?
std::vector<ESM::DialInfo>::iterator iit; ESM::Dialogue::InfoContainer::iterator iit;
for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); iit++) for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); iit++)
std::cout << "INFO!" << iit->mId << std::endl; std::cout << "INFO!" << iit->mId << std::endl;
} }
@ -707,9 +707,9 @@ void Record<ESM::Faction>::print()
std::cout << " Faction Reaction: " std::cout << " Faction Reaction: "
<< mData.mData.mRankData[i].mFactReaction << std::endl; << mData.mData.mRankData[i].mFactReaction << std::endl;
} }
std::vector<ESM::Faction::Reaction>::iterator rit; std::map<std::string, int>::iterator rit;
for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); rit++) for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); rit++)
std::cout << " Reaction: " << rit->mReaction << " = " << rit->mFaction << std::endl; std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl;
} }
template<> template<>

@ -214,13 +214,13 @@ QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre
uint row = 0; uint row = 0;
Ogre::ConfigOptionMap options = renderer->getConfigOptions(); Ogre::ConfigOptionMap options = renderer->getConfigOptions();
for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); i++, row++) for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); ++i, ++row)
{ {
Ogre::StringVector::iterator opt_it; Ogre::StringVector::iterator opt_it;
uint idx = 0; uint idx = 0;
for (opt_it = i->second.possibleValues.begin(); for (opt_it = i->second.possibleValues.begin();
opt_it != i->second.possibleValues.end(); opt_it++, idx++) opt_it != i->second.possibleValues.end(); ++opt_it, ++idx)
{ {
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) { if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) {
result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified();

@ -41,11 +41,11 @@ Launcher::MainDialog::MainDialog(QWidget *parent)
// Check if the font is installed // Check if the font is installed
if (!fonts.contains("EB Garamond")) { if (!fonts.contains("EB Garamond")) {
QString font = QString::fromStdString(mCfgMgr.getGlobalDataPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); QString font = QString::fromUtf8(mCfgMgr.getGlobalDataPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf");
file.setFileName(font); file.setFileName(font);
if (!file.exists()) { if (!file.exists()) {
font = QString::fromStdString(mCfgMgr.getLocalPath().string()) + QString("resources/mygui/EBGaramond-Regular.ttf"); font = QString::fromUtf8(mCfgMgr.getLocalPath().string().c_str()) + QString("resources/mygui/EBGaramond-Regular.ttf");
} }
fontDatabase.addApplicationFont(font); fontDatabase.addApplicationFont(font);
@ -243,7 +243,7 @@ bool Launcher::MainDialog::showFirstRunDialog()
} }
// Create the file if it doesn't already exist, else the importer will fail // Create the file if it doesn't already exist, else the importer will fail
QString path = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + QString("openmw.cfg"); QString path = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()) + QString("openmw.cfg");
QFile file(path); QFile file(path);
if (!file.exists()) { if (!file.exists()) {
@ -358,7 +358,7 @@ bool Launcher::MainDialog::setupLauncherSettings()
{ {
mLauncherSettings.setMultiValueEnabled(true); mLauncherSettings.setMultiValueEnabled(true);
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
QStringList paths; QStringList paths;
paths.append(QString("launcher.cfg")); paths.append(QString("launcher.cfg"));
@ -464,8 +464,8 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd)
bool Launcher::MainDialog::setupGameSettings() bool Launcher::MainDialog::setupGameSettings()
{ {
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str());
// Load the user config file first, separately // Load the user config file first, separately
// So we can write it properly, uncontaminated // So we can write it properly, uncontaminated
@ -594,7 +594,7 @@ bool Launcher::MainDialog::setupGameSettings()
while(expansions(cd)); while(expansions(cd));
selectedFile = QString::fromStdString(cd.GetMWEsmPath()); selectedFile = QString::fromUtf8(cd.GetMWEsmPath().c_str());
} }
#endif // WIN32 #endif // WIN32
@ -615,8 +615,8 @@ bool Launcher::MainDialog::setupGraphicsSettings()
{ {
mGraphicsSettings.setMultiValueEnabled(false); mGraphicsSettings.setMultiValueEnabled(false);
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str());
QFile localDefault(QString("settings-default.cfg")); QFile localDefault(QString("settings-default.cfg"));
QFile globalDefault(globalPath + QString("settings-default.cfg")); QFile globalDefault(globalPath + QString("settings-default.cfg"));
@ -702,7 +702,7 @@ bool Launcher::MainDialog::writeSettings()
mGraphicsPage->saveSettings(); mGraphicsPage->saveSettings();
mDataFilesPage->saveSettings(); mDataFilesPage->saveSettings();
QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str());
QDir dir(userPath); QDir dir(userPath);
if (!dir.exists()) { if (!dir.exists()) {
@ -806,7 +806,7 @@ void Launcher::MainDialog::play()
msgBox.setWindowTitle(tr("No game file selected")); msgBox.setWindowTitle(tr("No game file selected"));
msgBox.setIcon(QMessageBox::Warning); msgBox.setIcon(QMessageBox::Warning);
msgBox.setStandardButtons(QMessageBox::Ok); msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>You do not have no game file selected.</b><br><br> \ msgBox.setText(tr("<br><b>You do not have a game file selected.</b><br><br> \
OpenMW will not start without a game file selected.<br>")); OpenMW will not start without a game file selected.<br>"));
msgBox.exec(); msgBox.exec();
return; return;

@ -45,7 +45,8 @@ void Launcher::GameSettings::validatePaths()
Files::PathContainer dataDirs; Files::PathContainer dataDirs;
foreach (const QString &path, paths) { foreach (const QString &path, paths) {
dataDirs.push_back(Files::PathContainer::value_type(path.toStdString())); QByteArray bytes = path.toUtf8();
dataDirs.push_back(Files::PathContainer::value_type(std::string(bytes.constData(), bytes.length())));
} }
// Parse the data dirs to convert the tokenized paths // Parse the data dirs to convert the tokenized paths
@ -53,7 +54,7 @@ void Launcher::GameSettings::validatePaths()
mDataDirs.clear(); mDataDirs.clear();
for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) { for (Files::PathContainer::iterator it = dataDirs.begin(); it != dataDirs.end(); ++it) {
QString path = QString::fromStdString(it->string()); QString path = QString::fromUtf8(it->string().c_str());
path.remove(QChar('\"')); path.remove(QChar('\"'));
QDir dir(path); QDir dir(path);
@ -68,12 +69,13 @@ void Launcher::GameSettings::validatePaths()
return; return;
dataDirs.clear(); dataDirs.clear();
dataDirs.push_back(Files::PathContainer::value_type(local.toStdString())); QByteArray bytes = local.toUtf8();
dataDirs.push_back(Files::PathContainer::value_type(std::string(bytes.constData(), bytes.length())));
mCfgMgr.processPaths(dataDirs); mCfgMgr.processPaths(dataDirs);
if (!dataDirs.empty()) { if (!dataDirs.empty()) {
QString path = QString::fromStdString(dataDirs.front().string()); QString path = QString::fromUtf8(dataDirs.front().string().c_str());
path.remove(QChar('\"')); path.remove(QChar('\"'));
QDir dir(path); QDir dir(path);

@ -1,6 +1,6 @@
#include "unshieldthread.hpp" #include "unshieldthread.hpp"
#include <fstream> #include <boost/filesystem/fstream.hpp>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
namespace bfs = boost::filesystem; namespace bfs = boost::filesystem;
@ -49,7 +49,7 @@ namespace
std::string read_to_string(const bfs::path& path) std::string read_to_string(const bfs::path& path)
{ {
std::ifstream strstream(path.c_str(), std::ios::in | std::ios::binary); bfs::ifstream strstream(path, std::ios::in | std::ios::binary);
std::string str; std::string str;
strstream.seekg(0, std::ios::end); strstream.seekg(0, std::ios::end);
@ -201,7 +201,7 @@ namespace
add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini); add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini);
} }
std::ofstream inistream(ini_path.c_str()); bfs::ofstream inistream((ini_path));
inistream << ini; inistream << ini;
inistream.close(); inistream.close();
} }

@ -1,6 +1,5 @@
#include "importer.hpp" #include "importer.hpp"
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <map> #include <map>
@ -9,6 +8,10 @@
#include <sstream> #include <sstream>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
namespace bfs = boost::filesystem;
MwIniImporter::MwIniImporter() MwIniImporter::MwIniImporter()
: mVerbose(false) : mVerbose(false)
@ -661,7 +664,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
std::string section(""); std::string section("");
MwIniImporter::multistrmap map; MwIniImporter::multistrmap map;
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str()); bfs::ifstream file((bfs::path(filename)));
ToUTF8::Utf8Encoder encoder(mEncoding); ToUTF8::Utf8Encoder encoder(mEncoding);
std::string line; std::string line;
@ -674,6 +677,10 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
line = line.substr(0, line.length()-1); line = line.substr(0, line.length()-1);
} }
if(line.empty()) {
continue;
}
if(line[0] == '[') { if(line[0] == '[') {
int pos = line.find(']'); int pos = line.find(']');
if(pos < 2) { if(pos < 2) {
@ -690,10 +697,6 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
line = line.substr(0,comment_pos); line = line.substr(0,comment_pos);
} }
if(line.empty()) {
continue;
}
int pos = line.find("="); int pos = line.find("=");
if(pos < 1) { if(pos < 1) {
continue; continue;
@ -720,7 +723,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filenam
std::cout << "load cfg file: " << filename << std::endl; std::cout << "load cfg file: " << filename << std::endl;
MwIniImporter::multistrmap map; MwIniImporter::multistrmap map;
boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str()); bfs::ifstream file((bfs::path(filename)));
std::string line; std::string line;
while (std::getline(file, line)) { while (std::getline(file, line)) {
@ -858,7 +861,7 @@ void MwIniImporter::importGameFiles(multistrmap &cfg, const multistrmap &ini) co
} }
} }
void MwIniImporter::writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, const multistrmap &cfg) { void MwIniImporter::writeToFile(std::ostream &out, const multistrmap &cfg) {
for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) { for(multistrmap::const_iterator it=cfg.begin(); it != cfg.end(); ++it) {
for(std::vector<std::string>::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) { for(std::vector<std::string>::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) {

@ -1,12 +1,11 @@
#ifndef MWINIIMPORTER_IMPORTER #ifndef MWINIIMPORTER_IMPORTER
#define MWINIIMPORTER_IMPORTER 1 #define MWINIIMPORTER_IMPORTER 1
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/stream.hpp>
#include <string> #include <string>
#include <map> #include <map>
#include <vector> #include <vector>
#include <exception> #include <exception>
#include <iosfwd>
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
@ -24,7 +23,7 @@ class MwIniImporter {
void mergeFallback(multistrmap &cfg, const multistrmap &ini) const; void mergeFallback(multistrmap &cfg, const multistrmap &ini) const;
void importGameFiles(multistrmap &cfg, const multistrmap &ini) const; void importGameFiles(multistrmap &cfg, const multistrmap &ini) const;
void importArchives(multistrmap &cfg, const multistrmap &ini) const; void importArchives(multistrmap &cfg, const multistrmap &ini) const;
static void writeToFile(boost::iostreams::stream<boost::iostreams::file_sink> &out, const multistrmap &cfg); static void writeToFile(std::ostream &out, const multistrmap &cfg);
private: private:
static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value);

@ -1,14 +1,59 @@
#include "importer.hpp" #include "importer.hpp"
#include <iostream>
#include <string> #include <string>
#include <iostream>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
namespace bpo = boost::program_options; namespace bpo = boost::program_options;
namespace bfs = boost::filesystem;
#ifndef _WIN32
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
#else
// Include on Windows only
#include <boost/locale.hpp>
class utf8argv
{
public:
utf8argv(int argc, wchar_t *wargv[])
{
args.reserve(argc);
argv = new const char *[argc];
for (int i = 0; i < argc; ++i) {
args.push_back(boost::locale::conv::utf_to_utf<char>(wargv[i]));
argv[i] = args.back().c_str();
}
}
~utf8argv() { delete[] argv; }
char **get() const { return const_cast<char **>(argv); }
private:
const char **argv;
std::vector<std::string> args;
};
/* The only way to pass Unicode on Winodws with CLI is to use wide
characters interface which presents UTF-16 encoding. The rest of
OpenMW application stack assumes UTF-8 encoding, therefore this
conversion.
For boost::filesystem::path::imbue see components/files/windowspath.cpp
*/
int wmain(int argc, wchar_t *wargv[]) {
utf8argv converter(argc, wargv);
char **argv = converter.get();
boost::filesystem::path::imbue(boost::locale::generator().generate(""));
#endif
bpo::options_description desc("Syntax: mwiniimporter <options> inifile configfile\nAllowed options"); bpo::options_description desc("Syntax: mwiniimporter <options> inifile configfile\nAllowed options");
bpo::positional_options_description p_desc; bpo::positional_options_description p_desc;
desc.add_options() desc.add_options()
@ -94,7 +139,7 @@ int main(int argc, char *argv[]) {
} }
std::cout << "write to: " << outputFile << std::endl; std::cout << "write to: " << outputFile << std::endl;
boost::iostreams::stream<boost::iostreams::file_sink> file(outputFile); bfs::ofstream file((bfs::path(outputFile)));
importer.writeToFile(file, cfg); importer.writeToFile(file, cfg);
return 0; return 0;

@ -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
@ -88,34 +88,30 @@ opencs_units_noqt (view/tools
) )
opencs_units (view/settings opencs_units (view/settings
abstractblock settingwindow
proxyblock dialog
abstractwidget page
usersettingsdialog view
datadisplayformatpage booleanview
windowpage textview
listview
rangeview
resizeablestackedwidget
spinbox
) )
opencs_units_noqt (view/settings opencs_units_noqt (view/settings
abstractpage frame
blankpage
groupblock
customblock
groupbox
itemblock
settingwidget
toggleblock
support
) )
opencs_units (model/settings opencs_units (model/settings
usersettings usersettings
settingcontainer setting
connector
) )
opencs_units_noqt (model/settings opencs_hdrs_noqt (model/settings
support support
settingsitem
) )
opencs_units_noqt (model/filter opencs_units_noqt (model/filter
@ -149,6 +145,10 @@ if(WIN32)
endif(WIN32) endif(WIN32)
set(BOOST_COMPONENTS system filesystem program_options thread wave) set(BOOST_COMPONENTS system filesystem program_options thread wave)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)

@ -20,14 +20,15 @@
#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());
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
@ -37,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 ()));
@ -84,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>();
@ -117,6 +126,13 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end()); dataDirs.insert (dataDirs.end(), dataLocal.begin(), dataLocal.end());
//iterate the data directories and add them to the file dialog for loading
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
{
QString path = QString::fromUtf8 (iter->string().c_str());
mFileDialog.addFiles(path);
}
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> >());
} }
@ -150,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();
} }
@ -166,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();
} }
@ -178,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();
} }
@ -287,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);
}

@ -24,7 +24,7 @@
#include "view/doc/filedialog.hpp" #include "view/doc/filedialog.hpp"
#include "view/doc/newgame.hpp" #include "view/doc/newgame.hpp"
#include "view/settings/usersettingsdialog.hpp" #include "view/settings/dialog.hpp"
namespace OgreInit namespace OgreInit
{ {
@ -43,7 +43,7 @@ namespace CS
CSVDoc::ViewManager mViewManager; CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup; CSVDoc::StartupDialogue mStartup;
CSVDoc::NewGameDialogue mNewGame; CSVDoc::NewGameDialogue mNewGame;
CSVSettings::UserSettingsDialog mSettings; CSVSettings::Dialog mSettings;
CSVDoc::FileDialog mFileDialog; CSVDoc::FileDialog mFileDialog;
boost::filesystem::path mLocal; boost::filesystem::path mLocal;
boost::filesystem::path mResources; boost::filesystem::path mResources;
@ -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));
@ -64,7 +65,11 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
appendStage (new WriteRefIdCollectionStage (mDocument, mState)); appendStage (new WriteRefIdCollectionStage (mDocument, mState));
appendStage (new CollectionReferencesStage (mDocument, mState));
appendStage (new WriteCellCollectionStage (mDocument, mState));
// close file and clean up
appendStage (new CloseSaveStage (mState)); appendStage (new CloseSaveStage (mState));
appendStage (new FinalSavingStage (mDocument, mState)); appendStage (new FinalSavingStage (mDocument, mState));

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

@ -9,6 +9,8 @@
#include <components/esm/loaddial.hpp> #include <components/esm/loaddial.hpp>
#include <components/misc/stringops.hpp>
#include "../world/infocollection.hpp" #include "../world/infocollection.hpp"
#include "document.hpp" #include "document.hpp"
@ -23,11 +25,13 @@ 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);
mState.getStream().open ((mProjectFile ? mState.getPath() : mState.getTmpPath()).string().c_str()); mState.getStream().open (
mProjectFile ? mState.getPath() : mState.getTmpPath(),
std::ios::binary);
if (!mState.getStream().is_open()) if (!mState.getStream().is_open())
throw std::runtime_error ("failed to open stream for saving"); throw std::runtime_error ("failed to open stream for saving");
@ -43,7 +47,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 +100,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 +195,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 +208,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);
@ -214,6 +218,143 @@ void CSMDoc::WriteFilterStage::perform (int stage, std::vector<std::string>& mes
} }
CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document,
SavingState& state)
: mDocument (document), mState (state)
{}
int CSMDoc::CollectionReferencesStage::setup()
{
mState.getSubRecords().clear();
int size = mDocument.getData().getReferences().getSize();
int steps = size/100;
if (size%100) ++steps;
return steps;
}
void CSMDoc::CollectionReferencesStage::perform (int stage, Messages& messages)
{
int size = mDocument.getData().getReferences().getSize();
for (int i=stage*100; i<stage*100+100 && i<size; ++i)
{
const CSMWorld::Record<CSMWorld::CellRef>& record =
mDocument.getData().getReferences().getRecord (i);
if (record.mState==CSMWorld::RecordBase::State_Deleted ||
record.mState==CSMWorld::RecordBase::State_Modified ||
record.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{
mState.getSubRecords()[Misc::StringUtils::lowerCase (record.get().mCell)]
.push_back (i);
}
}
}
CSMDoc::WriteCellCollectionStage::WriteCellCollectionStage (Document& document,
SavingState& state)
: mDocument (document), mState (state)
{}
int CSMDoc::WriteCellCollectionStage::setup()
{
return mDocument.getData().getCells().getSize();
}
void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<CSMWorld::Cell>& cell =
mDocument.getData().getCells().getRecord (stage);
std::map<std::string, std::vector<int> >::const_iterator references =
mState.getSubRecords().find (Misc::StringUtils::lowerCase (cell.get().mId));
if (cell.mState==CSMWorld::RecordBase::State_Modified ||
cell.mState==CSMWorld::RecordBase::State_ModifiedOnly ||
references!=mState.getSubRecords().end())
{
bool interior = cell.get().mId.substr (0, 1)!="#";
// write cell data
mState.getWriter().startRecord (cell.mModified.sRecordId);
mState.getWriter().writeHNOCString ("NAME", cell.get().mName);
ESM::Cell cell2 = cell.get();
if (interior)
cell2.mData.mFlags |= ESM::Cell::Interior;
else
{
cell2.mData.mFlags &= ~ESM::Cell::Interior;
std::istringstream stream (cell.get().mId.c_str());
char ignore;
stream >> ignore >> cell2.mData.mX >> cell2.mData.mY;
}
cell2.save (mState.getWriter());
// write references
if (references!=mState.getSubRecords().end())
{
// first pass: find highest RefNum
int lastRefNum = -1;
for (std::vector<int>::const_iterator iter (references->second.begin());
iter!=references->second.end(); ++iter)
{
const CSMWorld::Record<CSMWorld::CellRef>& ref =
mDocument.getData().getReferences().getRecord (*iter);
if (ref.get().mRefNum.mContentFile==0 && ref.get().mRefNum.mIndex>lastRefNum)
lastRefNum = ref.get().mRefNum.mIndex;
}
// second pass: write
for (std::vector<int>::const_iterator iter (references->second.begin());
iter!=references->second.end(); ++iter)
{
const CSMWorld::Record<CSMWorld::CellRef>& ref =
mDocument.getData().getReferences().getRecord (*iter);
if (ref.mState==CSMWorld::RecordBase::State_Modified ||
ref.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{
if (ref.get().mRefNum.mContentFile==-2)
{
if (lastRefNum>=0xffffff)
throw std::runtime_error (
"RefNums exhausted in cell: " + cell.get().mId);
ESM::CellRef ref2 = ref.get();
ref2.mRefNum.mContentFile = 0;
ref2.mRefNum.mIndex = ++lastRefNum;
ref2.save (mState.getWriter());
}
else
ref.get().save (mState.getWriter());
}
else if (ref.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
}
}
}
mState.getWriter().endRecord (cell.mModified.sRecordId);
}
else if (cell.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
}
}
CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state) CSMDoc::CloseSaveStage::CloseSaveStage (SavingState& state)
: mState (state) : mState (state)
{} {}
@ -223,7 +364,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 +382,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())
{ {
@ -260,4 +401,4 @@ void CSMDoc::FinalSavingStage::perform (int stage, std::vector<std::string>& mes
mDocument.getUndoStack().setClean(); mDocument.getUndoStack().setClean();
} }
} }

@ -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,10 +161,42 @@ 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.
};
class CollectionReferencesStage : public Stage
{
Document& mDocument;
SavingState& mState;
public:
CollectionReferencesStage (Document& document, SavingState& state);
virtual int setup();
///< \return number of steps
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.
}; };
class WriteCellCollectionStage : public Stage
{
Document& mDocument;
SavingState& mState;
public:
WriteCellCollectionStage (Document& document, SavingState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class CloseSaveStage : public Stage class CloseSaveStage : public Stage
{ {
@ -177,7 +209,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 +225,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);
} }
@ -27,6 +25,8 @@ void CSMDoc::SavingState::start (Document& document, bool project)
mStream.clear(); mStream.clear();
mSubRecords.clear();
if (project) if (project)
mPath = mProjectPath; mPath = mProjectPath;
else else
@ -49,7 +49,7 @@ const boost::filesystem::path& CSMDoc::SavingState::getTmpPath() const
return mTmpPath; return mTmpPath;
} }
std::ofstream& CSMDoc::SavingState::getStream() boost::filesystem::ofstream& CSMDoc::SavingState::getStream()
{ {
return mStream; return mStream;
} }
@ -62,4 +62,9 @@ ESM::ESMWriter& CSMDoc::SavingState::getWriter()
bool CSMDoc::SavingState::isProjectFile() const bool CSMDoc::SavingState::isProjectFile() const
{ {
return mProjectFile; return mProjectFile;
} }
std::map<std::string, std::vector<int> >& CSMDoc::SavingState::getSubRecords()
{
return mSubRecords;
}

@ -2,11 +2,15 @@
#define CSM_DOC_SAVINGSTATE_H #define CSM_DOC_SAVINGSTATE_H
#include <fstream> #include <fstream>
#include <map>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp>
#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;
@ -18,14 +22,16 @@ namespace CSMDoc
boost::filesystem::path mPath; boost::filesystem::path mPath;
boost::filesystem::path mTmpPath; boost::filesystem::path mTmpPath;
ToUTF8::Utf8Encoder mEncoder; ToUTF8::Utf8Encoder mEncoder;
std::ofstream mStream; boost::filesystem::ofstream mStream;
ESM::ESMWriter mWriter; ESM::ESMWriter mWriter;
boost::filesystem::path mProjectPath; boost::filesystem::path mProjectPath;
bool mProjectFile; bool mProjectFile;
std::map<std::string, std::vector<int> > mSubRecords; // record ID, list of subrecords
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;
@ -36,15 +42,17 @@ namespace CSMDoc
const boost::filesystem::path& getTmpPath() const; const boost::filesystem::path& getTmpPath() const;
std::ofstream& getStream(); boost::filesystem::ofstream& getStream();
ESM::ESMWriter& getWriter(); ESM::ESMWriter& getWriter();
bool isProjectFile() const; bool isProjectFile() const;
///< Currently saving project file? (instead of content file) ///< Currently saving project file? (instead of content file)
std::map<std::string, std::vector<int> >& getSubRecords();
}; };
} }
#endif #endif

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

@ -0,0 +1,128 @@
#include "connector.hpp"
#include "../../view/settings/view.hpp"
#include "../../view/settings/page.hpp"
CSMSettings::Connector::Connector(CSVSettings::View *master,
QObject *parent)
: mMasterView (master), QObject(parent)
{}
void CSMSettings::Connector::addSlaveView (CSVSettings::View *view,
QList <QStringList> &masterProxyValues)
{
mSlaveViews.append (view);
mProxyListMap[view->viewKey()].append (masterProxyValues);
}
QList <QStringList> CSMSettings::Connector::getSlaveViewValues() const
{
QList <QStringList> list;
foreach (const CSVSettings::View *view, mSlaveViews)
list.append (view->selectedValues());
return list;
}
bool CSMSettings::Connector::proxyListsMatch (
const QList <QStringList> &list1,
const QList <QStringList> &list2) const
{
bool success = true;
for (int i = 0; i < list1.size(); i++)
{
success = stringListsMatch (list1.at(i), list2.at(i));
if (!success)
break;
}
return success;
}
void CSMSettings::Connector::slotUpdateMaster() const
{
//list of the current values for each slave.
QList <QStringList> slaveValueList = getSlaveViewValues();
int masterColumn = -1;
/*
* A row in the master view is one of the values in the
* master view's data model. This corresponds directly to the number of
* values in a proxy list contained in the ProxyListMap member.
* Thus, we iterate each "column" in the master proxy list
* (one for each vlaue in the master. Each column represents
* one master value's corresponding list of slave values. We examine
* each master value's list, comparing it to the current slave value list,
* stopping when we find a match using proxyListsMatch().
*
* If no match is found, clear the master view's value
*/
for (int i = 0; i < mMasterView->rowCount(); i++)
{
QList <QStringList> proxyValueList;
foreach (const QString &settingKey, mProxyListMap.keys())
{
// append the proxy value list stored in the i'th column
// for each setting key. A setting key is the id of the setting
// in page.name format.
proxyValueList.append (mProxyListMap.value(settingKey).at(i));
}
if (proxyListsMatch (slaveValueList, proxyValueList))
{
masterColumn = i;
break;
}
}
QString masterValue = mMasterView->value (masterColumn);
mMasterView->setSelectedValue (masterValue);
}
void CSMSettings::Connector::slotUpdateSlaves() const
{
int row = mMasterView->currentIndex();
if (row == -1)
return;
//iterate the proxy lists for the chosen master index
//and pass the list to each slave for updating
for (int i = 0; i < mSlaveViews.size(); i++)
{
QList <QStringList> proxyList =
mProxyListMap.value(mSlaveViews.at(i)->viewKey());
mSlaveViews.at(i)->setSelectedValues (proxyList.at(row));
}
}
bool CSMSettings::Connector::stringListsMatch (
const QStringList &list1,
const QStringList &list2) const
{
//returns a "sloppy" match, verifying that each list contains all the same
//items, though not necessarily in the same order.
if (list1.size() != list2.size())
return false;
QStringList tempList(list2);
//iterate each value in the list, removing one occurrence of the value in
//the other list. If no corresponding value is found, test fails
foreach (const QString &value, list1)
{
if (!tempList.contains(value))
return false;
tempList.removeOne(value);
}
return true;
}

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

@ -0,0 +1,391 @@
#include "setting.hpp"
#include "support.hpp"
CSMSettings::Setting::Setting(SettingType typ, const QString &settingName,
const QString &pageName)
: mIsEditorSetting (false)
{
buildDefaultSetting();
int settingType = static_cast <int> (typ);
//even-numbered setting types are multi-valued
if ((settingType % 2) == 0)
setProperty (Property_IsMultiValue, QVariant(true).toString());
//view type is related to setting type by an order of magnitude
setProperty (Property_SettingType, QVariant (settingType).toString());
setProperty (Property_Page, pageName);
setProperty (Property_Name, settingName);
}
void CSMSettings::Setting::buildDefaultSetting()
{
int arrLen = sizeof(sPropertyDefaults) / sizeof (*sPropertyDefaults);
for (int i = 0; i < arrLen; i++)
{
QStringList propertyList;
if (i <Property_DefaultValues)
propertyList.append (sPropertyDefaults[i]);
mProperties.append (propertyList);
}
}
void CSMSettings::Setting::addProxy (const Setting *setting,
const QStringList &vals)
{
if (serializable())
setSerializable (false);
QList <QStringList> list;
foreach (const QString &val, vals)
list << (QStringList() << val);
mProxies [setting->page() + '/' + setting->name()] = list;
}
void CSMSettings::Setting::addProxy (const Setting *setting,
const QList <QStringList> &list)
{
if (serializable())
setProperty (Property_Serializable, false);
mProxies [setting->page() + '/' + setting->name()] = list;
}
void CSMSettings::Setting::setColumnSpan (int value)
{
setProperty (Property_ColumnSpan, value);
}
int CSMSettings::Setting::columnSpan() const
{
return property (Property_ColumnSpan).at(0).toInt();
}
void CSMSettings::Setting::setDeclaredValues (QStringList list)
{
setProperty (Property_DeclaredValues, list);
}
QStringList CSMSettings::Setting::declaredValues() const
{
return property (Property_DeclaredValues);
}
QStringList CSMSettings::Setting::property (SettingProperty prop) const
{
if (prop >= mProperties.size())
return QStringList();
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)
{
setDefaultValues (QStringList() << value);
}
void CSMSettings::Setting::setDefaultValues (const QStringList &values)
{
setProperty (Property_DefaultValues, values);
}
QStringList CSMSettings::Setting::defaultValues() const
{
return property (Property_DefaultValues);
}
void CSMSettings::Setting::setDelimiter (const QString &value)
{
setProperty (Property_Delimiter, value);
}
QString CSMSettings::Setting::delimiter() const
{
return property (Property_Delimiter).at(0);
}
void CSMSettings::Setting::setEditorSetting(bool state)
{
mIsEditorSetting = true;
}
bool CSMSettings::Setting::isEditorSetting() const
{
return mIsEditorSetting;
}
void CSMSettings::Setting::setIsMultiLine (bool state)
{
setProperty (Property_IsMultiLine, state);
}
bool CSMSettings::Setting::isMultiLine() const
{
return (property (Property_IsMultiLine).at(0) == "true");
}
void CSMSettings::Setting::setIsMultiValue (bool state)
{
setProperty (Property_IsMultiValue, state);
}
bool CSMSettings::Setting::isMultiValue() const
{
return (property (Property_IsMultiValue).at(0) == "true");
}
const CSMSettings::ProxyValueMap &CSMSettings::Setting::proxyLists() const
{
return mProxies;
}
void CSMSettings::Setting::setSerializable (bool state)
{
setProperty (Property_Serializable, state);
}
bool CSMSettings::Setting::serializable() const
{
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)
{
setProperty (Property_Name, value);
}
QString CSMSettings::Setting::name() const
{
return property (Property_Name).at(0);
}
void CSMSettings::Setting::setPage (const QString &value)
{
setProperty (Property_Page, value);
}
QString CSMSettings::Setting::page() const
{
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)
{
setProperty (Property_RowSpan, value);
}
int CSMSettings::Setting::rowSpan () const
{
return property (Property_RowSpan).at(0).toInt();
}
void CSMSettings::Setting::setSingleStep (int value)
{
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
{
return static_cast <CSVSettings::ViewType> ( property (
Property_SettingType).at(0).toInt() / 10);
}
void CSMSettings::Setting::setViewColumn (int value)
{
setProperty (Property_ViewColumn, value);
}
int CSMSettings::Setting::viewColumn() const
{
return property (Property_ViewColumn).at(0).toInt();
}
void CSMSettings::Setting::setViewLocation (int row, int column)
{
setViewRow (row);
setViewColumn (column);
}
void CSMSettings::Setting::setViewRow (int value)
{
setProperty (Property_ViewRow, value);
}
int CSMSettings::Setting::viewRow() const
{
return property (Property_ViewRow).at(0).toInt();
}
void CSMSettings::Setting::setWidgetWidth (int value)
{
setProperty (Property_WidgetWidth, value);
}
int CSMSettings::Setting::widgetWidth() const
{
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)
{
setProperty (prop, QStringList() << QVariant (value).toString());
}
void CSMSettings::Setting::setProperty (SettingProperty prop, int value)
{
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,
const QString &value)
{
setProperty (prop, QStringList() << value);
}
void CSMSettings::Setting::setProperty (SettingProperty prop,
const QStringList &value)
{
if (prop < mProperties.size())
mProperties.replace (prop, value);
}

@ -0,0 +1,150 @@
#ifndef CSMSETTINGS_SETTING_HPP
#define CSMSETTINGS_SETTING_HPP
#include <QStringList>
#include <QMap>
#include "support.hpp"
namespace CSMSettings
{
//QString is the setting id in the form of "page/name"
//QList is a list of stringlists of proxy values.
//Order is important! Proxy stringlists are matched against
//master values by their position in the QList.
typedef QMap <QString, QList <QStringList> > ProxyValueMap;
///Setting class is the interface for the User Settings. It contains
///a great deal of boiler plate to provide the core API functions, as
///well as the property() functions which use enumeration to be iterable.
///This makes the Setting class capable of being manipulated by script.
///See CSMSettings::support.hpp for enumerations / string values.
class Setting
{
QList <QStringList> mProperties;
QStringList mDefaults;
bool mIsEditorSetting;
ProxyValueMap mProxies;
public:
explicit Setting(SettingType typ, const QString &settingName,
const QString &pageName);
void addProxy (const Setting *setting, const QStringList &vals);
void addProxy (const Setting *setting, const QList <QStringList> &list);
const QList <QStringList> &properties() const { return mProperties; }
const ProxyValueMap &proxies() const { return mProxies; }
void setColumnSpan (int value);
int columnSpan() const;
void setDeclaredValues (QStringList list);
QStringList declaredValues() const;
void setDefaultValue (int value);
void setDefaultValue (double value);
void setDefaultValue (const QString &value);
void setDefaultValues (const QStringList &values);
QStringList defaultValues() const;
void setDelimiter (const QString &value);
QString delimiter() const;
void setEditorSetting (bool state);
bool isEditorSetting() const;
void setIsMultiLine (bool state);
bool isMultiLine() const;
void setIsMultiValue (bool state);
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);
QString name() const;
void setPage (const QString &value);
QString page() const;
void setPrefix (const QString &value);
QString prefix() const;
void setRowSpan (const int value);
int rowSpan() const;
const ProxyValueMap &proxyLists() const;
void setSerializable (bool state);
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);
int viewColumn() const;
void setViewLocation (int row = -1, int column = -1);
void setViewRow (int value);
int viewRow() const;
void setType (int settingType);
CSMSettings::SettingType type() const;
CSVSettings::ViewType viewType() const;
void setWrapping (bool state);
bool wrapping() const;
void setWidgetWidth (int value);
int widgetWidth() const;
///returns the specified property value
QStringList property (SettingProperty prop) const;
///boilerplate code to convert setting values of common types
void setProperty (SettingProperty prop, bool 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 QStringList &value);
void addProxy (Setting* setting,
QMap <QString, QStringList> &proxyMap);
protected:
void buildDefaultSetting();
};
}
#endif // CSMSETTINGS_SETTING_HPP

@ -1,82 +0,0 @@
#include "settingcontainer.hpp"
#include <QStringList>
CSMSettings::SettingContainer::SettingContainer(QObject *parent) :
QObject(parent), mValue (0), mValues (0)
{
}
CSMSettings::SettingContainer::SettingContainer(const QString &value, QObject *parent) :
QObject(parent), mValue (new QString (value)), mValues (0)
{
}
void CSMSettings::SettingContainer::insert (const QString &value)
{
if (mValue)
{
mValues = new QStringList;
mValues->push_back (*mValue);
mValues->push_back (value);
delete mValue;
mValue = 0;
}
else
{
delete mValue;
mValue = new QString (value);
}
}
void CSMSettings::SettingContainer::update (const QString &value, int index)
{
if (isEmpty())
mValue = new QString(value);
else if (mValue)
*mValue = value;
else if (mValues)
mValues->replace(index, value);
}
QString CSMSettings::SettingContainer::getValue (int index) const
{
QString retVal("");
//if mValue is valid, it's a single-value property.
//ignore the index and return the value
if (mValue)
retVal = *mValue;
//otherwise, if it's a multivalued property
//return the appropriate value at the index
else if (mValues)
{
if (index == -1)
retVal = mValues->at(0);
else if (index < mValues->size())
retVal = mValues->at(index);
}
return retVal;
}
int CSMSettings::SettingContainer::count () const
{
int retVal = 0;
if (!isEmpty())
{
if (mValues)
retVal = mValues->size();
else
retVal = 1;
}
return retVal;
}

@ -1,47 +0,0 @@
#ifndef SETTINGCONTAINER_HPP
#define SETTINGCONTAINER_HPP
#include <QObject>
class QStringList;
namespace CSMSettings
{
class SettingContainer : public QObject
{
Q_OBJECT
QString *mValue;
QStringList *mValues;
public:
explicit SettingContainer (QObject *parent = 0);
explicit SettingContainer (const QString &value, QObject *parent = 0);
/// add a value to the container
/// multiple values supported
void insert (const QString &value);
/// update an existing value
/// index specifies multiple values
void update (const QString &value, int index = 0);
/// return value at specified index
QString getValue (int index = -1) const;
/// retrieve list of all values
inline QStringList *getValues() const { return mValues; }
/// return size of list
int count() const;
/// test for empty container
/// useful for default-constructed containers returned by QMap when invalid key is passed
inline bool isEmpty() const { return (!mValue && !mValues); }
inline bool isMultiValue() const { return (mValues); }
};
}
#endif // SETTINGCONTAINER_HPP

@ -1,104 +0,0 @@
#include "settingsitem.hpp"
#include <QStringList>
bool CSMSettings::SettingsItem::updateItem (const QStringList *values)
{
QStringList::ConstIterator it = values->begin();
//if the item is not multivalued,
//save the last value passed in the container
if (!mIsMultiValue)
{
it = values->end();
it--;
}
bool isValid = true;
QString value ("");
for (; it != values->end(); ++it)
{
value = *it;
isValid = validate(value);
//skip only the invalid values
if (!isValid)
continue;
insert(value);
}
return isValid;
}
bool CSMSettings::SettingsItem::updateItem (const QString &value)
{
//takes a value or a SettingsContainer and updates itself accordingly
//after validating the data against it's own definition
QString newValue = value;
if (!validate (newValue))
newValue = mDefaultValue;
bool success = (getValue() != newValue);
if (success)
{
if (mIsMultiValue)
insert (newValue);
else
update (newValue);
}
return success;
}
bool CSMSettings::SettingsItem::updateItem(int valueListIndex)
{
bool success = false;
if (mValueList)
{
if (mValueList->size() > valueListIndex)
success = updateItem (mValueList->at(valueListIndex));
}
return success;
}
bool CSMSettings::SettingsItem::validate (const QString &value)
{
//if there is no value list or value pair, there is no validation to do
bool isValid = !(!mValueList->isEmpty() || mValuePair);
if (!isValid && !mValueList->isEmpty())
{
for (QStringList::Iterator it = mValueList->begin(); it != mValueList->end(); ++it)
// foreach (QString listItem, *mValueList)
{
isValid = (value == *it);
if (isValid)
break;
}
}
else if (!isValid && mValuePair)
{
int numVal = value.toInt();
isValid = (numVal > mValuePair->left.toInt() && numVal < mValuePair->right.toInt());
}
return isValid;
}
void CSMSettings::SettingsItem::setDefaultValue (const QString &value)
{
mDefaultValue = value;
update (value);
}
QString CSMSettings::SettingsItem::getDefaultValue() const
{
return mDefaultValue;
}

@ -1,67 +0,0 @@
#ifndef SETTINGSITEM_HPP
#define SETTINGSITEM_HPP
#include <QObject>
#include "support.hpp"
#include "settingcontainer.hpp"
namespace CSMSettings
{
/// Represents a setting including metadata
/// (valid values, ranges, defaults, and multivalue status
class SettingsItem : public SettingContainer
{
QStringPair *mValuePair;
QStringList *mValueList;
bool mIsMultiValue;
QString mDefaultValue;
public:
explicit SettingsItem(QString name, bool isMultiValue,
const QString& defaultValue, QObject *parent = 0)
: SettingContainer(defaultValue, parent),
mIsMultiValue (isMultiValue), mValueList (0),
mValuePair (0), mDefaultValue (defaultValue)
{
QObject::setObjectName(name);
}
/// updateItem overloads for updating setting value
/// provided a list of values (multi-valued),
/// a specific value
/// or an index value corresponding to the mValueList
bool updateItem (const QStringList *values);
bool updateItem (const QString &value);
bool updateItem (int valueListIndex);
/// retrieve list of valid values for setting
inline QStringList *getValueList() { return mValueList; }
/// write list of valid values for setting
inline void setValueList (QStringList *valueList) { mValueList = valueList; }
/// valuePair used for spin boxes (max / min)
inline QStringPair *getValuePair() { return mValuePair; }
/// set value range (spinbox / integer use)
inline void setValuePair (QStringPair valuePair)
{
delete mValuePair;
mValuePair = new QStringPair(valuePair);
}
inline bool isMultivalue () { return mIsMultiValue; }
void setDefaultValue (const QString &value);
QString getDefaultValue () const;
private:
/// Verifies that the supplied value is one of the following:
/// 1. Within the limits of the value pair (min / max)
/// 2. One of the values indicated in the value list
bool validate (const QString &value);
};
}
#endif // SETTINGSITEM_HPP

@ -1 +0,0 @@
#include "support.hpp"

@ -1,39 +1,145 @@
#ifndef MODEL_SUPPORT_HPP #ifndef SETTING_SUPPORT_HPP
#define MODEL_SUPPORT_HPP #define SETTING_SUPPORT_HPP
#include <QObject> #include <Qt>
#include <QPair>
#include <QList>
#include <QVariant>
#include <QStringList> #include <QStringList>
class QLayout; //Enums
class QWidget;
class QListWidgetItem;
namespace CSMSettings namespace CSMSettings
{ {
class SettingContainer; ///Enumerated properties for scripting
enum SettingProperty
{
Property_Name = 0,
Property_Page = 1,
Property_SettingType = 2,
Property_IsMultiValue = 3,
Property_IsMultiLine = 4,
Property_WidgetWidth = 5,
Property_ViewRow = 6,
Property_ViewColumn = 7,
Property_Delimiter = 8,
Property_Serializable = 9,
Property_ColumnSpan = 10,
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
Property_DefaultValues = 22,
Property_DeclaredValues = 23,
Property_DefinedValues = 24,
Property_Proxies = 25
};
///Basic setting widget types.
enum SettingType
{
/*
* 0 - 9 - Boolean widgets
* 10-19 - List widgets
* 21-29 - Range widgets
* 31-39 - Text widgets
*
* Each range corresponds to a View_Type enum by a factor of 10.
*
* Even-numbered values are single-value widgets
* Odd-numbered values are multi-valued widgets
*/
typedef QList<SettingContainer *> SettingList; Type_CheckBox = 0,
typedef QMap<QString, SettingContainer *> SettingMap; Type_RadioButton = 1,
typedef QMap<QString, SettingMap *> SectionMap; Type_ListView = 10,
Type_ComboBox = 11,
Type_SpinBox = 21,
Type_DoubleSpinBox = 23,
Type_Slider = 25,
Type_Dial = 27,
Type_TextArea = 30,
Type_LineEdit = 31,
Type_Undefined = 40
};
struct QStringPair }
namespace CSVSettings
{
///Categorical view types which encompass the setting widget types
enum ViewType
{ {
QStringPair(): left (""), right ("") ViewType_Boolean = 0,
{} ViewType_List = 1,
ViewType_Range = 2,
ViewType_Text = 3,
ViewType_Undefined = 4
};
}
QStringPair (const QString &leftValue, const QString &rightValue)
: left (leftValue), right(rightValue)
{}
QStringPair (const QStringPair &pair) namespace CSMSettings
: left (pair.left), right (pair.right) {
{} ///used to construct default settings in the Setting class
struct PropertyDefaultValues
{
int id;
QString name;
QVariant value;
};
QString left; ///strings which correspond to setting values. These strings represent
QString right; ///the script language keywords which would be used to declare setting
///views for 3rd party addons
const QString sPropertyNames[] =
{
"name", "page", "setting_type", "is_multi_value",
"is_multi_line", "widget_width", "view_row", "view_column", "delimiter",
"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"
};
bool isEmpty() const ///Default values for a setting. Used in setting creation.
{ return (left.isEmpty() && right.isEmpty()); } const QString sPropertyDefaults[] =
{
"", //name
"", //page
"40", //setting type
"false", //multivalue
"false", //multiline
"7", //widget width
"-1", //view row
"-1", //view column
",", //delimiter
"true", //serialized
"1", //column 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
"", //declared values
"", //defined values
"" //proxy values
}; };
} }
#endif // MODEL_SUPPORT_HPP
#endif // VIEW_SUPPORT_HPP

@ -1,19 +1,15 @@
#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 <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include "settingcontainer.hpp"
#include <boost/version.hpp> #include <boost/version.hpp>
#include "setting.hpp"
#include "support.hpp"
#include <QDebug>
/** /**
* Workaround for problems with whitespaces in paths in older versions of Boost library * Workaround for problems with whitespaces in paths in older versions of Boost library
*/ */
@ -32,324 +28,400 @@ 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;
mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for writing</b><br><br> \ mSettingDefinitions = 0;
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> \ buildSettingModelDefaults();
Please make sure you have the right permissions and try again.<br>");
buildEditorSettingDefaults();
} }
void CSMSettings::UserSettings::buildEditorSettingDefaults() void CSMSettings::UserSettings::buildSettingModelDefaults()
{ {
SettingContainer *windowHeight = new SettingContainer("768", this); QString section = "Window Size";
SettingContainer *windowWidth = new SettingContainer("1024", this); {
SettingContainer *rsDelegate = new SettingContainer("Icon and Text", this); Setting *width = createSetting (Type_LineEdit, section, "Width");
SettingContainer *refIdTypeDelegate = new SettingContainer("Icon and Text", this); Setting *height = createSetting (Type_LineEdit, section, "Height");
windowHeight->setObjectName ("Height"); width->setWidgetWidth (5);
windowWidth->setObjectName ("Width"); height->setWidgetWidth (8);
rsDelegate->setObjectName ("Record Status Display");
refIdTypeDelegate->setObjectName ("Referenceable ID Type Display");
SettingMap *displayFormatMap = new SettingMap; width->setDefaultValues (QStringList() << "1024");
SettingMap *windowSizeMap = new SettingMap; height->setDefaultValues (QStringList() << "768");
displayFormatMap->insert (rsDelegate->objectName(), rsDelegate ); width->setEditorSetting (true);
displayFormatMap->insert (refIdTypeDelegate->objectName(), refIdTypeDelegate); height->setEditorSetting (true);
windowSizeMap->insert (windowWidth->objectName(), windowWidth ); height->setViewLocation (2,2);
windowSizeMap->insert (windowHeight->objectName(), windowHeight ); width->setViewLocation (2,1);
mEditorSettingDefaults.insert ("Display Format", displayFormatMap); /*
mEditorSettingDefaults.insert ("Window Size", windowSizeMap); *Create the proxy setting for predefined values
} */
Setting *preDefined = createSetting (Type_ComboBox, section,
"Pre-Defined");
CSMSettings::UserSettings::~UserSettings() preDefined->setDeclaredValues (QStringList() << "640 x 480"
{ << "800 x 600" << "1024 x 768" << "1440 x 900");
mUserSettingsInstance = 0;
}
QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly) const
{
QIODevice::OpenMode openFlags = QIODevice::Text;
if (isReadOnly) preDefined->setViewLocation (1, 1);
openFlags = QIODevice::ReadOnly | openFlags; preDefined->setWidgetWidth (10);
else preDefined->setColumnSpan (2);
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
QFile *file = new QFile(filePath); preDefined->addProxy (width,
QTextStream *stream = 0; QStringList() << "640" << "800" << "1024" << "1440"
);
if (file->open(openFlags)) preDefined->addProxy (height,
{ QStringList() << "480" << "600" << "768" << "900"
stream = new QTextStream(file); );
stream->setCodec(QTextCodec::codecForName("UTF-8"));
} }
return stream; section = "Display Format";
}
bool CSMSettings::UserSettings::writeSettings(QMap<QString, CSMSettings::SettingList *> &settings)
{
QTextStream *stream = openFileStream(mUserFilePath);
bool success = (stream);
if (success)
{ {
QList<QString> keyList = settings.keys(); QString defaultValue = "Icon and Text";
foreach (QString key, keyList)
{
SettingList *sectionSettings = settings[key];
*stream << "[" << key << "]" << '\n'; QStringList values = QStringList()
<< defaultValue << "Icon Only" << "Text Only";
foreach (SettingContainer *item, *sectionSettings) Setting *rsd = createSetting (Type_RadioButton,
*stream << item->objectName() << " = " << item->getValue() << '\n'; section, "Record Status Display");
}
stream->device()->close(); Setting *ritd = createSetting (Type_RadioButton,
delete stream; section, "Referenceable ID Type Display");
stream = 0;
}
else
{
displayFileErrorMessage(mReadWriteMessage, false);
}
return (success); rsd->setDeclaredValues (values);
} ritd->setDeclaredValues (values);
rsd->setEditorSetting (true);
ritd->setEditorSetting (true);
}
const CSMSettings::SectionMap &CSMSettings::UserSettings::getSectionMap() const section = "Proxy Selection Test";
{ {
return mSectionSettings; /******************************************************************
* 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,
"Master Proxy");
Setting *slaveBoolean = createSetting (Type_CheckBox, section,
"Proxy Checkboxes");
Setting *slaveSingleText = createSetting (Type_LineEdit, section,
"Proxy TextBox 1");
Setting *slaveMultiText = createSetting (Type_LineEdit, section,
"ProxyTextBox 2");
Setting *slaveAlphaSpinbox = createSetting (Type_SpinBox, section,
"Alpha Spinbox");
Setting *slaveIntegerSpinbox = createSetting (Type_SpinBox, section,
"Int Spinbox");
Setting *slaveDoubleSpinbox = createSetting (Type_DoubleSpinBox,
section, "Double Spinbox");
Setting *slaveSlider = createSetting (Type_Slider, section, "Slider");
Setting *slaveDial = createSetting (Type_Dial, section, "Dial");
//set declared values for selected views
masterBoolean->setDeclaredValues (QStringList()
<< "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>()
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three" << "Five")
<< (QStringList() << "Two" << "Four")
);
masterBoolean->addProxy (slaveSingleText, QList <QStringList>()
<< (QStringList() << "Text A")
<< (QStringList() << "Text B")
<< (QStringList() << "Text A")
<< (QStringList() << "Text C")
);
masterBoolean->addProxy (slaveMultiText, QList <QStringList>()
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three")
<< (QStringList() << "One" << "Three" << "Five")
<< (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
//other settings non-serialized for demo purposes
slaveBoolean->setSerializable (false);
slaveSingleText->setSerializable (false);
slaveMultiText->setSerializable (false);
slaveAlphaSpinbox->setSerializable (false);
slaveIntegerSpinbox->setSerializable (false);
slaveDoubleSpinbox->setSerializable (false);
slaveSlider->setSerializable (false);
slaveDial->setSerializable (false);
slaveBoolean->setDefaultValues (QStringList()
<< "One" << "Three" << "Five");
slaveSingleText->setDefaultValue ("Text A");
slaveMultiText->setDefaultValues (QStringList()
<< "One" << "Three" << "Five");
slaveSingleText->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);
*/
}
} }
const CSMSettings::SettingMap *CSMSettings::UserSettings::getSettings(const QString &sectionName) const CSMSettings::UserSettings::~UserSettings()
{ {
return getValidSettings(sectionName); mUserSettingsInstance = 0;
} }
bool CSMSettings::UserSettings::loadFromFile(const QString &filePath) void CSMSettings::UserSettings::loadSettings (const QString &fileName)
{ {
if (filePath.isEmpty()) QString userFilePath = QString::fromUtf8
return false; (mCfgMgr.getUserConfigPath().string().c_str());
SectionMap loadedSettings;
QTextStream *stream = openFileStream (filePath, true); QString globalFilePath = QString::fromUtf8
(mCfgMgr.getGlobalPath().string().c_str());
bool success = (stream); QString otherFilePath = globalFilePath;
if (success) //test for local only if global fails (uninstalled copy)
if (!QFile (globalFilePath + fileName).exists())
{ {
//looks for a square bracket, "'\\[" //if global is invalid, use the local path
//that has one or more "not nothing" in it, "([^]]+)" otherFilePath = QString::fromUtf8
//and is closed with a square bracket, "\\]" (mCfgMgr.getLocalPath().string().c_str());
}
QRegExp sectionRe("^\\[([^]]+)\\]");
//Find any character(s) that is/are not equal sign(s), "[^=]+"
//followed by an optional whitespace, an equal sign, and another optional whitespace, "\\s*=\\s*"
//and one or more periods, "(.+)"
QRegExp keyRe("^([^=]+)\\s*=\\s*(.+)$");
CSMSettings::SettingMap *settings = 0; QSettings::setPath
QString section = "none"; (QSettings::IniFormat, QSettings::UserScope, userFilePath);
while (!stream->atEnd()) QSettings::setPath
{ (QSettings::IniFormat, QSettings::SystemScope, otherFilePath);
QString line = stream->readLine().simplified();
if (line.isEmpty() || line.startsWith("#")) mSettingDefinitions = new QSettings
continue; (QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this);
}
//if a section is found, push it onto a new QStringList bool CSMSettings::UserSettings::hasSettingDefinitions
//and push the QStringList onto (const QString &viewKey) const
if (sectionRe.exactMatch(line)) {
{ return (mSettingDefinitions->contains (viewKey));
//add the previous section's settings to the member map }
if (settings)
loadedSettings.insert(section, settings);
//save new section and create a new list
section = sectionRe.cap(1);
settings = new SettingMap;
continue;
}
if (keyRe.indexIn(line) != -1) void CSMSettings::UserSettings::setDefinitions
{ (const QString &key, const QStringList &list)
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified()); {
sc->setObjectName(keyRe.cap(1).simplified()); mSettingDefinitions->setValue (key, list);
(*settings)[keyRe.cap(1).simplified()] = sc; }
}
} void CSMSettings::UserSettings::saveDefinitions() const
{
mSettingDefinitions->sync();
}
loadedSettings.insert(section, settings); QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
{
if (!mSettingDefinitions->contains (settingKey))
return QString();
stream->device()->close(); QStringList defs = mSettingDefinitions->value (settingKey).toStringList();
delete stream;
stream = 0;
}
mergeMap (loadedSettings); if (defs.isEmpty())
return QString();
return success; return defs.at(0);
} }
void CSMSettings::UserSettings::mergeMap (const CSMSettings::SectionMap &sectionSettings) CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
{ {
foreach (QString key, sectionSettings.uniqueKeys()) assert(mUserSettingsInstance);
{ return *mUserSettingsInstance;
// insert entire section if it does not already exist in the loaded files
if (mSectionSettings.find(key) == mSectionSettings.end())
mSectionSettings.insert(key, sectionSettings.value(key));
else
{
SettingMap *passedSettings = sectionSettings.value(key);
SettingMap *settings = mSectionSettings.value(key);
foreach (QString key2, passedSettings->uniqueKeys())
{
//insert section settings individially if they do not already exist
if (settings->find(key2) == settings->end())
settings->insert(key2, passedSettings->value(key2));
else
{
settings->value(key2)->update(passedSettings->value(key2)->getValue());
}
}
}
}
} }
void CSMSettings::UserSettings::loadSettings (const QString &fileName) void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
const QStringList &list)
{ {
mSectionSettings.clear(); mSettingDefinitions->setValue (settingKey ,list);
//global
QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName;
bool globalOk = loadFromFile(globalFilePath);
//local emit userSettingUpdated (settingKey, list);
QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName; }
bool localOk = loadFromFile(localFilePath);
//user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName;
loadFromFile(mUserFilePath);
if (!(localOk || globalOk)) CSMSettings::Setting *CSMSettings::UserSettings::findSetting
(const QString &pageName, const QString &settingName)
{
foreach (Setting *setting, mSettings)
{ {
QString message = QObject::tr("<br><b>Could not open user settings files for reading</b><br><br> \ if (setting->name() == settingName)
Global and local settings files could not be read.\ {
You may have incorrect file permissions or the OpenCS installation may be corrupted.<br>"); if (setting->page() == pageName)
return setting;
message += QObject::tr("<br>Global filepath: ") + globalFilePath; }
message += QObject::tr("<br>Local filepath: ") + localFilePath;
displayFileErrorMessage ( message, true);
} }
return 0;
} }
void CSMSettings::UserSettings::updateSettings (const QString &sectionName, const QString &settingName) void CSMSettings::UserSettings::removeSetting
(const QString &pageName, const QString &settingName)
{ {
if (mSettings.isEmpty())
SettingMap *settings = getValidSettings(sectionName);
if (!settings)
return; return;
if (settingName.isEmpty()) QList <Setting *>::iterator removeIterator = mSettings.begin();
{
foreach (const SettingContainer *setting, *settings) while (removeIterator != mSettings.end())
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
else
{ {
if (settings->find(settingName) != settings->end()) if ((*removeIterator)->name() == settingName)
{ {
const SettingContainer *setting = settings->value(settingName); if ((*removeIterator)->page() == pageName)
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue()); {
mSettings.erase (removeIterator);
break;
}
} }
removeIterator++;
} }
} }
QString CSMSettings::UserSettings::getSetting (const QString &section, const QString &setting) const
{
SettingMap *settings = getValidSettings(section);
QString retVal = ""; CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const
{
SettingPageMap pageMap;
if (settings->find(setting) != settings->end()) foreach (Setting *setting, mSettings)
retVal = settings->value(setting)->getValue(); pageMap[setting->page()].append (setting);
return retVal; return pageMap;
} }
CSMSettings::UserSettings& CSMSettings::UserSettings::instance() CSMSettings::Setting *CSMSettings::UserSettings::createSetting
(CSMSettings::SettingType typ, const QString &page, const QString &name)
{ {
assert(mUserSettingsInstance); //get list of all settings for the current setting name
return *mUserSettingsInstance; if (findSetting (page, name))
} {
qWarning() << "Duplicate declaration encountered: "
<< (name + '/' + page);
return 0;
}
void CSMSettings::UserSettings::displayFileErrorMessage(const QString &message, bool isReadOnly) Setting *setting = new Setting (typ, name, page);
{
// 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();
}
CSMSettings::SettingMap *
CSMSettings::UserSettings::getValidSettings (const QString &sectionName) const
{
SettingMap *settings = 0;
//copy the default values for the entire section if it's not found //add declaration to the model
if (mSectionSettings.find(sectionName) == mSectionSettings.end()) mSettings.append (setting);
{
if (mEditorSettingDefaults.find(sectionName) != mEditorSettingDefaults.end())
settings = mEditorSettingDefaults.value (sectionName);
}
//otherwise, iterate the section's settings, looking for missing values and replacing them with defaults.
else
{
SettingMap *loadedSettings = mSectionSettings[sectionName];
SettingMap *defaultSettings = mEditorSettingDefaults[sectionName];
foreach (QString key, defaultSettings->uniqueKeys()) return setting;
{ }
//write the default value to the loaded settings
if (loadedSettings->find((key))==loadedSettings->end())
loadedSettings->insert(key, defaultSettings->value(key));
}
settings = mSectionSettings.value (sectionName); QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const
} {
if (mSettingDefinitions->contains (viewKey))
return mSettingDefinitions->value (viewKey).toStringList();
return settings; return QStringList();
} }

@ -1,13 +1,12 @@
#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 "support.hpp"
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
@ -18,77 +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 {
struct UserSettings: public QObject class Setting;
typedef QMap <QString, QList <Setting *> > SettingPageMap;
class UserSettings: public QObject
{ {
Q_OBJECT Q_OBJECT
SectionMap mSectionSettings;
SectionMap mEditorSettingDefaults;
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(QMap<QString, SettingList *> &sections);
/// Called from editor to trigger signal to update the specified setting.
/// If no setting name is specified, all settings found in the specified section are updated.
void updateSettings (const QString &sectionName, const QString &settingName = "");
/// Retrieves the settings file at all three levels (global, local and user). /// Retrieves the settings file at all three levels (global, local and user).
/// \todo Multi-valued settings are not fully implemented. Setting values
/// \todo loaded in later files will always overwrite previously loaded values.
void loadSettings (const QString &fileName); void loadSettings (const QString &fileName);
/// Returns the entire map of settings across all sections /// Updates QSettings and syncs with the ini file
const SectionMap &getSectionMap () const; void setDefinitions (const QString &key, const QStringList &defs);
const SettingMap *getSettings (const QString &sectionName) const; QString settingValue (const QString &settingKey);
/// Retrieves the value as a QString of the specified setting in the specified section ///retrieve a setting object from a given page and setting name
QString getSetting(const QString &section, const QString &setting) const; Setting *findSetting
(const QString &pageName, const QString &settingName = QString());
private: ///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;
/// Opens a QTextStream from the provided path as read-only or read-write. ///Returns a string list of defined vlaues for the specified setting
QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const; ///in "page/name" format.
QStringList definitions (const QString &viewKey) const;
/// Parses a setting file specified in filePath from the provided text stream. ///Test to indicate whether or not a setting has any definitions
bool loadFromFile (const QString &filePath = ""); bool hasSettingDefinitions (const QString &viewKey) const;
/// merge the passed map into mSectionSettings ///Save any unsaved changes in the QSettings object
void mergeMap (const SectionMap &); void saveDefinitions() const;
void displayFileErrorMessage(const QString &message, bool isReadOnly); private:
void buildEditorSettingDefaults(); void buildSettingModelDefaults();
SettingMap *getValidSettings (const QString &sectionName) const; ///add a new setting to the model and return it
Setting *createSetting (CSMSettings::SettingType typ,
const QString &page, const QString &name);
signals: signals:
void signalUpdateEditorSetting (const QString &settingName, const QString &settingValue); 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;
} }
@ -681,146 +621,95 @@ void CSMTools::ReferenceableCheckStage::npcCheck(
} }
else else
{ {
if (npc.mNpdt52.mMana < 0)
{
messages.push_back(id.toString() + "|" + npc.mId + " mana has negative value");
}
if (npc.mNpdt52.mFatigue < 0)
{
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 +749,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 +767,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 +778,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 +794,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:

@ -18,8 +18,3 @@ void CSMWorld::Cell::load (ESM::ESMReader &esm)
mId = stream.str(); mId = stream.str();
} }
} }
void CSMWorld::Cell::addRef (const std::string& id)
{
mRefs.push_back (std::make_pair (id, false));
}

@ -1,7 +1,7 @@
#ifndef CSM_WOLRD_CELL_H #ifndef CSM_WOLRD_CELL_H
#define CSM_WOLRD_CELL_H #define CSM_WOLRD_CELL_H
#include <vector> #include <set>
#include <string> #include <string>
#include <components/esm/loadcell.hpp> #include <components/esm/loadcell.hpp>
@ -15,12 +15,12 @@ namespace CSMWorld
struct Cell : public ESM::Cell struct Cell : public ESM::Cell
{ {
std::string mId; std::string mId;
std::vector<std::pair<std::string, bool> > mRefs; // ID, modified
std::vector<std::string> mDeletedRefs;
void load (ESM::ESMReader &esm); /// These are the references modified by the edited content file. These are stored in
/// mModified only.
std::set<std::string> mTouchedRefs;
void addRef (const std::string& id); void load (ESM::ESMReader &esm);
}; };
} }

@ -10,6 +10,7 @@
#include "columnbase.hpp" #include "columnbase.hpp"
#include "columns.hpp" #include "columns.hpp"
#include "info.hpp" #include "info.hpp"
#include "cell.hpp"
namespace CSMWorld namespace CSMWorld
{ {
@ -87,6 +88,45 @@ namespace CSMWorld
} }
}; };
/// \brief Specialisation that takes care of the modified reference tracking
template<>
struct RecordStateColumn<Cell> : public Column<Cell>
{
RecordStateColumn<Cell>()
: Column<Cell> (Columns::ColumnId_Modification, ColumnBase::Display_RecordState)
{}
virtual QVariant get (const Record<Cell>& record) const
{
if (record.mState==Record<Cell>::State_Erased)
return static_cast<int> (Record<Cell>::State_Deleted);
if (!record.mModified.mTouchedRefs.empty() &&
!record.mState==Record<Cell>::State_Deleted &&
!record.mState==Record<Cell>::State_ModifiedOnly)
{
static_cast<int> (Record<Cell>::State_Modified);
}
return static_cast<int> (record.mState);
}
virtual void set (Record<Cell>& record, const QVariant& data)
{
record.mState = static_cast<RecordBase::State> (data.toInt());
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT> template<typename ESXRecordT>
struct FixedRecordTypeColumn : public Column<ESXRecordT> struct FixedRecordTypeColumn : public Column<ESXRecordT>
{ {

@ -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,171 @@ 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;
mRefLoadCache.clear();
/// \todo set encoding properly, once config implementation has been fixed. mReader = new ESM::ESMReader;
ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252")); mReader->setEncoder (&mEncoder);
reader.setEncoder (&encoder); mReader->open (path.string());
reader.open (path.string()); mBase = base;
mProject = project;
const ESM::Dialogue *dialogue = 0; mAuthor = mReader->getAuthor();
mDescription = mReader->getDesc();
mAuthor = reader.getAuthor(); return mReader->getRecordCount();
mDescription = reader.getDesc(); }
// Note: We do not need to send update signals here, because at this point the model is not connected bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
// to any view. {
while (reader.hasMoreRecs()) if (!mReader)
throw std::logic_error ("can't continue loading, because no load has been started");
if (!mReader->hasMoreRecs())
{ {
ESM::NAME n = reader.getRecName(); delete mReader;
reader.getRecHeader(); mReader = 0;
mDialogue = 0;
mRefLoadCache.clear();
return true;
}
switch (n.val) ESM::NAME n = mReader->getRecName();
mReader->getRecHeader();
switch (n.val)
{
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break;
case ESM::REC_SKIL: mSkills.load (*mReader, mBase); break;
case ESM::REC_CLAS: mClasses.load (*mReader, mBase); break;
case ESM::REC_FACT: mFactions.load (*mReader, mBase); break;
case ESM::REC_RACE: mRaces.load (*mReader, mBase); break;
case ESM::REC_SOUN: mSounds.load (*mReader, mBase); break;
case ESM::REC_SCPT: mScripts.load (*mReader, mBase); break;
case ESM::REC_REGN: mRegions.load (*mReader, mBase); break;
case ESM::REC_BSGN: mBirthsigns.load (*mReader, mBase); break;
case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break;
case ESM::REC_CELL:
{ {
case ESM::REC_GLOB: mGlobals.load (reader, base); break; mCells.load (*mReader, mBase);
case ESM::REC_GMST: mGmsts.load (reader, base); break; std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1));
case ESM::REC_SKIL: mSkills.load (reader, base); break; mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages);
case ESM::REC_CLAS: mClasses.load (reader, base); break; break;
case ESM::REC_FACT: mFactions.load (reader, base); break; }
case ESM::REC_RACE: mRaces.load (reader, base); break;
case ESM::REC_SOUN: mSounds.load (reader, base); break;
case ESM::REC_SCPT: mScripts.load (reader, base); break;
case ESM::REC_REGN: mRegions.load (reader, base); break;
case ESM::REC_BSGN: mBirthsigns.load (reader, base); break;
case ESM::REC_SPEL: mSpells.load (reader, base); break;
case ESM::REC_CELL:
mCells.load (reader, base);
mRefs.load (reader, mCells.getSize()-1, base);
break;
case ESM::REC_ACTI: mReferenceables.load (reader, base, UniversalId::Type_Activator); break; case ESM::REC_ACTI: mReferenceables.load (*mReader, mBase, UniversalId::Type_Activator); break;
case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break; case ESM::REC_ALCH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Potion); break;
case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break; case ESM::REC_APPA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Apparatus); break;
case ESM::REC_ARMO: mReferenceables.load (reader, base, UniversalId::Type_Armor); break; case ESM::REC_ARMO: mReferenceables.load (*mReader, mBase, UniversalId::Type_Armor); break;
case ESM::REC_BOOK: mReferenceables.load (reader, base, UniversalId::Type_Book); break; case ESM::REC_BOOK: mReferenceables.load (*mReader, mBase, UniversalId::Type_Book); break;
case ESM::REC_CLOT: mReferenceables.load (reader, base, UniversalId::Type_Clothing); break; case ESM::REC_CLOT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Clothing); break;
case ESM::REC_CONT: mReferenceables.load (reader, base, UniversalId::Type_Container); break; case ESM::REC_CONT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Container); break;
case ESM::REC_CREA: mReferenceables.load (reader, base, UniversalId::Type_Creature); break; case ESM::REC_CREA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Creature); break;
case ESM::REC_DOOR: mReferenceables.load (reader, base, UniversalId::Type_Door); break; case ESM::REC_DOOR: mReferenceables.load (*mReader, mBase, UniversalId::Type_Door); break;
case ESM::REC_INGR: mReferenceables.load (reader, base, UniversalId::Type_Ingredient); break; case ESM::REC_INGR: mReferenceables.load (*mReader, mBase, UniversalId::Type_Ingredient); break;
case ESM::REC_LEVC: case ESM::REC_LEVC:
mReferenceables.load (reader, base, UniversalId::Type_CreatureLevelledList); break; mReferenceables.load (*mReader, mBase, UniversalId::Type_CreatureLevelledList); break;
case ESM::REC_LEVI: case ESM::REC_LEVI:
mReferenceables.load (reader, base, UniversalId::Type_ItemLevelledList); break; mReferenceables.load (*mReader, mBase, UniversalId::Type_ItemLevelledList); break;
case ESM::REC_LIGH: mReferenceables.load (reader, base, UniversalId::Type_Light); break; case ESM::REC_LIGH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Light); break;
case ESM::REC_LOCK: mReferenceables.load (reader, base, UniversalId::Type_Lockpick); break; case ESM::REC_LOCK: mReferenceables.load (*mReader, mBase, UniversalId::Type_Lockpick); break;
case ESM::REC_MISC: case ESM::REC_MISC:
mReferenceables.load (reader, base, UniversalId::Type_Miscellaneous); break; mReferenceables.load (*mReader, mBase, UniversalId::Type_Miscellaneous); break;
case ESM::REC_NPC_: mReferenceables.load (reader, base, UniversalId::Type_Npc); break; case ESM::REC_NPC_: mReferenceables.load (*mReader, mBase, UniversalId::Type_Npc); break;
case ESM::REC_PROB: mReferenceables.load (reader, base, UniversalId::Type_Probe); break; case ESM::REC_PROB: mReferenceables.load (*mReader, mBase, UniversalId::Type_Probe); break;
case ESM::REC_REPA: mReferenceables.load (reader, base, UniversalId::Type_Repair); break; case ESM::REC_REPA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Repair); break;
case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break; case ESM::REC_STAT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Static); break;
case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break; case ESM::REC_WEAP: mReferenceables.load (*mReader, mBase, UniversalId::Type_Weapon); break;
case ESM::REC_DIAL: case ESM::REC_DIAL:
{ {
std::string id = reader.getHNOString ("NAME"); std::string id = mReader->getHNOString ("NAME");
ESM::Dialogue record; ESM::Dialogue record;
record.mId = id; record.mId = id;
record.load (reader); record.load (*mReader);
if (record.mType==ESM::Dialogue::Journal) if (record.mType==ESM::Dialogue::Journal)
{
mJournals.load (record, mBase);
mDialogue = &mJournals.getRecord (id).get();
}
else if (record.mType==ESM::Dialogue::Deleted)
{
mDialogue = 0; // record vector can be shuffled around which would make pointer
// to record invalid
if (mJournals.tryDelete (id))
{ {
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,11 @@ 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;
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
// not implemented // not implemented
Data (const Data&); Data (const Data&);
@ -78,7 +94,7 @@ namespace CSMWorld
public: public:
Data(); Data (ToUTF8::FromType encoding);
virtual ~Data(); virtual ~Data();
@ -167,10 +183,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,12 +1,10 @@
#include "ref.hpp" #include "ref.hpp"
#include "cell.hpp" CSMWorld::CellRef::CellRef()
void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string& id)
{ {
mId = id; mRefNum.mIndex = 0;
mCell = cell.mId;
cell.addRef (mId); // special marker: This reference does not have a RefNum assign to it yet.
mRefNum.mContentFile = -2;
} }

@ -3,11 +3,6 @@
#include <components/esm/cellref.hpp> #include <components/esm/cellref.hpp>
namespace ESM
{
class ESMReader;
}
namespace CSMWorld namespace CSMWorld
{ {
class Cell; class Cell;
@ -18,8 +13,7 @@ namespace CSMWorld
std::string mId; std::string mId;
std::string mCell; std::string mCell;
void load (ESM::ESMReader &esm, Cell& cell, const std::string& id); CellRef();
///< Load cell ref and register it with \a cell.
}; };
} }

@ -3,12 +3,15 @@
#include <sstream> #include <sstream>
#include <components/misc/stringops.hpp>
#include "ref.hpp" #include "ref.hpp"
#include "cell.hpp" #include "cell.hpp"
#include "universalid.hpp" #include "universalid.hpp"
#include "record.hpp" #include "record.hpp"
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base) void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base,
std::map<ESM::RefNum, std::string>& cache, CSMDoc::Stage::Messages& messages)
{ {
Record<Cell> cell = mCells.getRecord (cellIndex); Record<Cell> cell = mCells.getRecord (cellIndex);
@ -17,19 +20,79 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
CellRef ref; CellRef ref;
bool deleted = false; bool deleted = false;
while (cell2.getNextRef (reader, ref, deleted))
while (ESM::Cell::getNextRef (reader, ref, deleted))
{ {
/// \todo handle deleted and moved references ref.mCell = cell2.mId;
ref.load (reader, cell2, getNewId());
Record<CellRef> record2; /// \todo handle moved references
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
(base ? record2.mBase : record2.mModified) = ref;
appendRecord (record2); std::map<ESM::RefNum, std::string>::iterator iter = cache.find (ref.mRefNum);
}
if (deleted)
{
if (iter==cache.end())
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell,
mCells.getId (cellIndex));
messages.push_back (std::make_pair (id,
"Attempt to delete a non-existing reference"));
continue;
}
int index = getIndex (iter->second);
Record<CellRef> record = getRecord (index);
if (record.mState==RecordBase::State_BaseOnly)
{
removeRows (index, 1);
cache.erase (iter);
}
else
{
cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase (
mCells.getId (cellIndex)));
record.mState = RecordBase::State_Deleted;
setRecord (index, record);
}
continue;
}
mCells.setRecord (cellIndex, cell); if (!base)
cell.mModified.mTouchedRefs.insert (Misc::StringUtils::lowerCase (
mCells.getId (cellIndex)));
if (iter==cache.end())
{
// new reference
ref.mId = getNewId();
Record<CellRef> record;
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
(base ? record.mBase : record.mModified) = ref;
appendRecord (record);
cache.insert (std::make_pair (ref.mRefNum, ref.mId));
}
else
{
// old reference -> merge
ref.mId = iter->second;
int index = getIndex (ref.mId);
Record<CellRef> record = getRecord (index);
record.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_Modified;
(base ? record.mBase : record.mModified) = ref;
setRecord (index, record);
}
}
} }
std::string CSMWorld::RefCollection::getNewId() std::string CSMWorld::RefCollection::getNewId()
@ -38,14 +101,3 @@ std::string CSMWorld::RefCollection::getNewId()
stream << "ref#" << mNextId++; stream << "ref#" << mNextId++;
return stream.str(); return stream.str();
} }
void CSMWorld::RefCollection::cloneRecord(const std::string& origin,
const std::string& destination,
const CSMWorld::UniversalId::Type type,
const CSMWorld::UniversalId::ArgumentType argumentType)
{
Record<CSMWorld::CellRef> clone(getRecord(origin));
clone.mState = CSMWorld::RecordBase::State_ModifiedOnly;
clone.get().mId = destination;
insertRecord(clone, getAppendIndex(destination, type), type);
}

@ -1,6 +1,10 @@
#ifndef CSM_WOLRD_REFCOLLECTION_H #ifndef CSM_WOLRD_REFCOLLECTION_H
#define CSM_WOLRD_REFCOLLECTION_H #define CSM_WOLRD_REFCOLLECTION_H
#include <map>
#include "../doc/stage.hpp"
#include "collection.hpp" #include "collection.hpp"
#include "ref.hpp" #include "ref.hpp"
#include "record.hpp" #include "record.hpp"
@ -22,15 +26,12 @@ namespace CSMWorld
: mCells (cells), mNextId (0) : mCells (cells), mNextId (0)
{} {}
void load (ESM::ESMReader& reader, int cellIndex, bool base); void load (ESM::ESMReader& reader, int cellIndex, bool base,
std::map<ESM::RefNum, std::string>& cache,
CSMDoc::Stage::Messages& messages);
///< Load a sequence of references. ///< Load a sequence of references.
std::string getNewId(); std::string getNewId();
void cloneRecord(const std::string& origin,
const std::string& destination,
const CSMWorld::UniversalId::Type type,
const CSMWorld::UniversalId::ArgumentType argumentType);
}; };
} }

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

@ -12,16 +12,15 @@ CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const
return mUniversalId; return mUniversalId;
} }
void CSVDoc::SubView::updateEditorSetting (const QString &settingName, const QString &settingValue)
{
}
void CSVDoc::SubView::setStatusBar (bool show) {} void CSVDoc::SubView::setStatusBar (bool show) {}
void CSVDoc::SubView::useHint (const std::string& hint) {} void CSVDoc::SubView::useHint (const std::string& hint) {}
void CSVDoc::SubView::updateUserSetting (const QString &, const QStringList &)
{}
void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id)
{ {
mUniversalId = id; mUniversalId = id;
setWindowTitle (mUniversalId.toString().c_str()); setWindowTitle (mUniversalId.toString().c_str());
} }

@ -37,7 +37,6 @@ namespace CSVDoc
CSMWorld::UniversalId getUniversalId() const; CSMWorld::UniversalId getUniversalId() const;
virtual void setEditLock (bool locked) = 0; virtual void setEditLock (bool locked) = 0;
virtual void updateEditorSetting (const QString &, const QString &);
virtual void setStatusBar (bool show); virtual void setStatusBar (bool show);
///< Default implementation: ignored ///< Default implementation: ignored
@ -48,6 +47,10 @@ namespace CSVDoc
signals: signals:
void focusId (const CSMWorld::UniversalId& universalId, const std::string& hint); void focusId (const CSMWorld::UniversalId& universalId, const std::string& hint);
public slots:
virtual void updateUserSetting
(const QString &, const QStringList &);
}; };
} }

@ -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 "../settings/usersettingsdialog.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);
@ -235,8 +242,11 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
: mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1),
mViewTotal (totalViews) mViewTotal (totalViews)
{ {
QString width = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Width")); QString width = CSMSettings::UserSettings::instance().settingValue
QString height = CSMSettings::UserSettings::instance().getSetting(QString("Window Size"), QString("Height")); ("Window Size/Width");
QString height = CSMSettings::UserSettings::instance().settingValue
("Window Size/Height");
resize (width.toInt(), height.toInt()); resize (width.toInt(), height.toInt());
@ -336,7 +346,10 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this, connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this,
SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&))); SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&)));
CSMSettings::UserSettings::instance().updateSettings("Display Format"); connect (&CSMSettings::UserSettings::instance(),
SIGNAL (userSettingUpdated (const QString &, const QStringList &)),
view,
SLOT (updateUserSetting (const QString &, const QStringList &)));
view->show(); view->show();
} }
@ -484,25 +497,9 @@ void CSVDoc::View::resizeViewHeight (int height)
resize (geometry().width(), height); resize (geometry().width(), height);
} }
void CSVDoc::View::updateEditorSetting (const QString &settingName, const QString &settingValue) void CSVDoc::View::updateUserSetting
{ (const QString &name, const QStringList &list)
if ( (settingName == "Record Status Display") || (settingName == "Referenceable ID Type Display") ) {}
{
foreach (QObject *view, mSubViewWindow.children())
{
// not all mSubviewWindow children are CSVDoc::Subview objects
CSVDoc::SubView *subview = dynamic_cast<CSVDoc::SubView *>(view);
if (subview)
subview->updateEditorSetting (settingName, settingValue);
}
}
else if (settingName == "Width")
resizeViewWidth (settingValue.toInt());
else if (settingName == "Height")
resizeViewHeight (settingValue.toInt());
}
void CSVDoc::View::toggleShowStatusBar (bool show) void CSVDoc::View::toggleShowStatusBar (bool show)
{ {
@ -512,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));
}

@ -126,6 +126,8 @@ namespace CSVDoc
void abortOperation (int type); void abortOperation (int type);
void updateUserSetting (const QString &, const QStringList &);
private slots: private slots:
void newView(); void newView();
@ -177,6 +179,8 @@ namespace CSVDoc
void addJournalInfosSubView(); void addJournalInfosSubView();
void toggleShowStatusBar (bool show); void toggleShowStatusBar (bool show);
void loadErrorLog();
}; };
} }

@ -15,7 +15,8 @@
#include "../world/vartypedelegate.hpp" #include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp" #include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp" #include "../world/idtypedelegate.hpp"
#include "../settings/usersettingsdialog.hpp"
#include "../../model/settings/usersettings.hpp"
#include "view.hpp" #include "view.hpp"
@ -84,8 +85,32 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
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 (&CSMSettings::UserSettings::instance(), SIGNAL (signalUpdateEditorSetting (const QString &, const QString &)), connect (&mDocumentManager, SIGNAL (loadRequest (CSMDoc::Document *)),
this, SLOT (slotUpdateEditorSetting (const QString &, const QString &))); &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()
@ -119,6 +144,11 @@ CSVDoc::View *CSVDoc::ViewManager::addView (CSMDoc::Document *document)
connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest())); connect (view, SIGNAL (loadDocumentRequest ()), this, SIGNAL (loadDocumentRequest()));
connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest())); connect (view, SIGNAL (editSettingsRequest()), this, SIGNAL (editSettingsRequest()));
connect (&CSMSettings::UserSettings::instance(),
SIGNAL (userSettingUpdated(const QString &, const QStringList &)),
view,
SLOT (updateUserSetting (const QString &, const QStringList &)));
updateIndices(); updateIndices();
return view; return view;
@ -313,9 +343,3 @@ void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
if (notifySaveOnClose (view)) if (notifySaveOnClose (view))
QApplication::instance()->exit(); QApplication::instance()->exit();
} }
void CSVDoc::ViewManager::slotUpdateEditorSetting (const QString &settingName, const QString &settingValue)
{
foreach (CSVDoc::View *view, mViews)
view->updateEditorSetting (settingName, settingValue);
}

@ -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&);
@ -76,9 +79,6 @@ namespace CSVDoc
void progress (int current, int max, int type, int threads, CSMDoc::Document *document); void progress (int current, int max, int type, int threads, CSMDoc::Document *document);
void onExitWarningHandler(int state, CSMDoc::Document* document); void onExitWarningHandler(int state, CSMDoc::Document* document);
/// connected to update signal in UserSettings
void slotUpdateEditorSetting (const QString &, const QString &);
}; };
} }

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

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

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

Loading…
Cancel
Save