1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-27 03:35:27 +00:00

Merge branch 'dialog-fix' into NonTableFields

This commit is contained in:
Marek Kochanowicz 2014-06-17 11:49:35 +02:00
commit 187fccc8cc
639 changed files with 16975 additions and 10819 deletions

View File

@ -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)
@ -102,13 +90,13 @@ endif(UNIX AND NOT APPLE)
# Location of morrowind data files # Location of morrowind data files
if (APPLE) if (APPLE)
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
set(MORROWIND_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files")
elseif(UNIX) elseif(UNIX)
set(MORROWIND_DATA_FILES "/usr/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") set(MORROWIND_DATA_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/data/" CACHE PATH "location of Morrowind data files")
set(MORROWIND_RESOURCE_FILES "/usr/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") set(OPENMW_RESOURCE_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files")
else() else()
set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files")
set(MORROWIND_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files")
endif(APPLE) endif(APPLE)
if (WIN32) if (WIN32)
@ -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)
@ -268,16 +239,40 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED) find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED) find_package(Bullet REQUIRED)
IF(OGRE_STATIC)
find_package(Cg) set(OGRE_PLUGIN_INCLUDE_DIRS "")
IF(WIN32) set(OGRE_STATIC_PLUGINS "")
set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_Direct3D9_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS})
ELSE(WIN32) macro(add_static_ogre_plugin PLUGIN)
set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS}) if(OGRE_${PLUGIN}_FOUND)
ENDIF(WIN32) # strip RenderSystem_ or Plugin_ prefix from plugin name
ENDIF(OGRE_STATIC) string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN})
string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP})
add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME})
list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS})
list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES})
endif(OGRE_${PLUGIN}_FOUND)
endmacro(add_static_ogre_plugin)
if(OGRE_STATIC)
# set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS
add_static_ogre_plugin(Plugin_OctreeSceneManager)
add_static_ogre_plugin(Plugin_ParticleFX)
find_package(Cg)
if(Cg_FOUND)
add_static_ogre_plugin(Plugin_CgProgramManager)
list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES})
endif(Cg_FOUND)
add_static_ogre_plugin(RenderSystem_GL)
if(WIN32)
add_static_ogre_plugin(RenderSystem_Direct3D9)
endif(WIN32)
endif(OGRE_STATIC)
include_directories("." include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS}
${SDL2_INCLUDE_DIR} ${SDL2_INCLUDE_DIR}
${Boost_INCLUDE_DIR} ${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR}
@ -289,6 +284,10 @@ include_directories("."
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
if(MYGUI_STATIC)
add_definitions(-DMYGUI_STATIC)
endif (MYGUI_STATIC)
if (APPLE) if (APPLE)
# List used Ogre plugins # List used Ogre plugins
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
@ -368,8 +367,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 +433,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 +449,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 +478,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 +616,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 +633,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 +643,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 +700,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})

View File

@ -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(),

View File

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

View File

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

View File

@ -94,15 +94,6 @@ if(NOT WIN32)
endif(NOT WIN32) endif(NOT WIN32)
# Main executable # Main executable
IF(OGRE_STATIC)
IF(WIN32)
ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL)
set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES})
ELSE(WIN32)
ADD_DEFINITIONS(-DENABLE_PLUGIN_GL)
set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_GL_LIBRARIES})
ENDIF(WIN32)
ENDIF(OGRE_STATIC)
add_executable(omwlauncher add_executable(omwlauncher
${GUI_TYPE} ${GUI_TYPE}
${LAUNCHER} ${LAUNCHER}
@ -116,7 +107,7 @@ target_link_libraries(omwlauncher
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
${SDL2_LIBRARY} ${SDL2_LIBRARY_ONLY}
${QT_LIBRARIES} ${QT_LIBRARIES}
components components
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc
opencs_units (model/world opencs_units (model/world
idtable idtableproxymodel regionmap data idtable idtableproxymodel regionmap data commanddispatcher
) )
@ -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)
@ -192,6 +192,7 @@ endif(APPLE)
target_link_libraries(opencs target_link_libraries(opencs
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES} ${SHINY_LIBRARIES}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${QT_LIBRARIES} ${QT_LIBRARIES}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,6 +6,8 @@
#include <QTimer> #include <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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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; namespace CSMSettings
class QListWidgetItem; {
///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
*/
Type_CheckBox = 0,
Type_RadioButton = 1,
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
};
}
namespace CSVSettings
{
///Categorical view types which encompass the setting widget types
enum ViewType
{
ViewType_Boolean = 0,
ViewType_List = 1,
ViewType_Range = 2,
ViewType_Text = 3,
ViewType_Undefined = 4
};
}
namespace CSMSettings namespace CSMSettings
{ {
class SettingContainer; ///used to construct default settings in the Setting class
struct PropertyDefaultValues
typedef QList<SettingContainer *> SettingList;
typedef QMap<QString, SettingContainer *> SettingMap;
typedef QMap<QString, SettingMap *> SectionMap;
struct QStringPair
{ {
QStringPair(): left (""), right ("") int id;
{} QString name;
QVariant value;
};
QStringPair (const QString &leftValue, const QString &rightValue) ///strings which correspond to setting values. These strings represent
: left (leftValue), right(rightValue) ///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"
};
QStringPair (const QStringPair &pair) ///Default values for a setting. Used in setting creation.
: left (pair.left), right (pair.right) const QString sPropertyDefaults[] =
{} {
"", //name
QString left; "", //page
QString right; "40", //setting type
"false", //multivalue
bool isEmpty() const "false", //multiline
{ return (left.isEmpty() && right.isEmpty()); } "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

View File

@ -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,43 +28,250 @@ 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");
preDefined->setDeclaredValues (QStringList() << "640 x 480"
<< "800 x 600" << "1024 x 768" << "1440 x 900");
preDefined->setViewLocation (1, 1);
preDefined->setWidgetWidth (10);
preDefined->setColumnSpan (2);
preDefined->addProxy (width,
QStringList() << "640" << "800" << "1024" << "1440"
);
preDefined->addProxy (height,
QStringList() << "480" << "600" << "768" << "900"
);
}
section = "Display Format";
{
QString defaultValue = "Icon and Text";
QStringList values = QStringList()
<< defaultValue << "Icon Only" << "Text Only";
Setting *rsd = createSetting (Type_RadioButton,
section, "Record Status Display");
Setting *ritd = createSetting (Type_RadioButton,
section, "Referenceable ID Type Display");
rsd->setDeclaredValues (values);
ritd->setDeclaredValues (values);
rsd->setEditorSetting (true);
ritd->setEditorSetting (true);
}
section = "Proxy Selection Test";
{
/******************************************************************
* 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);
*/
}
} }
CSMSettings::UserSettings::~UserSettings() CSMSettings::UserSettings::~UserSettings()
@ -76,230 +279,62 @@ CSMSettings::UserSettings::~UserSettings()
mUserSettingsInstance = 0; mUserSettingsInstance = 0;
} }
QTextStream *CSMSettings::UserSettings::openFileStream (const QString &filePath, bool isReadOnly) const
{
QIODevice::OpenMode openFlags = QIODevice::Text;
if (isReadOnly)
openFlags = QIODevice::ReadOnly | openFlags;
else
openFlags = QIODevice::ReadWrite | QIODevice::Truncate | openFlags;
QFile *file = new QFile(filePath);
QTextStream *stream = 0;
if (file->open(openFlags))
{
stream = new QTextStream(file);
stream->setCodec(QTextCodec::codecForName("UTF-8"));
}
return stream;
}
bool CSMSettings::UserSettings::writeSettings(QMap<QString, CSMSettings::SettingList *> &settings)
{
QTextStream *stream = openFileStream(mUserFilePath);
bool success = (stream);
if (success)
{
QList<QString> keyList = settings.keys();
foreach (QString key, keyList)
{
SettingList *sectionSettings = settings[key];
*stream << "[" << key << "]" << '\n';
foreach (SettingContainer *item, *sectionSettings)
*stream << item->objectName() << " = " << item->getValue() << '\n';
}
stream->device()->close();
delete stream;
stream = 0;
}
else
{
displayFileErrorMessage(mReadWriteMessage, false);
}
return (success);
}
const CSMSettings::SectionMap &CSMSettings::UserSettings::getSectionMap() const
{
return mSectionSettings;
}
const CSMSettings::SettingMap *CSMSettings::UserSettings::getSettings(const QString &sectionName) const
{
return getValidSettings(sectionName);
}
bool CSMSettings::UserSettings::loadFromFile(const QString &filePath)
{
if (filePath.isEmpty())
return false;
SectionMap loadedSettings;
QTextStream *stream = openFileStream (filePath, true);
bool success = (stream);
if (success)
{
//looks for a square bracket, "'\\["
//that has one or more "not nothing" in it, "([^]]+)"
//and is closed with a square bracket, "\\]"
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;
QString section = "none";
while (!stream->atEnd())
{
QString line = stream->readLine().simplified();
if (line.isEmpty() || line.startsWith("#"))
continue;
//if a section is found, push it onto a new QStringList
//and push the QStringList onto
if (sectionRe.exactMatch(line))
{
//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)
{
SettingContainer *sc = new SettingContainer (keyRe.cap(2).simplified());
sc->setObjectName(keyRe.cap(1).simplified());
(*settings)[keyRe.cap(1).simplified()] = sc;
}
}
loadedSettings.insert(section, settings);
stream->device()->close();
delete stream;
stream = 0;
}
mergeMap (loadedSettings);
return success;
}
void CSMSettings::UserSettings::mergeMap (const CSMSettings::SectionMap &sectionSettings)
{
foreach (QString key, sectionSettings.uniqueKeys())
{
// 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::loadSettings (const QString &fileName)
{ {
mSectionSettings.clear(); QString userFilePath = QString::fromUtf8
(mCfgMgr.getUserConfigPath().string().c_str());
//global QString globalFilePath = QString::fromUtf8
QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName; (mCfgMgr.getGlobalPath().string().c_str());
bool globalOk = loadFromFile(globalFilePath);
QString otherFilePath = globalFilePath;
//local //test for local only if global fails (uninstalled copy)
QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName; if (!QFile (globalFilePath + fileName).exists())
bool localOk = loadFromFile(localFilePath);
//user
mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName;
loadFromFile(mUserFilePath);
if (!(localOk || globalOk))
{ {
QString message = QObject::tr("<br><b>Could not open user settings files for reading</b><br><br> \ //if global is invalid, use the local path
Global and local settings files could not be read.\ otherFilePath = QString::fromUtf8
You may have incorrect file permissions or the OpenCS installation may be corrupted.<br>"); (mCfgMgr.getLocalPath().string().c_str());
message += QObject::tr("<br>Global filepath: ") + globalFilePath;
message += QObject::tr("<br>Local filepath: ") + localFilePath;
displayFileErrorMessage ( message, true);
} }
QSettings::setPath
(QSettings::IniFormat, QSettings::UserScope, userFilePath);
QSettings::setPath
(QSettings::IniFormat, QSettings::SystemScope, otherFilePath);
mSettingDefinitions = new QSettings
(QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this);
} }
void CSMSettings::UserSettings::updateSettings (const QString &sectionName, const QString &settingName) bool CSMSettings::UserSettings::hasSettingDefinitions
(const QString &viewKey) const
{ {
return (mSettingDefinitions->contains (viewKey));
SettingMap *settings = getValidSettings(sectionName);
if (!settings)
return;
if (settingName.isEmpty())
{
foreach (const SettingContainer *setting, *settings)
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
else
{
if (settings->find(settingName) != settings->end())
{
const SettingContainer *setting = settings->value(settingName);
emit signalUpdateEditorSetting (setting->objectName(), setting->getValue());
}
}
} }
QString CSMSettings::UserSettings::getSetting (const QString &section, const QString &setting) const void CSMSettings::UserSettings::setDefinitions
(const QString &key, const QStringList &list)
{ {
SettingMap *settings = getValidSettings(section); mSettingDefinitions->setValue (key, list);
}
QString retVal = ""; void CSMSettings::UserSettings::saveDefinitions() const
{
mSettingDefinitions->sync();
}
if (settings->find(setting) != settings->end()) QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
retVal = settings->value(setting)->getValue(); {
if (!mSettingDefinitions->contains (settingKey))
return QString();
return retVal; QStringList defs = mSettingDefinitions->value (settingKey).toStringList();
if (defs.isEmpty())
return QString();
return defs.at(0);
} }
CSMSettings::UserSettings& CSMSettings::UserSettings::instance() CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
@ -308,48 +343,85 @@ CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
return *mUserSettingsInstance; return *mUserSettingsInstance;
} }
void CSMSettings::UserSettings::displayFileErrorMessage(const QString &message, bool isReadOnly) void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
const QStringList &list)
{ {
// File cannot be opened or created mSettingDefinitions->setValue (settingKey ,list);
QMessageBox msgBox;
msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
if (!isReadOnly) emit userSettingUpdated (settingKey, list);
msgBox.setText (mReadWriteMessage + message);
else
msgBox.setText (message);
msgBox.exec();
} }
CSMSettings::SettingMap * CSMSettings::Setting *CSMSettings::UserSettings::findSetting
CSMSettings::UserSettings::getValidSettings (const QString &sectionName) const (const QString &pageName, const QString &settingName)
{ {
SettingMap *settings = 0; foreach (Setting *setting, mSettings)
//copy the default values for the entire section if it's not found
if (mSectionSettings.find(sectionName) == mSectionSettings.end())
{ {
if (mEditorSettingDefaults.find(sectionName) != mEditorSettingDefaults.end()) if (setting->name() == settingName)
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())
{ {
//write the default value to the loaded settings if (setting->page() == pageName)
if (loadedSettings->find((key))==loadedSettings->end()) return setting;
loadedSettings->insert(key, defaultSettings->value(key));
} }
}
return 0;
}
settings = mSectionSettings.value (sectionName); void CSMSettings::UserSettings::removeSetting
(const QString &pageName, const QString &settingName)
{
if (mSettings.isEmpty())
return;
QList <Setting *>::iterator removeIterator = mSettings.begin();
while (removeIterator != mSettings.end())
{
if ((*removeIterator)->name() == settingName)
{
if ((*removeIterator)->page() == pageName)
{
mSettings.erase (removeIterator);
break;
}
}
removeIterator++;
}
}
CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const
{
SettingPageMap pageMap;
foreach (Setting *setting, mSettings)
pageMap[setting->page()].append (setting);
return pageMap;
}
CSMSettings::Setting *CSMSettings::UserSettings::createSetting
(CSMSettings::SettingType typ, const QString &page, const QString &name)
{
//get list of all settings for the current setting name
if (findSetting (page, name))
{
qWarning() << "Duplicate declaration encountered: "
<< (name + '/' + page);
return 0;
} }
return settings; Setting *setting = new Setting (typ, name, page);
//add declaration to the model
mSettings.append (setting);
return setting;
}
QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const
{
if (mSettingDefinitions->contains (viewKey))
return mSettingDefinitions->value (viewKey).toStringList();
return QStringList();
} }

View File

@ -1,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());
///remove a setting from the list
void removeSetting
(const QString &pageName, const QString &settingName);
///Retreive a map of the settings, keyed by page name
SettingPageMap settingPageMap() const;
///Returns a string list of defined vlaues for the specified setting
///in "page/name" format.
QStringList definitions (const QString &viewKey) const;
///Test to indicate whether or not a setting has any definitions
bool hasSettingDefinitions (const QString &viewKey) const;
///Save any unsaved changes in the QSettings object
void saveDefinitions() const;
private: private:
void buildSettingModelDefaults();
/// Opens a QTextStream from the provided path as read-only or read-write. ///add a new setting to the model and return it
QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const; Setting *createSetting (CSMSettings::SettingType typ,
const QString &page, const QString &name);
/// Parses a setting file specified in filePath from the provided text stream.
bool loadFromFile (const QString &filePath = "");
/// merge the passed map into mSectionSettings
void mergeMap (const SectionMap &);
void displayFileErrorMessage(const QString &message, bool isReadOnly);
void buildEditorSettingDefaults();
SettingMap *getValidSettings (const QString &sectionName) const;
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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
if (someItem.mModel.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has no model");
}
//checking for icon
if (someItem.mIcon.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has no icon");
}
if (enchantable)
{
if (someItem.mData.mEnchant < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative enchantment");
}
}
}
template<typename ITEM> void CSMTools::ReferenceableCheckStage::inventoryItemCheck(
const ITEM& someItem,
std::vector< std::string >& messages,
const std::string& someID)
{
if (someItem.mName.empty())
{
messages.push_back(someID + "|" + someItem.mId + " has an empty name");
}
//Checking for weight
if (someItem.mData.mWeight < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative weight");
}
//Checking for value
if (someItem.mData.mValue < 0)
{
messages.push_back(someID + "|" + someItem.mId + " has negative value");
}
//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 && someItem.mData.mEnchant < 0)
messages.push_back (std::make_pair (someID, someItem.mId + " has negative enchantment"));
} }
template<typename TOOL> void CSMTools::ReferenceableCheckStage::toolCheck( template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck (
const TOOL& someTool, const Item& someItem, Messages& messages, const std::string& someID)
std::vector< std::string >& messages, {
const std::string& someID, bool canBeBroken) if (someItem.mName.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name"));
//Checking for weight
if (someItem.mData.mWeight < 0)
messages.push_back (std::make_pair (someID, someItem.mId + " has negative weight"));
//Checking for value
if (someItem.mData.mValue < 0)
messages.push_back (std::make_pair (someID, someItem.mId + " has negative value"));
//checking for model
if (someItem.mModel.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has no model"));
//checking for icon
if (someItem.mIcon.empty())
messages.push_back (std::make_pair (someID, someItem.mId + " has no icon"));
}
template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck (
const Tool& someTool, Messages& messages, const std::string& someID, bool canBeBroken)
{ {
if (someTool.mData.mQuality <= 0) 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;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -45,8 +45,9 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (mVerifier, SIGNAL (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);
} }

View File

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

View File

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

View File

@ -15,12 +15,9 @@ 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); void load (ESM::ESMReader &esm);
void addRef (const std::string& id);
}; };
} }

View File

@ -86,6 +86,8 @@ namespace CSMWorld
virtual QVariant getData (int index, int column) const; virtual QVariant getData (int index, int column) const;
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const;
virtual void setData (int index, int column, const QVariant& data); virtual void setData (int index, int column, const QVariant& data);
virtual const ColumnBase& getColumn (int column) const; virtual const ColumnBase& getColumn (int column) const;
@ -295,6 +297,12 @@ namespace CSMWorld
return mColumns.at (column)->get (mRecords.at (index)); return mColumns.at (column)->get (mRecords.at (index));
} }
template<typename ESXRecordT, typename IdAccessorT>
QVariant Collection<ESXRecordT, IdAccessorT>::getNestedData(int row, int column, int subRow, int subColumn) const
{
return 10; //TODO
}
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>
void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data) void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data)
{ {

View File

@ -2,6 +2,7 @@
#include "collectionbase.hpp" #include "collectionbase.hpp"
#include <stdexcept> #include <stdexcept>
#include <cassert>
#include "columnbase.hpp" #include "columnbase.hpp"

View File

@ -48,6 +48,8 @@ namespace CSMWorld
virtual QVariant getData (int index, int column) const = 0; virtual QVariant getData (int index, int column) const = 0;
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const = 0;
virtual void setData (int index, int column, const QVariant& data) = 0; virtual void setData (int index, int column, const QVariant& data) = 0;
virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn);

View File

@ -89,7 +89,9 @@ namespace CSMWorld
Display_RefRecordType, Display_RefRecordType,
Display_DialogueType, Display_DialogueType,
Display_QuestStatusType, Display_QuestStatusType,
Display_Gender Display_Gender,
Display_Nested
}; };
int mColumnId; int mColumnId;
@ -125,6 +127,12 @@ namespace CSMWorld
throw std::logic_error ("Column " + getTitle() + " is not editable"); throw std::logic_error ("Column " + getTitle() + " is not editable");
} }
}; };
template<typename ESXRecordT>
struct NestedColumn
{
virtual QVariant getNested(const Record<ESXRecordT>& record, int subColumn, int subSow) const = 0;
};
} }
#endif #endif

View File

@ -167,6 +167,7 @@ namespace CSMWorld
ColumnId_PcRank = 154, ColumnId_PcRank = 154,
ColumnId_Scope = 155, ColumnId_Scope = 155,
ColumnId_ReferenceableId = 156, ColumnId_ReferenceableId = 156,
ColumnId_ContainerContent = 157,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.

View File

@ -0,0 +1,165 @@
#include "commanddispatcher.hpp"
#include "../doc/document.hpp"
#include "idtable.hpp"
#include "record.hpp"
#include "commands.hpp"
std::vector<std::string> CSMWorld::CommandDispatcher::getDeletableRecords() const
{
std::vector<std::string> result;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
int stateColumnIndex = model.findColumnIndex (Columns::ColumnId_Modification);
for (std::vector<std::string>::const_iterator iter (mSelection.begin());
iter!=mSelection.end(); ++iter)
{
int row = model.getModelIndex (*iter, 0).row();
// check record state
RecordBase::State state = static_cast<RecordBase::State> (
model.data (model.index (row, stateColumnIndex)).toInt());
if (state==RecordBase::State_Deleted)
continue;
// check other columns (only relevant for a subset of the tables)
int dialogueTypeIndex = model.searchColumnIndex (Columns::ColumnId_DialogueType);
if (dialogueTypeIndex!=-1)
{
int type = model.data (model.index (row, dialogueTypeIndex)).toInt();
if (type!=ESM::Dialogue::Topic && type!=ESM::Dialogue::Journal)
continue;
}
result.push_back (*iter);
}
return result;
}
std::vector<std::string> CSMWorld::CommandDispatcher::getRevertableRecords() const
{
std::vector<std::string> result;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
/// \todo Reverting temporarily disabled on tables that support reordering, because
/// revert logic currently can not handle reordering.
if (model.getFeatures() & IdTable::Feature_ReorderWithinTopic)
return result;
int stateColumnIndex = model.findColumnIndex (Columns::ColumnId_Modification);
for (std::vector<std::string>::const_iterator iter (mSelection.begin());
iter!=mSelection.end(); ++iter)
{
int row = model.getModelIndex (*iter, 0).row();
// check record state
RecordBase::State state = static_cast<RecordBase::State> (
model.data (model.index (row, stateColumnIndex)).toInt());
if (state==RecordBase::State_BaseOnly)
continue;
result.push_back (*iter);
}
return result;
}
CSMWorld::CommandDispatcher::CommandDispatcher (CSMDoc::Document& document,
const CSMWorld::UniversalId& id, QObject *parent)
: QObject (parent), mDocument (document), mId (id), mLocked (false)
{}
void CSMWorld::CommandDispatcher::setEditLock (bool locked)
{
mLocked = locked;
}
void CSMWorld::CommandDispatcher::setSelection (const std::vector<std::string>& selection)
{
mSelection = selection;
}
bool CSMWorld::CommandDispatcher::canDelete() const
{
if (mLocked)
return false;
return getDeletableRecords().size()!=0;
}
bool CSMWorld::CommandDispatcher::canRevert() const
{
if (mLocked)
return false;
return getRevertableRecords().size()!=0;
}
void CSMWorld::CommandDispatcher::executeDelete()
{
if (mLocked)
return;
std::vector<std::string> rows = getDeletableRecords();
if (rows.empty())
return;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
if (rows.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Delete multiple records"));
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
{
std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
toString().toUtf8().constData();
mDocument.getUndoStack().push (new CSMWorld::DeleteCommand (model, id));
}
if (rows.size()>1)
mDocument.getUndoStack().endMacro();
}
void CSMWorld::CommandDispatcher::executeRevert()
{
if (mLocked)
return;
std::vector<std::string> rows = getRevertableRecords();
if (rows.empty())
return;
IdTable& model = dynamic_cast<IdTable&> (*mDocument.getData().getTableModel (mId));
int columnIndex = model.findColumnIndex (Columns::ColumnId_Id);
if (rows.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Revert multiple records"));
for (std::vector<std::string>::const_iterator iter (rows.begin()); iter!=rows.end(); ++iter)
{
std::string id = model.data (model.getModelIndex (*iter, columnIndex)).
toString().toUtf8().constData();
mDocument.getUndoStack().push (new CSMWorld::RevertCommand (model, id));
}
if (rows.size()>1)
mDocument.getUndoStack().endMacro();
}

View File

@ -0,0 +1,53 @@
#ifndef CSM_WOLRD_COMMANDDISPATCHER_H
#define CSM_WOLRD_COMMANDDISPATCHER_H
#include <vector>
#include <QObject>
#include "universalid.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMWorld
{
class CommandDispatcher : public QObject
{
Q_OBJECT
bool mLocked;
CSMDoc::Document& mDocument;
UniversalId mId;
std::vector<std::string> mSelection;
std::vector<std::string> getDeletableRecords() const;
std::vector<std::string> getRevertableRecords() const;
public:
CommandDispatcher (CSMDoc::Document& document, const CSMWorld::UniversalId& id,
QObject *parent = 0);
///< \param id ID of the table the commands should operate on primarily.
void setEditLock (bool locked);
void setSelection (const std::vector<std::string>& selection);
bool canDelete() const;
bool canRevert() const;
public slots:
void executeDelete();
void executeRevert();
};
}
#endif

View File

@ -16,11 +16,12 @@
#include "regionmap.hpp" #include "regionmap.hpp"
#include "columns.hpp" #include "columns.hpp"
void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update)
UniversalId::Type type2, bool update)
{ {
mModels.push_back (model); mModels.push_back (model);
mModelIndex.insert (std::make_pair (type1, model)); mModelIndex.insert (std::make_pair (type, model));
UniversalId::Type type2 = UniversalId::getParentType (type);
if (type2!=UniversalId::Type_None) if (type2!=UniversalId::Type_None)
mModelIndex.insert (std::make_pair (type2, model)); mModelIndex.insert (std::make_pair (type2, model));
@ -55,7 +56,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>);
@ -234,32 +236,34 @@ CSMWorld::Data::Data() : mRefs (mCells)
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>); mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>); mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill, false); addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); addModel (new IdTable (&mClasses), UniversalId::Type_Class);
addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); addModel (new IdTable (&mFactions), UniversalId::Type_Faction);
addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); addModel (new IdTable (&mRaces), UniversalId::Type_Race);
addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); addModel (new IdTable (&mSounds), UniversalId::Type_Sound);
addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); addModel (new IdTable (&mScripts), UniversalId::Type_Script);
addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); addModel (new IdTable (&mRegions), UniversalId::Type_Region);
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsign);
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); addModel (new IdTable (&mSpells), UniversalId::Type_Spell);
addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic); addModel (new IdTable (&mTopics), UniversalId::Type_Topic);
addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal); addModel (new IdTable (&mJournals), UniversalId::Type_Journal);
addModel (new IdTable (&mTopicInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo); addModel (new IdTable (&mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo);
addModel (new IdTable (&mJournalInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo); addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo);
addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell); addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell);
addModel (new IdTable (&mReferenceables, IdTable::Reordering_None, IdTable::Viewing_None, true), addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview),
UniversalId::Type_Referenceables, UniversalId::Type_Referenceable); UniversalId::Type_Referenceable);
addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell, true), UniversalId::Type_References, UniversalId::Type_Reference, false); addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference);
addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false); addModel (new IdTable (&mFilters), UniversalId::Type_Filter);
} }
CSMWorld::Data::~Data() 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 +457,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());
@ -466,8 +470,7 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
if (id.getType()==UniversalId::Type_RegionMap) if (id.getType()==UniversalId::Type_RegionMap)
{ {
RegionMap *table = 0; RegionMap *table = 0;
addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, false);
UniversalId::Type_None, false);
return table; return table;
} }
throw std::logic_error ("No table model available for " + id.toString()); throw std::logic_error ("No table model available for " + id.toString());
@ -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;
switch (n.val) mRefLoadCache.clear();
{ return true;
case ESM::REC_GLOB: mGlobals.load (reader, base); break;
case ESM::REC_GMST: mGmsts.load (reader, base); break;
case ESM::REC_SKIL: mSkills.load (reader, base); break;
case ESM::REC_CLAS: mClasses.load (reader, base); break;
case ESM::REC_FACT: mFactions.load (reader, base); break;
case ESM::REC_RACE: mRaces.load (reader, base); break;
case ESM::REC_SOUN: mSounds.load (reader, base); break;
case ESM::REC_SCPT: mScripts.load (reader, base); break;
case ESM::REC_REGN: mRegions.load (reader, base); break;
case ESM::REC_BSGN: mBirthsigns.load (reader, base); break;
case ESM::REC_SPEL: mSpells.load (reader, base); break;
case ESM::REC_CELL:
mCells.load (reader, base);
mRefs.load (reader, mCells.getSize()-1, base);
break;
case ESM::REC_ACTI: mReferenceables.load (reader, base, UniversalId::Type_Activator); break;
case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break;
case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break;
case ESM::REC_ARMO: mReferenceables.load (reader, base, UniversalId::Type_Armor); break;
case ESM::REC_BOOK: mReferenceables.load (reader, base, UniversalId::Type_Book); break;
case ESM::REC_CLOT: mReferenceables.load (reader, base, UniversalId::Type_Clothing); break;
case ESM::REC_CONT: mReferenceables.load (reader, base, UniversalId::Type_Container); break;
case ESM::REC_CREA: mReferenceables.load (reader, base, UniversalId::Type_Creature); break;
case ESM::REC_DOOR: mReferenceables.load (reader, base, UniversalId::Type_Door); break;
case ESM::REC_INGR: mReferenceables.load (reader, base, UniversalId::Type_Ingredient); break;
case ESM::REC_LEVC:
mReferenceables.load (reader, base, UniversalId::Type_CreatureLevelledList); break;
case ESM::REC_LEVI:
mReferenceables.load (reader, base, UniversalId::Type_ItemLevelledList); break;
case ESM::REC_LIGH: mReferenceables.load (reader, base, UniversalId::Type_Light); break;
case ESM::REC_LOCK: mReferenceables.load (reader, base, UniversalId::Type_Lockpick); break;
case ESM::REC_MISC:
mReferenceables.load (reader, base, UniversalId::Type_Miscellaneous); break;
case ESM::REC_NPC_: mReferenceables.load (reader, base, UniversalId::Type_Npc); break;
case ESM::REC_PROB: mReferenceables.load (reader, base, UniversalId::Type_Probe); break;
case ESM::REC_REPA: mReferenceables.load (reader, base, UniversalId::Type_Repair); break;
case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break;
case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break;
case ESM::REC_DIAL:
{
std::string id = reader.getHNOString ("NAME");
ESM::Dialogue record;
record.mId = id;
record.load (reader);
if (record.mType==ESM::Dialogue::Journal)
{
mJournals.load (record, base);
dialogue = &mJournals.getRecord (id).get();
}
else if (record.mType==ESM::Dialogue::Deleted)
{
dialogue = 0; // record vector can be shuffled around which would make pointer
// to record invalid
if (mJournals.tryDelete (id))
{
/// \todo handle info records
}
else if (mTopics.tryDelete (id))
{
/// \todo handle info records
}
else
{
/// \todo report deletion of non-existing record
}
}
else
{
mTopics.load (record, base);
dialogue = &mTopics.getRecord (id).get();
}
break;
}
case ESM::REC_INFO:
{
if (!dialogue)
{
/// \todo INFO record without matching DIAL record -> report to user
reader.skipRecord();
break;
}
if (dialogue->mType==ESM::Dialogue::Journal)
mJournalInfos.load (reader, base, *dialogue);
else
mTopicInfos.load (reader, base, *dialogue);
break;
}
case ESM::REC_FILT:
if (project)
{
mFilters.load (reader, base);
mFilters.setData (mFilters.getSize()-1,
mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
static_cast<int> (CSMFilter::Filter::Scope_Project));
break;
}
// fall through (filter record in a content file is an error with format 0)
default:
/// \todo throw an exception instead, once all records are implemented
/// or maybe report error and continue?
reader.skipRecord();
}
} }
ESM::NAME n = mReader->getRecName();
mReader->getRecHeader();
switch (n.val)
{
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break;
case ESM::REC_SKIL: mSkills.load (*mReader, mBase); break;
case ESM::REC_CLAS: mClasses.load (*mReader, mBase); break;
case ESM::REC_FACT: mFactions.load (*mReader, mBase); break;
case ESM::REC_RACE: mRaces.load (*mReader, mBase); break;
case ESM::REC_SOUN: mSounds.load (*mReader, mBase); break;
case ESM::REC_SCPT: mScripts.load (*mReader, mBase); break;
case ESM::REC_REGN: mRegions.load (*mReader, mBase); break;
case ESM::REC_BSGN: mBirthsigns.load (*mReader, mBase); break;
case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break;
case ESM::REC_CELL:
{
mCells.load (*mReader, mBase);
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1));
mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages);
break;
}
case ESM::REC_ACTI: mReferenceables.load (*mReader, mBase, UniversalId::Type_Activator); break;
case ESM::REC_ALCH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Potion); break;
case ESM::REC_APPA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Apparatus); break;
case ESM::REC_ARMO: mReferenceables.load (*mReader, mBase, UniversalId::Type_Armor); break;
case ESM::REC_BOOK: mReferenceables.load (*mReader, mBase, UniversalId::Type_Book); break;
case ESM::REC_CLOT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Clothing); break;
case ESM::REC_CONT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Container); break;
case ESM::REC_CREA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Creature); break;
case ESM::REC_DOOR: mReferenceables.load (*mReader, mBase, UniversalId::Type_Door); break;
case ESM::REC_INGR: mReferenceables.load (*mReader, mBase, UniversalId::Type_Ingredient); break;
case ESM::REC_LEVC:
mReferenceables.load (*mReader, mBase, UniversalId::Type_CreatureLevelledList); break;
case ESM::REC_LEVI:
mReferenceables.load (*mReader, mBase, UniversalId::Type_ItemLevelledList); break;
case ESM::REC_LIGH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Light); break;
case ESM::REC_LOCK: mReferenceables.load (*mReader, mBase, UniversalId::Type_Lockpick); break;
case ESM::REC_MISC:
mReferenceables.load (*mReader, mBase, UniversalId::Type_Miscellaneous); break;
case ESM::REC_NPC_: mReferenceables.load (*mReader, mBase, UniversalId::Type_Npc); break;
case ESM::REC_PROB: mReferenceables.load (*mReader, mBase, UniversalId::Type_Probe); break;
case ESM::REC_REPA: mReferenceables.load (*mReader, mBase, UniversalId::Type_Repair); break;
case ESM::REC_STAT: mReferenceables.load (*mReader, mBase, UniversalId::Type_Static); break;
case ESM::REC_WEAP: mReferenceables.load (*mReader, mBase, UniversalId::Type_Weapon); break;
case ESM::REC_DIAL:
{
std::string id = mReader->getHNOString ("NAME");
ESM::Dialogue record;
record.mId = id;
record.load (*mReader);
if (record.mType==ESM::Dialogue::Journal)
{
mJournals.load (record, mBase);
mDialogue = &mJournals.getRecord (id).get();
}
else if (record.mType==ESM::Dialogue::Deleted)
{
mDialogue = 0; // record vector can be shuffled around which would make pointer
// to record invalid
if (mJournals.tryDelete (id))
{
/// \todo handle info records
}
else if (mTopics.tryDelete (id))
{
/// \todo handle info records
}
else
{
messages.push_back (std::make_pair (UniversalId::Type_None,
"Trying to delete dialogue record " + id + " which does not exist"));
}
}
else
{
mTopics.load (record, mBase);
mDialogue = &mTopics.getRecord (id).get();
}
break;
}
case ESM::REC_INFO:
{
if (!mDialogue)
{
messages.push_back (std::make_pair (UniversalId::Type_None,
"Found info record not following a dialogue record"));
mReader->skipRecord();
break;
}
if (mDialogue->mType==ESM::Dialogue::Journal)
mJournalInfos.load (*mReader, mBase, *mDialogue);
else
mTopicInfos.load (*mReader, mBase, *mDialogue);
break;
}
case ESM::REC_FILT:
if (mProject)
{
mFilters.load (*mReader, mBase);
mFilters.setData (mFilters.getSize()-1,
mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
static_cast<int> (CSMFilter::Filter::Scope_Project));
break;
}
// fall through (filter record in a content file is an error with format 0)
default:
messages.push_back (std::make_pair (UniversalId::Type_None,
"Unsupported record type: " + n.toString()));
mReader->skipRecord();
}
return false;
} }
bool CSMWorld::Data::hasId (const std::string& id) const bool CSMWorld::Data::hasId (const std::string& id) const

View File

@ -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,13 +73,18 @@ 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&);
Data& operator= (const Data&); Data& operator= (const Data&);
void addModel (QAbstractItemModel *model, UniversalId::Type type1, void addModel (QAbstractItemModel *model, UniversalId::Type type,
UniversalId::Type type2 = UniversalId::Type_None, bool update = true); bool update = true);
static void appendIds (std::vector<std::string>& ids, const CollectionBase& collection, static void appendIds (std::vector<std::string>& ids, const CollectionBase& collection,
bool listDeleted); bool listDeleted);
@ -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;

View File

@ -6,9 +6,8 @@
#include "collectionbase.hpp" #include "collectionbase.hpp"
#include "columnbase.hpp" #include "columnbase.hpp"
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering, CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
Viewing viewing, bool preview) : mIdCollection (idCollection), mFeatures (features)
: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing), mPreview (preview)
{} {}
CSMWorld::IdTable::~IdTable() CSMWorld::IdTable::~IdTable()
@ -18,10 +17,10 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const
{ {
if (hasChildren(parent)) if (hasChildren(parent))
{ {
int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column()); int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column());
return nestedRows; return nestedRows;
} }
return mIdCollection->getSize(); return mIdCollection->getSize();
} }
@ -29,7 +28,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const
{ {
if (parent.isValid()) if (parent.isValid())
{ {
return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); return mIdCollection->getNestedColumnsCount(parent.row(), parent.column());
} }
return mIdCollection->getColumns(); return mIdCollection->getColumns();
@ -46,7 +45,7 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
if (index.internalId() != 0) if (index.internalId() != 0)
{ {
std::pair<int, int> parentAdress(unfoldIndexAdress(index.internalId())); std::pair<int, int> parentAdress(unfoldIndexAdress(index.internalId()));
return mIdCollection->getNestedData(parentAdress.first, parentAdress.second, index.row(), index.column()); return mIdCollection->getNestedData(index.row(), index.column(), parentAdress.first, parentAdress.second);
} else { } else {
return mIdCollection->getData (index.row(), index.column()); return mIdCollection->getData (index.row(), index.column());
} }
@ -117,8 +116,11 @@ bool CSMWorld::IdTable::removeRows (int row, int count, const QModelIndex& paren
QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& parent) const
{ {
unsigned int encodedId = 0;
if (parent.isValid()) if (parent.isValid())
return QModelIndex(); {
encodedId = this->foldIndexAdress(parent);
}
if (row<0 || row>=mIdCollection->getSize()) if (row<0 || row>=mIdCollection->getSize())
return QModelIndex(); return QModelIndex();
@ -126,7 +128,7 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa
if (column<0 || column>=mIdCollection->getColumns()) if (column<0 || column>=mIdCollection->getColumns())
return QModelIndex(); return QModelIndex();
return createIndex (row, column); return createIndex(row, column, encodedId);
} }
QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const
@ -136,14 +138,14 @@ QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const
return QModelIndex(); return QModelIndex();
} }
const std::pair<int, int>& adress(unfoldIndexAdress(index.internalId())); unsigned int id = index.internalId();
const std::pair<int, int>& adress(unfoldIndexAdress(id));
if (adress.first >= this->rowCount() || adress.second >= this->columnCount()) if (adress.first >= this->rowCount() || adress.second >= this->columnCount())
{ {
qDebug()<<"Parent index is not present in the model";
throw "Parent index is not present in the model"; throw "Parent index is not present in the model";
} }
return createIndex(adress.first, adress.second, 0); return createIndex(adress.first, adress.second);
} }
void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type) void CSMWorld::IdTable::addRecord (const std::string& id, UniversalId::Type type)
@ -162,15 +164,16 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin,
CSMWorld::UniversalId::Type type) CSMWorld::UniversalId::Type type)
{ {
int index = mIdCollection->getAppendIndex (destination); int index = mIdCollection->getAppendIndex (destination);
beginInsertRows (QModelIndex(), index, index); beginInsertRows (QModelIndex(), index, index);
mIdCollection->cloneRecord(origin, destination, type); mIdCollection->cloneRecord(origin, destination, type);
endInsertRows(); endInsertRows();
} }
///This method can return only indexes to the top level table cells
QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const QModelIndex CSMWorld::IdTable::getModelIndex (const std::string& id, int column) const
{ {
return index (mIdCollection->getIndex (id), column); return index(mIdCollection->getIndex (id), column);
} }
void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record) void CSMWorld::IdTable::setRecord (const std::string& id, const RecordBase& record)
@ -218,19 +221,9 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newO
index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1)); index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1));
} }
CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const unsigned int CSMWorld::IdTable::getFeatures() const
{ {
return mReordering; return mFeatures;
}
CSMWorld::IdTable::Viewing CSMWorld::IdTable::getViewing() const
{
return mViewing;
}
bool CSMWorld::IdTable::hasPreview() const
{
return mPreview;
} }
std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const
@ -238,7 +231,7 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
std::string id; std::string id;
std::string hint; std::string hint;
if (mViewing==Viewing_Cell) if (mFeatures & Feature_ViewCell)
{ {
int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell); int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell);
int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id); int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
@ -249,7 +242,7 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData()); hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData());
} }
} }
else if (mViewing==Viewing_Id) else if (mFeatures & Feature_ViewId)
{ {
int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id); int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
@ -269,31 +262,23 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint); return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint);
} }
///For top level data/columns
int CSMWorld::IdTable::getColumnId(int column) const int CSMWorld::IdTable::getColumnId(int column) const
{ {
return mIdCollection->getColumn(column).getId(); return mIdCollection->getColumn(column).getId();
} }
bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const
{
return (index.isValid() &&
mIdCollection->getColumn (index.column()).mDisplayType == ColumnBase::Display_Nested &&
index.data().isValid());
}
unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const unsigned int CSMWorld::IdTable::foldIndexAdress (const QModelIndex& index) const
{ {
unsigned int out = index.row() * this->columnCount(); unsigned int out = index.row() * this->columnCount();
out += index.column(); out += index.column();
++out; return ++out;
return out;
} }
std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const
{ {
if (id == 0) if (id == 0)
{ {
qDebug()<<"Attempt to unfold index id of the top level data cell";
throw "Attempt to unfold index id of the top level data cell"; throw "Attempt to unfold index id of the top level data cell";
} }

View File

@ -8,19 +8,15 @@
#include "universalid.hpp" #include "universalid.hpp"
#include "columns.hpp" #include "columns.hpp"
<<<<<<< Updated upstream
=======
/*! \brief /*! \brief
* Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records, * Clas for holding the model. Uses typical qt table abstraction/interface for granting access to the individiual fields of the records,
* Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface * Some records are holding nested data (for instance inventory list of the npc). In casses like this, table model offers interface
* to access nested data in the qt way that is specify parent. The parent is encoded in the internalid of the index model * to access nested data in the qt way that is specify parent. Since some of those nested data require multiple columns to
* See methods fold and unfold adress to see why. This approach has some serious limitations: it allows only * represent informations, single int (default way to index model in the qmodelindex) is not sufficiant. Therefore tablemodelindex class
* a single level of the nesting. At the point of creating this code this seemed to be a good enough solution. * can hold two ints for the sake of indexing two dimensions of the table. This model does not support multiple levels of the nested
* If for some reason it turned out that in fact multiple levels of nesting are needed, change in the addressing of the * data. Vast majority of methods makes sense only for the top level data.
* index is most likely the very first to be considered.
*/ */
>>>>>>> Stashed changes
namespace CSMWorld namespace CSMWorld
{ {
class CollectionBase; class CollectionBase;
@ -32,43 +28,38 @@ namespace CSMWorld
public: public:
enum Reordering enum Features
{ {
Reordering_None, Feature_ReorderWithinTopic = 1,
Reordering_WithinTopic
};
enum Viewing /// Use ID column to generate view request (ID is transformed into
{ /// worldspace and original ID is passed as hint with c: prefix).
Viewing_None, Feature_ViewId = 2,
Viewing_Id, // use ID column to generate view request (ID is transformed into
// worldspace and original ID is passed as hint with c: prefix) /// Use cell column to generate view request (cell ID is transformed
Viewing_Cell // use cell column to generate view request (cell ID is transformed /// into worldspace and record ID is passed as hint with r: prefix).
// into worldspace and record ID is passed as hint with r: prefix) Feature_ViewCell = 4,
Feature_View = Feature_ViewId | Feature_ViewCell,
Feature_Preview = 8
}; };
private: private:
CollectionBase *mIdCollection; CollectionBase *mIdCollection;
Reordering mReordering; unsigned int mFeatures;
Viewing mViewing;
bool mPreview; bool mPreview;
// not implemented // not implemented
IdTable (const IdTable&); IdTable (const IdTable&);
IdTable& operator= (const IdTable&); IdTable& operator= (const IdTable&);
<<<<<<< Updated upstream
=======
unsigned int foldIndexAdress(const QModelIndex& index) const; unsigned int foldIndexAdress(const QModelIndex& index) const;
std::pair<int, int> unfoldIndexAdress(unsigned int id) const; std::pair<int, int> unfoldIndexAdress(unsigned int id) const;
>>>>>>> Stashed changes
public: public:
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_None, IdTable (CollectionBase *idCollection, unsigned int features = 0);
Viewing viewing = Viewing_None, bool preview = false);
///< The ownership of \a idCollection is not transferred. ///< The ownership of \a idCollection is not transferred.
virtual ~IdTable(); virtual ~IdTable();
@ -91,8 +82,8 @@ namespace CSMWorld
const; const;
virtual QModelIndex parent (const QModelIndex& index) const; virtual QModelIndex parent (const QModelIndex& index) const;
virtual bool hasChildren (const QModelIndex& index) const; virtual bool hasChildren (const QModelIndex& index) const;
void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None); void addRecord (const std::string& id, UniversalId::Type type = UniversalId::Type_None);
///< \param type Will be ignored, unless the collection supports multiple record types ///< \param type Will be ignored, unless the collection supports multiple record types
@ -119,11 +110,7 @@ namespace CSMWorld
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices ///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex). /// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
Reordering getReordering() const; unsigned int getFeatures() const;
Viewing getViewing() const;
bool hasPreview() const;
std::pair<UniversalId, std::string> view (int row) const; std::pair<UniversalId, std::string> view (int row) const;
///< Return the UniversalId and the hint for viewing \a row. If viewing is not ///< Return the UniversalId and the hint for viewing \a row. If viewing is not

View File

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

View File

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

View File

@ -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,73 @@ 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
{
record.mState = RecordBase::State_Deleted;
setRecord (index, record);
}
continue;
}
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);
}
} }
mCells.setRecord (cellIndex, cell);
} }
std::string CSMWorld::RefCollection::getNewId() std::string CSMWorld::RefCollection::getNewId()

View File

@ -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,7 +26,9 @@ 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();

View File

@ -1,14 +1,13 @@
#include "refidadapter.hpp" #include "refidadapter.hpp"
#include "cassert"
#include <QVariant>
CSMWorld::RefIdAdapter::RefIdAdapter() {} CSMWorld::RefIdAdapter::RefIdAdapter() {}
<<<<<<< Updated upstream
CSMWorld::RefIdAdapter::~RefIdAdapter() {}
=======
CSMWorld::RefIdAdapter::~RefIdAdapter() {} CSMWorld::RefIdAdapter::~RefIdAdapter() {}
CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() {} CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() {}
CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {} CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {}
>>>>>>> Stashed changes

View File

@ -30,6 +30,13 @@ namespace CSMWorld
const QVariant& value) const = 0; const QVariant& value) const = 0;
///< If the data type does not match an exception is thrown. ///< If the data type does not match an exception is thrown.
virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data,
int idnex, int subRowIndex, int subColIndex) const;
virtual void setNestedData (const RefIdColumn *column, RefIdData& data,
const QVariant& value, int index,
int subRowIndex, int subColIndex) const;
virtual std::string getId (const RecordBase& record) const = 0; virtual std::string getId (const RecordBase& record) const = 0;
virtual void setId(RecordBase& record, const std::string& id) = 0; virtual void setId(RecordBase& record, const std::string& id) = 0;
@ -43,15 +50,14 @@ namespace CSMWorld
virtual ~NestedRefIdAdapter(); virtual ~NestedRefIdAdapter();
virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row, virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int row,
const QVariant& value, int subRowIndex, int subColIndex) const = 0; const QVariant& value, int subRowIndex, int subColIndex) const = 0;
virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data,
int index, int subRowIndex, int subColIndex) const = 0; int index, int subRowIndex, int subColIndex) const = 0;
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0;
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0;
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const = 0;
}; };
} }

View File

@ -175,9 +175,9 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
} }
CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns,
const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn) const RefIdColumn *weight, const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content)
: NameRefIdAdapter<ESM::Container> (UniversalId::Type_Container, columns), mWeight (weight), : NameRefIdAdapter<ESM::Container> (UniversalId::Type_Container, columns), mWeight (weight),
mOrganic (organic), mRespawn (respawn) mOrganic (organic), mRespawn (respawn), mContent(content)
{} {}
int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const
@ -220,7 +220,7 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co
if (column==mRespawn) if (column==mRespawn)
return (record.get().mFlags & ESM::Container::Respawn)!=0; return (record.get().mFlags & ESM::Container::Respawn)!=0;
if (column==mContent) if (column==mContent)
return true; return true;
@ -253,16 +253,14 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD
NameRefIdAdapter<ESM::Container>::setData (column, data, index, value); NameRefIdAdapter<ESM::Container>::setData (column, data, index, value);
} }
<<<<<<< Updated upstream
=======
void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data,
int row, int index,
const QVariant& value, const QVariant& value,
int subRowIndex, int subRowIndex,
int subColIndex) const int subColIndex) const
{ {
Record<ESM::Container>& record = static_cast<Record<ESM::Container>&> ( Record<ESM::Container>& record = static_cast<Record<ESM::Container>&> (
data.getRecord (RefIdData::LocalIndex (row, UniversalId::Type_Container))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
if (column==mContent) if (column==mContent)
{ {
@ -286,12 +284,11 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, R
} }
QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column,
const CSMWorld::RefIdData& data, const CSMWorld::RefIdData& data,
int index, int index,
int subRowIndex, int subRowIndex,
int subColIndex) const int subColIndex) const
{ {
qDebug()<<"Accessing content column";
const Record<ESM::Container>& record = static_cast<const Record<ESM::Container>&> ( const Record<ESM::Container>& record = static_cast<const Record<ESM::Container>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
@ -317,7 +314,6 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo
} }
>>>>>>> Stashed changes
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
: ActorColumns (actorColumns) : ActorColumns (actorColumns)
{} {}

View File

@ -35,7 +35,7 @@ namespace CSMWorld
BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base); BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base);
virtual std::string getId (const RecordBase& record) const; virtual std::string getId (const RecordBase& record) const;
virtual void setId (RecordBase& record, const std::string& id); virtual void setId (RecordBase& record, const std::string& id);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
@ -58,7 +58,7 @@ namespace CSMWorld
{ {
(dynamic_cast<Record<RecordT>&> (record).get().mId) = id; (dynamic_cast<Record<RecordT>&> (record).get().mId) = id;
} }
template<typename RecordT> template<typename RecordT>
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
{ {
@ -611,33 +611,27 @@ namespace CSMWorld
const RefIdColumn *mWeight; const RefIdColumn *mWeight;
const RefIdColumn *mOrganic; const RefIdColumn *mOrganic;
const RefIdColumn *mRespawn; const RefIdColumn *mRespawn;
const RefIdColumn *mContent;
public: public:
ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight,
<<<<<<< Updated upstream const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content);
const RefIdColumn *organic, const RefIdColumn *respawn);
=======
const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content);
virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index,
int index, int subRowIndex, int subColIndex) const; int subRowIndex, int subColIndex) const;
>>>>>>> Stashed changes
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const; virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) const;
<<<<<<< Updated upstream
=======
virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index, virtual void setNestedData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value, int subRowIndex, int subColIndex) const; const QVariant& value, int subRowIndex, int subColIndex) const;
>>>>>>> Stashed changes
virtual void setData (const RefIdColumn *column, RefIdData& data, int index, virtual void setData (const RefIdColumn *column, RefIdData& data, int index,
const QVariant& value) const; const QVariant& value) const;
///< If the data type does not match an exception is thrown. ///< If the data type does not match an exception is thrown.
virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const;
virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const;
}; };

View File

@ -166,6 +166,9 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean));
const RefIdColumn *respawn = &mColumns.back(); const RefIdColumn *respawn = &mColumns.back();
mColumns.push_back(RefIdColumn (Columns::ColumnId_ContainerContent, ColumnBase::Display_Nested, ColumnBase::Flag_Dialogue, false, false));
const RefIdColumn *content = &mColumns.back();
CreatureColumns creatureColumns (actorsColumns); CreatureColumns creatureColumns (actorsColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType)); mColumns.push_back (RefIdColumn (Columns::ColumnId_CreatureType, ColumnBase::Display_CreatureType));
@ -305,10 +308,17 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponReach, ColumnBase::Display_Float)); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponReach, ColumnBase::Display_Float));
weaponColumns.mReach = &mColumns.back(); weaponColumns.mReach = &mColumns.back();
for (int i=0; i<6; ++i) for (int i=0; i<3; ++i)
{ {
mColumns.push_back (RefIdColumn (Columns::ColumnId_MinChop + i, ColumnBase::Display_Integer)); const RefIdColumn **column =
weaponColumns.mChop[i] = &mColumns.back(); i==0 ? weaponColumns.mChop : (i==1 ? weaponColumns.mSlash : weaponColumns.mThrust);
for (int j=0; j<2; ++j)
{
mColumns.push_back (
RefIdColumn (Columns::ColumnId_MinChop+i*2+j, ColumnBase::Display_Integer));
column[j] = &mColumns.back();
}
} }
static const struct static const struct
@ -341,7 +351,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, mAdapters.insert (std::make_pair (UniversalId::Type_Clothing,
new ClothingRefIdAdapter (enchantableColumns, clothingType))); new ClothingRefIdAdapter (enchantableColumns, clothingType)));
mAdapters.insert (std::make_pair (UniversalId::Type_Container, mAdapters.insert (std::make_pair (UniversalId::Type_Container,
new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn))); new ContainerRefIdAdapter (nameColumns, weightCapacity, organic, respawn, content)));
mAdapters.insert (std::make_pair (UniversalId::Type_Creature, mAdapters.insert (std::make_pair (UniversalId::Type_Creature,
new CreatureRefIdAdapter (creatureColumns))); new CreatureRefIdAdapter (creatureColumns)));
mAdapters.insert (std::make_pair (UniversalId::Type_Door, mAdapters.insert (std::make_pair (UniversalId::Type_Door,
@ -417,8 +427,6 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const
return adaptor.getData (&mColumns.at (column), mData, localIndex.first); return adaptor.getData (&mColumns.at (column), mData, localIndex.first);
} }
<<<<<<< Updated upstream
=======
QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const
{ {
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row);
@ -429,7 +437,6 @@ QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subR
return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn);
} }
>>>>>>> Stashed changes
void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data)
{ {
RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index);

View File

@ -69,6 +69,8 @@ namespace CSMWorld
virtual QVariant getData (int index, int column) const; virtual QVariant getData (int index, int column) const;
virtual QVariant getNestedData(int row, int column, int subRow, int subColumn) const;
virtual void setData (int index, int column, const QVariant& data); virtual void setData (int index, int column, const QVariant& data);
virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); virtual void setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn);

View File

@ -231,27 +231,27 @@ namespace CSMWorld
void save (int index, ESM::ESMWriter& writer) const; void save (int index, ESM::ESMWriter& writer) const;
//RECORD CONTAINERS ACCESS METHODS //RECORD CONTAINERS ACCESS METHODS
const RefIdDataContainer<ESM::Book>& getBooks() const; const RefIdDataContainer<ESM::Book>& getBooks() const;
const RefIdDataContainer<ESM::Activator>& getActivators() const; const RefIdDataContainer<ESM::Activator>& getActivators() const;
const RefIdDataContainer<ESM::Potion>& getPotions() const; const RefIdDataContainer<ESM::Potion>& getPotions() const;
const RefIdDataContainer<ESM::Apparatus>& getApparati() const; const RefIdDataContainer<ESM::Apparatus>& getApparati() const;
const RefIdDataContainer<ESM::Armor>& getArmors() const; const RefIdDataContainer<ESM::Armor>& getArmors() const;
const RefIdDataContainer<ESM::Clothing>& getClothing() const; const RefIdDataContainer<ESM::Clothing>& getClothing() const;
const RefIdDataContainer<ESM::Container>& getContainers() const; const RefIdDataContainer<ESM::Container>& getContainers() const;
const RefIdDataContainer<ESM::Creature>& getCreatures() const; const RefIdDataContainer<ESM::Creature>& getCreatures() const;
const RefIdDataContainer<ESM::Door>& getDoors() const; const RefIdDataContainer<ESM::Door>& getDoors() const;
const RefIdDataContainer<ESM::Ingredient>& getIngredients() const; const RefIdDataContainer<ESM::Ingredient>& getIngredients() const;
const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const; const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const;
const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const; const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const;
const RefIdDataContainer<ESM::Light>& getLights() const; const RefIdDataContainer<ESM::Light>& getLights() const;
const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const; const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const;
const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const; const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const;
const RefIdDataContainer<ESM::NPC>& getNPCs() const; const RefIdDataContainer<ESM::NPC>& getNPCs() const;
const RefIdDataContainer<ESM::Weapon >& getWeapons() const; const RefIdDataContainer<ESM::Weapon >& getWeapons() const;
const RefIdDataContainer<ESM::Probe >& getProbes() const; const RefIdDataContainer<ESM::Probe >& getProbes() const;
const RefIdDataContainer<ESM::Repair>& getRepairs() const; const RefIdDataContainer<ESM::Repair>& getRepairs() const;
const RefIdDataContainer<ESM::Static>& getStatics() const; const RefIdDataContainer<ESM::Static>& getStatics() const;
}; };
} }

View File

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

View File

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

View File

@ -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 },
@ -61,9 +61,10 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell", ":./spell.png" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Topic, "Topic", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Journal, "Journal", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 }, { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 }, { CSMWorld::UniversalId::Class_SubRecord, 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" },
@ -89,7 +90,7 @@ namespace
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Static, "Static", ":./static.png" },
{ CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" }, { CSMWorld::UniversalId::Class_RefRecord, CSMWorld::UniversalId::Type_Weapon, "Weapon", ":./weapon.png" },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 }, { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Reference, "Reference", 0 },
{ CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Filter, "Filter", ":./filter.png" },
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Scene, "Scene", 0 },
{ CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 }, { CSMWorld::UniversalId::Class_Collection, CSMWorld::UniversalId::Type_Preview, "Preview", 0 },
@ -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
}; };
} }
@ -318,6 +320,28 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceabl
return list; return list;
} }
CSMWorld::UniversalId::Type CSMWorld::UniversalId::getParentType (Type type)
{
for (int i=0; sIdArg[i].mType; ++i)
if (type==sIdArg[i].mType)
{
if (sIdArg[i].mClass==Class_RefRecord)
return Type_Referenceables;
if (sIdArg[i].mClass==Class_SubRecord || sIdArg[i].mClass==Class_Record)
{
if (type==Type_Cell_Missing)
return Type_Cells;
return static_cast<Type> (type-1);
}
break;
}
return Type_None;
}
bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right) bool CSMWorld::operator== (const CSMWorld::UniversalId& left, const CSMWorld::UniversalId& right)
{ {
return left.isEqual (right); return left.isEqual (right);

View File

@ -32,6 +32,8 @@ namespace CSMWorld
ArgumentType_Index ArgumentType_Index
}; };
/// \note A record list type must always be immediately followed by the matching
/// record type, if this type is of class SubRecord or Record.
enum Type enum Type
{ {
Type_None = 0, Type_None = 0,
@ -60,6 +62,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,
@ -85,8 +88,8 @@ namespace CSMWorld
Type_References, Type_References,
Type_Reference, Type_Reference,
Type_RegionMap, Type_RegionMap,
Type_Filter,
Type_Filters, Type_Filters,
Type_Filter,
Type_Topics, Type_Topics,
Type_Topic, Type_Topic,
Type_Journals, Type_Journals,
@ -96,10 +99,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:
@ -145,6 +149,11 @@ namespace CSMWorld
///< Will return an empty string, if no icon is available. ///< Will return an empty string, if no icon is available.
static std::vector<Type> listReferenceableTypes(); static std::vector<Type> listReferenceableTypes();
/// If \a type is a SubRecord, RefRecord or Record type return the type of the table
/// that contains records of type \a type.
/// Otherwise return Type_None.
static Type getParentType (Type type);
}; };
bool operator== (const UniversalId& left, const UniversalId& right); bool operator== (const UniversalId& left, const UniversalId& right);

View File

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

View File

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

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