mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-10-31 19:56:38 +00:00 
			
		
		
		
	Merge branch 'dialog-fix' into NonTableFields
TODO stop failing epicly with git
This commit is contained in:
		
						commit
						defd0b1754
					
				
					 639 changed files with 16980 additions and 10827 deletions
				
			
		
							
								
								
									
										131
									
								
								CMakeLists.txt
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								CMakeLists.txt
									
									
									
									
									
								
							|  | @ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) | |||
| message(STATUS "Configuring OpenMW...") | ||||
| 
 | ||||
| set(OPENMW_VERSION_MAJOR 0) | ||||
| set(OPENMW_VERSION_MINOR 29) | ||||
| set(OPENMW_VERSION_MINOR 30) | ||||
| set(OPENMW_VERSION_RELEASE 0) | ||||
| 
 | ||||
| set(OPENMW_VERSION_COMMITHASH "") | ||||
|  | @ -36,18 +36,8 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git) | |||
|                 string(REGEX REPLACE "^openmw-[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_MINOR "${VERSION}") | ||||
|                 string(REGEX REPLACE "^openmw-[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" GIT_VERSION_RELEASE "${VERSION}") | ||||
| 
 | ||||
|                 set(GIT_VERSION "${GIT_VERSION_MAJOR}.${GIT_VERSION_MINOR}.${GIT_VERSION_RELEASE}") | ||||
| 
 | ||||
|                 if(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) | ||||
|                     message(FATAL_ERROR "Silly Zini forgot to update the version again...") | ||||
|                 else(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) | ||||
|                     set(OPENMW_VERSION_MAJOR ${GIT_VERSION_MAJOR}) | ||||
|                     set(OPENMW_VERSION_MINOR ${GIT_VERSION_MINOR}) | ||||
|                     set(OPENMW_VERSION_RELEASE ${GIT_VERSION_RELEASE}) | ||||
| 
 | ||||
|                     set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") | ||||
|                     set(OPENMW_VERSION_TAGHASH "${TAGHASH}") | ||||
|                 endif(NOT ${OPENMW_VERSION} STREQUAL ${GIT_VERSION}) | ||||
|                 set(OPENMW_VERSION_COMMITHASH "${COMMITHASH}") | ||||
|                 set(OPENMW_VERSION_TAGHASH "${TAGHASH}") | ||||
| 
 | ||||
|                 message(STATUS "OpenMW version ${OPENMW_VERSION}") | ||||
|             else(MATCH) | ||||
|  | @ -86,8 +76,6 @@ option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock fram | |||
| 
 | ||||
| # Sound source selection | ||||
| 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 | ||||
| option(OPENMW_OSX_DEPLOYMENT OFF) | ||||
|  | @ -102,13 +90,13 @@ endif(UNIX AND NOT APPLE) | |||
| # Location of morrowind data files | ||||
| if (APPLE) | ||||
|     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) | ||||
|     set(MORROWIND_DATA_FILES "/usr/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(MORROWIND_DATA_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") | ||||
|     set(OPENMW_RESOURCE_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") | ||||
| else() | ||||
|     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) | ||||
| 
 | ||||
| if (WIN32) | ||||
|  | @ -131,6 +119,7 @@ set(OENGINE_OGRE | |||
| ) | ||||
| 
 | ||||
| set(OENGINE_GUI | ||||
|   ${LIBDIR}/openengine/gui/loglistener.cpp | ||||
|   ${LIBDIR}/openengine/gui/manager.cpp | ||||
|   ${LIBDIR}/openengine/gui/layout.hpp | ||||
| ) | ||||
|  | @ -171,27 +160,6 @@ if (USE_FFMPEG) | |||
|     endif (FFMPEG_FOUND) | ||||
| 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) | ||||
|     message(WARNING "--------------------") | ||||
|     message(WARNING "Failed to find any sound input packages") | ||||
|  | @ -257,6 +225,9 @@ endif () | |||
| 
 | ||||
| 
 | ||||
| set(BOOST_COMPONENTS system filesystem program_options) | ||||
| if(WIN32) | ||||
|     set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) | ||||
| endif(WIN32) | ||||
| 
 | ||||
| IF(BOOST_STATIC) | ||||
|     set(Boost_USE_STATIC_LIBS   ON) | ||||
|  | @ -268,16 +239,40 @@ find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) | |||
| find_package(SDL2 REQUIRED) | ||||
| find_package(OpenAL REQUIRED) | ||||
| find_package(Bullet REQUIRED) | ||||
| IF(OGRE_STATIC) | ||||
| find_package(Cg) | ||||
| IF(WIN32) | ||||
| 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) | ||||
| 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}) | ||||
| ENDIF(WIN32) | ||||
| ENDIF(OGRE_STATIC) | ||||
| 
 | ||||
| set(OGRE_PLUGIN_INCLUDE_DIRS "") | ||||
| set(OGRE_STATIC_PLUGINS "") | ||||
| 
 | ||||
| macro(add_static_ogre_plugin PLUGIN) | ||||
|     if(OGRE_${PLUGIN}_FOUND) | ||||
|         # strip RenderSystem_ or Plugin_ prefix from plugin name | ||||
|         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("." | ||||
|     ${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} | ||||
|     ${Boost_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}) | ||||
| 
 | ||||
| if(MYGUI_STATIC) | ||||
|    add_definitions(-DMYGUI_STATIC) | ||||
| endif (MYGUI_STATIC) | ||||
| 
 | ||||
| if (APPLE) | ||||
|     # List used Ogre plugins | ||||
|     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 | ||||
|     "${OpenMW_BINARY_DIR}/openmw.cfg.install") | ||||
| 
 | ||||
| configure_file(${OpenMW_SOURCE_DIR}/files/opencs.cfg | ||||
|     "${OpenMW_BINARY_DIR}/opencs.cfg") | ||||
| configure_file(${OpenMW_SOURCE_DIR}/files/opencs.ini | ||||
|     "${OpenMW_BINARY_DIR}/opencs.ini") | ||||
| 
 | ||||
| configure_file(${OpenMW_SOURCE_DIR}/files/opencs/defaultfilters | ||||
|     "${OpenMW_BINARY_DIR}/resources/defaultfilters" COPYONLY) | ||||
|  | @ -434,7 +433,6 @@ IF(NOT WIN32 AND NOT APPLE) | |||
| 
 | ||||
|         # Install licenses | ||||
|         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" ) | ||||
|     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}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") | ||||
|     IF(BUILD_OPENCS) | ||||
|         INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") | ||||
|         INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${SYSCONFDIR}" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "opencs") | ||||
|     ENDIF(BUILD_OPENCS) | ||||
| 
 | ||||
|     # Install resources | ||||
|  | @ -480,7 +478,7 @@ if(WIN32) | |||
|     ENDIF(BUILD_MWINIIMPORTER) | ||||
|     IF(BUILD_OPENCS) | ||||
|         INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".") | ||||
|         INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION ".") | ||||
|         INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".") | ||||
|     ENDIF(BUILD_OPENCS) | ||||
| 
 | ||||
|     INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") | ||||
|  | @ -618,6 +616,7 @@ if (WIN32) | |||
|         4706 # Assignment in conditional expression | ||||
|         4738 # Storing 32-bit float result in memory, possible loss of performance | ||||
|         4986 # Undocumented warning that occurs in the crtdbg.h file | ||||
|         4987 # nonstandard extension used (triggered by setjmp.h) | ||||
|         4996 # Function was declared deprecated | ||||
| 
 | ||||
|         # cause by ogre extensivly | ||||
|  | @ -634,7 +633,9 @@ if (WIN32) | |||
|         4305 # Truncating value (double to float, for example) | ||||
|         4309 # Variable overflow, trying to store 128 in a signed char for example | ||||
|         4355 # Using 'this' in member initialization list | ||||
|         4505 # Unreferenced local function has been removed | ||||
|         4701 # Potentially uninitialized local variable used | ||||
|         4702 # Unreachable code | ||||
|         4800 # Boolean optimization warning, e.g. myBool = (myInt != 0) instead of myBool = myInt | ||||
|         ) | ||||
| 
 | ||||
|  | @ -642,19 +643,31 @@ if (WIN32) | |||
|         set(WARNINGS "${WARNINGS} /wd${d}") | ||||
|     endforeach(d) | ||||
| 
 | ||||
|     set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here | ||||
|     set(SHINY_WARNINGS "${WARNINGS} /wd4245") | ||||
|     set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${SHINY_WARNINGS}) | ||||
|     # there's an unreferenced local variable in the ogre platform, suppress it | ||||
|     set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101") | ||||
|     set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${SHINY_OGRE_WARNINGS}) | ||||
|     set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     set_target_properties(oics PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     if (BUILD_LAUNCHER) | ||||
|         set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     endif (BUILD_LAUNCHER) | ||||
|     set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|         if (BUILD_BSATOOL) | ||||
|     if (BUILD_BSATOOL) | ||||
|         set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|             endif (BUILD_BSATOOL) | ||||
|     endif (BUILD_BSATOOL) | ||||
|     if (BUILD_ESMTOOL) | ||||
|         set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     endif (BUILD_ESMTOOL) | ||||
|     if (BUILD_OPENCS) | ||||
|         set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     endif (BUILD_OPENCS) | ||||
|     if (BUILD_MWINIIMPORTER) | ||||
|         set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS ${WARNINGS}) | ||||
|     endif (BUILD_MWINIIMPORTER) | ||||
|   endif(MSVC) | ||||
| 
 | ||||
|   # Same for MinGW | ||||
|  | @ -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}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) | ||||
|     install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) | ||||
|     install(FILES "${OpenMW_BINARY_DIR}/opencs.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) | ||||
|     install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) | ||||
| 
 | ||||
|     set(CPACK_GENERATOR "DragNDrop") | ||||
|     set(CPACK_PACKAGE_VERSION ${OPENMW_VERSION}) | ||||
|  |  | |||
|  | @ -333,7 +333,7 @@ int load(Arguments& info) | |||
| 
 | ||||
|             // Is the user interested in this record type?
 | ||||
|             bool interested = true; | ||||
|             if (info.types.size() > 0) | ||||
|             if (!info.types.empty()) | ||||
|             { | ||||
|                 std::vector<std::string>::iterator match; | ||||
|                 match = std::find(info.types.begin(), info.types.end(), | ||||
|  |  | |||
|  | @ -387,7 +387,7 @@ std::string magicEffectLabel(int idx) | |||
|         "sEffectSummonCreature04", | ||||
|         "sEffectSummonCreature05" | ||||
|     }; | ||||
|     if (idx >= 0 && idx <= 143) | ||||
|     if (idx >= 0 && idx <= 142) | ||||
|         return magicEffectLabels[idx]; | ||||
|     else | ||||
|         return "Invalid"; | ||||
|  | @ -471,7 +471,7 @@ std::string skillLabel(int idx) | |||
|         "Speechcraft", | ||||
|         "Hand-to-hand" | ||||
|     }; | ||||
|     if (idx >= 0 && idx <= 27) | ||||
|     if (idx >= 0 && idx <= 26) | ||||
|         return skillLabels[idx]; | ||||
|     else | ||||
|         return "Invalid"; | ||||
|  | @ -498,7 +498,7 @@ std::string rangeTypeLabel(int idx) | |||
|         "Touch", | ||||
|         "Target" | ||||
|     }; | ||||
|     if (idx >= 0 && idx <= 3) | ||||
|     if (idx >= 0 && idx <= 2) | ||||
|         return rangeTypeLabels[idx]; | ||||
|     else | ||||
|         return "Invalid"; | ||||
|  |  | |||
|  | @ -124,7 +124,7 @@ void printEffectList(ESM::EffectList effects) | |||
| { | ||||
|     int i = 0; | ||||
|     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) | ||||
|                   << " (" << eit->mEffectID << ")" << std::endl; | ||||
|  | @ -651,7 +651,7 @@ void Record<ESM::Dialogue>::print() | |||
|     // Sadly, there are no DialInfos, because the loader dumps as it
 | ||||
|     // loads, rather than loading and then dumping. :-( Anyone mind if
 | ||||
|     // I change this?
 | ||||
|     std::vector<ESM::DialInfo>::iterator iit; | ||||
|     ESM::Dialogue::InfoContainer::iterator iit; | ||||
|     for (iit = mData.mInfo.begin(); iit != mData.mInfo.end(); iit++) | ||||
|         std::cout << "INFO!" << iit->mId << std::endl; | ||||
| } | ||||
|  | @ -707,9 +707,9 @@ void Record<ESM::Faction>::print() | |||
|             std::cout << "    Faction Reaction: " | ||||
|                       << 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++) | ||||
|         std::cout << "  Reaction: " << rit->mReaction << " = " << rit->mFaction << std::endl; | ||||
|         std::cout << "  Reaction: " << rit->second << " = " << rit->first << std::endl; | ||||
| } | ||||
| 
 | ||||
| template<> | ||||
|  |  | |||
|  | @ -94,15 +94,6 @@ if(NOT WIN32) | |||
| endif(NOT WIN32) | ||||
| 
 | ||||
| # 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 | ||||
|     ${GUI_TYPE} | ||||
|     ${LAUNCHER} | ||||
|  | @ -116,7 +107,7 @@ target_link_libraries(omwlauncher | |||
|     ${Boost_LIBRARIES} | ||||
|     ${OGRE_LIBRARIES} | ||||
|     ${OGRE_STATIC_PLUGINS} | ||||
|     ${SDL2_LIBRARY} | ||||
|     ${SDL2_LIBRARY_ONLY} | ||||
|     ${QT_LIBRARIES} | ||||
|     components | ||||
| ) | ||||
|  |  | |||
|  | @ -214,13 +214,13 @@ QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre | |||
|     uint row = 0; | ||||
|     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; | ||||
|         uint idx = 0; | ||||
| 
 | ||||
|         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) { | ||||
|                 result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromStdString((*opt_it).c_str()).simplified(); | ||||
|  |  | |||
|  | @ -41,11 +41,11 @@ Launcher::MainDialog::MainDialog(QWidget *parent) | |||
|     // Check if the font is installed
 | ||||
|     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); | ||||
| 
 | ||||
|         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); | ||||
|  | @ -243,7 +243,7 @@ bool Launcher::MainDialog::showFirstRunDialog() | |||
|         } | ||||
| 
 | ||||
|         // 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); | ||||
| 
 | ||||
|         if (!file.exists()) { | ||||
|  | @ -358,7 +358,7 @@ bool Launcher::MainDialog::setupLauncherSettings() | |||
| { | ||||
|     mLauncherSettings.setMultiValueEnabled(true); | ||||
| 
 | ||||
|     QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); | ||||
|     QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); | ||||
| 
 | ||||
|     QStringList paths; | ||||
|     paths.append(QString("launcher.cfg")); | ||||
|  | @ -464,8 +464,8 @@ bool Launcher::expansions(Launcher::UnshieldThread& cd) | |||
| 
 | ||||
| bool Launcher::MainDialog::setupGameSettings() | ||||
| { | ||||
|     QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); | ||||
|     QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); | ||||
|     QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); | ||||
|     QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); | ||||
| 
 | ||||
|     // Load the user config file first, separately
 | ||||
|     // So we can write it properly, uncontaminated
 | ||||
|  | @ -594,7 +594,7 @@ bool Launcher::MainDialog::setupGameSettings() | |||
| 
 | ||||
|             while(expansions(cd)); | ||||
| 
 | ||||
|             selectedFile = QString::fromStdString(cd.GetMWEsmPath()); | ||||
|             selectedFile = QString::fromUtf8(cd.GetMWEsmPath().c_str()); | ||||
|         } | ||||
|         #endif // WIN32
 | ||||
| 
 | ||||
|  | @ -615,8 +615,8 @@ bool Launcher::MainDialog::setupGraphicsSettings() | |||
| { | ||||
|     mGraphicsSettings.setMultiValueEnabled(false); | ||||
| 
 | ||||
|     QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); | ||||
|     QString globalPath = QString::fromStdString(mCfgMgr.getGlobalPath().string()); | ||||
|     QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); | ||||
|     QString globalPath = QString::fromUtf8(mCfgMgr.getGlobalPath().string().c_str()); | ||||
| 
 | ||||
|     QFile localDefault(QString("settings-default.cfg")); | ||||
|     QFile globalDefault(globalPath + QString("settings-default.cfg")); | ||||
|  | @ -702,7 +702,7 @@ bool Launcher::MainDialog::writeSettings() | |||
|     mGraphicsPage->saveSettings(); | ||||
|     mDataFilesPage->saveSettings(); | ||||
| 
 | ||||
|     QString userPath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()); | ||||
|     QString userPath = QString::fromUtf8(mCfgMgr.getUserConfigPath().string().c_str()); | ||||
|     QDir dir(userPath); | ||||
| 
 | ||||
|     if (!dir.exists()) { | ||||
|  | @ -806,7 +806,7 @@ void Launcher::MainDialog::play() | |||
|             msgBox.setWindowTitle(tr("No game file selected")); | ||||
|             msgBox.setIcon(QMessageBox::Warning); | ||||
|             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>")); | ||||
|             msgBox.exec(); | ||||
|             return; | ||||
|  |  | |||
|  | @ -45,7 +45,8 @@ void Launcher::GameSettings::validatePaths() | |||
|     Files::PathContainer dataDirs; | ||||
| 
 | ||||
|     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
 | ||||
|  | @ -53,7 +54,7 @@ void Launcher::GameSettings::validatePaths() | |||
|     mDataDirs.clear(); | ||||
| 
 | ||||
|     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('\"')); | ||||
| 
 | ||||
|         QDir dir(path); | ||||
|  | @ -68,12 +69,13 @@ void Launcher::GameSettings::validatePaths() | |||
|         return; | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     if (!dataDirs.empty()) { | ||||
|         QString path = QString::fromStdString(dataDirs.front().string()); | ||||
|         QString path = QString::fromUtf8(dataDirs.front().string().c_str()); | ||||
|         path.remove(QChar('\"')); | ||||
| 
 | ||||
|         QDir dir(path); | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| #include "unshieldthread.hpp" | ||||
| 
 | ||||
| #include <fstream> | ||||
| #include <boost/filesystem/fstream.hpp> | ||||
| #include <components/misc/stringops.hpp> | ||||
|     | ||||
| namespace bfs = boost::filesystem; | ||||
|  | @ -49,7 +49,7 @@ namespace | |||
| 
 | ||||
|     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; | ||||
| 
 | ||||
|         strstream.seekg(0, std::ios::end); | ||||
|  | @ -201,7 +201,7 @@ namespace | |||
|             add_setting("Archives", "Archive 1", "Bloodmoon.bsa", ini); | ||||
|         } | ||||
| 
 | ||||
|         std::ofstream inistream(ini_path.c_str()); | ||||
|         bfs::ofstream inistream((ini_path)); | ||||
|         inistream << ini; | ||||
|         inistream.close(); | ||||
|     } | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| #include "importer.hpp" | ||||
| #include <boost/iostreams/device/file.hpp> | ||||
| #include <boost/iostreams/stream.hpp> | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <map> | ||||
|  | @ -9,6 +8,10 @@ | |||
| #include <sstream> | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem/fstream.hpp> | ||||
| 
 | ||||
| namespace bfs = boost::filesystem; | ||||
| 
 | ||||
| MwIniImporter::MwIniImporter() | ||||
|     : mVerbose(false) | ||||
|  | @ -661,7 +664,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam | |||
| 
 | ||||
|     std::string section(""); | ||||
|     MwIniImporter::multistrmap map; | ||||
|     boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str()); | ||||
|     bfs::ifstream file((bfs::path(filename))); | ||||
|     ToUTF8::Utf8Encoder encoder(mEncoding); | ||||
| 
 | ||||
|     std::string line; | ||||
|  | @ -674,6 +677,10 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam | |||
|             line = line.substr(0, line.length()-1); | ||||
|         } | ||||
| 
 | ||||
|         if(line.empty()) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         if(line[0] == '[') { | ||||
|             int pos = line.find(']'); | ||||
|             if(pos < 2) { | ||||
|  | @ -690,10 +697,6 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam | |||
|             line = line.substr(0,comment_pos); | ||||
|         } | ||||
| 
 | ||||
|         if(line.empty()) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         int pos = line.find("="); | ||||
|         if(pos < 1) { | ||||
|             continue; | ||||
|  | @ -720,7 +723,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filenam | |||
|     std::cout << "load cfg file: " << filename << std::endl; | ||||
| 
 | ||||
|     MwIniImporter::multistrmap map; | ||||
|     boost::iostreams::stream<boost::iostreams::file_source>file(filename.c_str()); | ||||
|     bfs::ifstream file((bfs::path(filename))); | ||||
| 
 | ||||
|     std::string 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(std::vector<std::string>::const_iterator entry=it->second.begin(); entry != it->second.end(); ++entry) { | ||||
|  |  | |||
|  | @ -1,12 +1,11 @@ | |||
| #ifndef MWINIIMPORTER_IMPORTER | ||||
| #define MWINIIMPORTER_IMPORTER 1 | ||||
| 
 | ||||
| #include <boost/iostreams/device/file.hpp> | ||||
| #include <boost/iostreams/stream.hpp> | ||||
| #include <string> | ||||
| #include <map> | ||||
| #include <vector> | ||||
| #include <exception> | ||||
| #include <iosfwd> | ||||
| 
 | ||||
| #include <components/to_utf8/to_utf8.hpp> | ||||
| 
 | ||||
|  | @ -24,7 +23,7 @@ class MwIniImporter { | |||
|     void    mergeFallback(multistrmap &cfg, const multistrmap &ini) const; | ||||
|     void    importGameFiles(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: | ||||
|     static void insertMultistrmap(multistrmap &cfg, const std::string& key, const std::string& value); | ||||
|  |  | |||
|  | @ -1,14 +1,59 @@ | |||
| #include "importer.hpp" | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include <boost/program_options.hpp> | ||||
| #include <boost/filesystem.hpp> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem/fstream.hpp> | ||||
| 
 | ||||
| namespace bpo = boost::program_options; | ||||
| namespace bfs = boost::filesystem; | ||||
| 
 | ||||
| #ifndef _WIN32 | ||||
| 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::positional_options_description p_desc; | ||||
|     desc.add_options() | ||||
|  | @ -94,7 +139,7 @@ int main(int argc, char *argv[]) { | |||
|     } | ||||
| 
 | ||||
|     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); | ||||
| 
 | ||||
|     return 0; | ||||
|  |  | |||
|  | @ -5,11 +5,11 @@ opencs_units (. editor) | |||
| set (CMAKE_BUILD_TYPE DEBUG) | ||||
| 
 | ||||
| opencs_units (model/doc | ||||
|     document operation saving | ||||
|     document operation saving documentmanager loader | ||||
|     ) | ||||
| 
 | ||||
| opencs_units_noqt (model/doc | ||||
|     documentmanager stage savingstate savingstages | ||||
|     stage savingstate savingstages | ||||
|     ) | ||||
| 
 | ||||
| opencs_hdrs_noqt (model/doc | ||||
|  | @ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc | |||
| 
 | ||||
| 
 | ||||
| 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 | ||||
|     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 | ||||
|     table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator | ||||
|     cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool | ||||
|     scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap | ||||
|     scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable | ||||
|     ) | ||||
| 
 | ||||
| opencs_units (view/render | ||||
|  | @ -88,34 +88,30 @@ opencs_units_noqt (view/tools | |||
|     ) | ||||
| 
 | ||||
| opencs_units (view/settings | ||||
|     abstractblock | ||||
|     proxyblock | ||||
|     abstractwidget | ||||
|     usersettingsdialog | ||||
|     datadisplayformatpage | ||||
|     windowpage | ||||
|     settingwindow | ||||
|     dialog | ||||
|     page | ||||
|     view | ||||
|     booleanview | ||||
|     textview | ||||
|     listview | ||||
|     rangeview | ||||
|     resizeablestackedwidget | ||||
|     spinbox | ||||
|     ) | ||||
| 
 | ||||
| opencs_units_noqt (view/settings | ||||
|     abstractpage | ||||
|     blankpage | ||||
|     groupblock | ||||
|     customblock | ||||
|     groupbox | ||||
|     itemblock | ||||
|     settingwidget | ||||
|     toggleblock | ||||
|     support | ||||
|     frame | ||||
|     ) | ||||
| 
 | ||||
| opencs_units (model/settings | ||||
|     usersettings | ||||
|     settingcontainer | ||||
|     setting | ||||
|     connector | ||||
|     ) | ||||
| 
 | ||||
| opencs_units_noqt (model/settings | ||||
| opencs_hdrs_noqt (model/settings | ||||
|     support | ||||
|     settingsitem | ||||
|     ) | ||||
| 
 | ||||
| opencs_units_noqt (model/filter | ||||
|  | @ -149,6 +145,10 @@ if(WIN32) | |||
| endif(WIN32) | ||||
| 
 | ||||
| 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(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) | ||||
|  | @ -192,6 +192,7 @@ endif(APPLE) | |||
| 
 | ||||
| target_link_libraries(opencs | ||||
|     ${OGRE_LIBRARIES} | ||||
|     ${OGRE_STATIC_PLUGINS} | ||||
|     ${SHINY_LIBRARIES} | ||||
|     ${Boost_LIBRARIES} | ||||
|     ${QT_LIBRARIES} | ||||
|  |  | |||
|  | @ -20,14 +20,15 @@ | |||
| #include "model/world/data.hpp" | ||||
| 
 | ||||
| CS::Editor::Editor (OgreInit::OgreInit& ogreInit) | ||||
| : mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), | ||||
| : mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), | ||||
|   mIpcServerName ("org.openmw.OpenCS") | ||||
| { | ||||
|     std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(); | ||||
| 
 | ||||
|     setupDataFiles (config.first); | ||||
| 
 | ||||
|     CSMSettings::UserSettings::instance().loadSettings ("opencs.cfg"); | ||||
|     CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); | ||||
|     mSettings.setModel (CSMSettings::UserSettings::instance()); | ||||
| 
 | ||||
|     ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); | ||||
| 
 | ||||
|  | @ -37,6 +38,11 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit) | |||
|     mNewGame.setLocalData (mLocal); | ||||
|     mFileDialog.setLocalData (mLocal); | ||||
| 
 | ||||
|     connect (&mDocumentManager, SIGNAL (documentAdded (CSMDoc::Document *)), | ||||
|         this, SLOT (documentAdded (CSMDoc::Document *))); | ||||
|     connect (&mDocumentManager, SIGNAL (lastDocumentDeleted()), | ||||
|         this, SLOT (lastDocumentDeleted())); | ||||
| 
 | ||||
|     connect (&mViewManager, SIGNAL (newGameRequest ()), this, SLOT (createGame ())); | ||||
|     connect (&mViewManager, SIGNAL (newAddonRequest ()), this, SLOT (createAddon ())); | ||||
|     connect (&mViewManager, SIGNAL (loadDocumentRequest ()), this, SLOT (loadDocument ())); | ||||
|  | @ -84,6 +90,9 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi | |||
| 
 | ||||
|     mCfgMgr.readConfiguration(variables, desc); | ||||
| 
 | ||||
|     mDocumentManager.setEncoding ( | ||||
|         ToUTF8::calculateEncoding (variables["encoding"].as<std::string>())); | ||||
| 
 | ||||
|     mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>()); | ||||
| 
 | ||||
|     mFsStrict = variables["fs-strict"].as<bool>(); | ||||
|  | @ -117,6 +126,13 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi | |||
| 
 | ||||
|     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> >()); | ||||
| } | ||||
| 
 | ||||
|  | @ -150,9 +166,8 @@ void CS::Editor::openFiles (const boost::filesystem::path &savePath) | |||
|     foreach (const QString &path, mFileDialog.selectedFilePaths()) | ||||
|         files.push_back(path.toUtf8().constData()); | ||||
| 
 | ||||
|     CSMDoc::Document *document = mDocumentManager.addDocument (files, savePath, false); | ||||
|     mDocumentManager.addDocument (files, savePath, false); | ||||
| 
 | ||||
|     mViewManager.addView (document); | ||||
|     mFileDialog.hide(); | ||||
| } | ||||
| 
 | ||||
|  | @ -166,9 +181,8 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath) | |||
| 
 | ||||
|     files.push_back(mFileDialog.filename().toUtf8().constData()); | ||||
| 
 | ||||
|     CSMDoc::Document *document = mDocumentManager.addDocument (files, savePath, true); | ||||
|     mDocumentManager.addDocument (files, savePath, true); | ||||
| 
 | ||||
|     mViewManager.addView (document); | ||||
|     mFileDialog.hide(); | ||||
| } | ||||
| 
 | ||||
|  | @ -178,9 +192,7 @@ void CS::Editor::createNewGame (const boost::filesystem::path& file) | |||
| 
 | ||||
|     files.push_back (file); | ||||
| 
 | ||||
|     CSMDoc::Document *document = mDocumentManager.addDocument (files, file, true); | ||||
| 
 | ||||
|     mViewManager.addView (document); | ||||
|     mDocumentManager.addDocument (files, file, true); | ||||
| 
 | ||||
|     mNewGame.hide(); | ||||
| } | ||||
|  | @ -287,3 +299,13 @@ std::auto_ptr<sh::Factory> CS::Editor::setupGraphics() | |||
| 
 | ||||
|     return factory; | ||||
| } | ||||
| 
 | ||||
| void CS::Editor::documentAdded (CSMDoc::Document *document) | ||||
| { | ||||
|     mViewManager.addView (document); | ||||
| } | ||||
| 
 | ||||
| void CS::Editor::lastDocumentDeleted() | ||||
| { | ||||
|     exit (0); | ||||
| } | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| #include "view/doc/filedialog.hpp" | ||||
| #include "view/doc/newgame.hpp" | ||||
| 
 | ||||
| #include "view/settings/usersettingsdialog.hpp" | ||||
| #include "view/settings/dialog.hpp" | ||||
| 
 | ||||
| namespace OgreInit | ||||
| { | ||||
|  | @ -43,7 +43,7 @@ namespace CS | |||
|             CSVDoc::ViewManager mViewManager; | ||||
|             CSVDoc::StartupDialogue mStartup; | ||||
|             CSVDoc::NewGameDialogue mNewGame; | ||||
|             CSVSettings::UserSettingsDialog mSettings; | ||||
|             CSVSettings::Dialog mSettings; | ||||
|             CSVDoc::FileDialog mFileDialog; | ||||
|             boost::filesystem::path mLocal; | ||||
|             boost::filesystem::path mResources; | ||||
|  | @ -85,6 +85,10 @@ namespace CS | |||
| 
 | ||||
|             void showSettings(); | ||||
| 
 | ||||
|             void documentAdded (CSMDoc::Document *document); | ||||
| 
 | ||||
|             void lastDocumentDeleted(); | ||||
| 
 | ||||
|         private: | ||||
| 
 | ||||
|             QString mIpcServerName; | ||||
|  |  | |||
|  | @ -3,18 +3,24 @@ | |||
| 
 | ||||
| #include <exception> | ||||
| #include <iostream> | ||||
| #include <string> | ||||
| 
 | ||||
| #include <QApplication> | ||||
| #include <QIcon> | ||||
| #include <QMetaType> | ||||
| 
 | ||||
| #include <extern/shiny/Main/Factory.hpp> | ||||
| 
 | ||||
| #include <components/ogreinit/ogreinit.hpp> | ||||
| 
 | ||||
| #include "model/world/universalid.hpp" | ||||
| 
 | ||||
| #ifdef Q_OS_MAC | ||||
| #include <QDir> | ||||
| #endif | ||||
| 
 | ||||
| Q_DECLARE_METATYPE (std::string) | ||||
| 
 | ||||
| class Application : public QApplication | ||||
| { | ||||
|     private: | ||||
|  | @ -42,6 +48,9 @@ int main(int argc, char *argv[]) | |||
| { | ||||
|     Q_INIT_RESOURCE (resources); | ||||
| 
 | ||||
|     qRegisterMetaType<std::string> ("std::string"); | ||||
|     qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId"); | ||||
| 
 | ||||
|     OgreInit::OgreInit ogreInit; | ||||
| 
 | ||||
|     std::auto_ptr<sh::Factory> shinyFactory; | ||||
|  |  | |||
|  | @ -8,23 +8,6 @@ | |||
| #include <components/files/configurationmanager.hpp> | ||||
| #endif | ||||
| 
 | ||||
| void CSMDoc::Document::load (const std::vector<boost::filesystem::path>::const_iterator& begin, | ||||
|                              const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified) | ||||
| { | ||||
|     assert (begin!=end); | ||||
| 
 | ||||
|     std::vector<boost::filesystem::path>::const_iterator end2 (end); | ||||
| 
 | ||||
|     if (lastAsModified) | ||||
|         --end2; | ||||
| 
 | ||||
|     for (std::vector<boost::filesystem::path>::const_iterator iter (begin); iter!=end2; ++iter) | ||||
|         getData().loadFile (*iter, true, false); | ||||
| 
 | ||||
|     if (lastAsModified) | ||||
|         getData().loadFile (*end2, false, false); | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::Document::addGmsts() | ||||
| { | ||||
|     static const char *gmstFloats[] = | ||||
|  | @ -2219,64 +2202,42 @@ void CSMDoc::Document::createBase() | |||
|     } | ||||
| } | ||||
| 
 | ||||
| CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, const std::vector< boost::filesystem::path >& files, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, bool new_) | ||||
|     : mSavePath (savePath), mContentFiles (files), mTools (mData), mResDir(resDir), | ||||
|       mProjectPath ((configuration.getUserDataPath() / "projects") / | ||||
|                     (savePath.filename().string() + ".project")), | ||||
|       mSaving (*this, mProjectPath) | ||||
| CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, | ||||
|     const std::vector< boost::filesystem::path >& files, bool new_, | ||||
|     const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, | ||||
|     ToUTF8::FromType encoding) | ||||
| : mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding), mTools (mData), | ||||
|   mResDir(resDir), | ||||
|   mProjectPath ((configuration.getUserDataPath() / "projects") / | ||||
|   (savePath.filename().string() + ".project")), | ||||
|   mSaving (*this, mProjectPath, encoding) | ||||
| { | ||||
|     if (files.empty()) | ||||
|     if (mContentFiles.empty()) | ||||
|         throw std::runtime_error ("Empty content file sequence"); | ||||
| 
 | ||||
|     if (new_ && files.size()==1) | ||||
|         createBase(); | ||||
|     else | ||||
|     { | ||||
|         std::vector<boost::filesystem::path>::const_iterator end = files.end(); | ||||
| 
 | ||||
|         if (new_) | ||||
|             --end; | ||||
| 
 | ||||
|         load (files.begin(), end, !new_); | ||||
|     } | ||||
| 
 | ||||
|     if (new_) | ||||
|     { | ||||
|         mData.setDescription (""); | ||||
|         mData.setAuthor (""); | ||||
|     } | ||||
| 
 | ||||
|     bool filtersFound = false; | ||||
| 
 | ||||
|     if (boost::filesystem::exists (mProjectPath)) | ||||
|     { | ||||
|         filtersFound = true; | ||||
|     } | ||||
|     else | ||||
|     if (!boost::filesystem::exists (mProjectPath)) | ||||
|     { | ||||
|         boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath()); | ||||
|         locCustomFiltersPath /= "defaultfilters"; | ||||
| 
 | ||||
|         if (boost::filesystem::exists(locCustomFiltersPath)) | ||||
|         if (boost::filesystem::exists (locCustomFiltersPath)) | ||||
|         { | ||||
|             boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath); | ||||
|             filtersFound = true; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             boost::filesystem::path filters(mResDir); | ||||
|             filters /= "defaultfilters"; | ||||
| 
 | ||||
|             if (boost::filesystem::exists(filters)) | ||||
|             { | ||||
|                 boost::filesystem::copy_file(filters, mProjectPath); | ||||
|                 filtersFound = true; | ||||
|             } | ||||
|             boost::filesystem::copy_file (mResDir / "defaultfilters", mProjectPath); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (filtersFound) | ||||
|         getData().loadFile (mProjectPath, false, true); | ||||
|     if (mNew) | ||||
|     { | ||||
|         mData.setDescription (""); | ||||
|         mData.setAuthor (""); | ||||
| 
 | ||||
|         if (mContentFiles.size()==1) | ||||
|             createBase(); | ||||
|     } | ||||
| 
 | ||||
|     addOptionalGmsts(); | ||||
|     addOptionalGlobals(); | ||||
|  | @ -2288,8 +2249,10 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, co | |||
| 
 | ||||
|     connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); | ||||
|     connect (&mSaving, SIGNAL (done (int)), this, SLOT (operationDone (int))); | ||||
|     connect (&mSaving, SIGNAL (reportMessage (const QString&, int)), | ||||
|              this, SLOT (reportMessage (const QString&, int))); | ||||
| 
 | ||||
|     connect ( | ||||
|         &mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), | ||||
|         this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int))); | ||||
| } | ||||
| 
 | ||||
| CSMDoc::Document::~Document() | ||||
|  | @ -2322,11 +2285,21 @@ const boost::filesystem::path& CSMDoc::Document::getSavePath() const | |||
|     return mSavePath; | ||||
| } | ||||
| 
 | ||||
| const boost::filesystem::path& CSMDoc::Document::getProjectPath() const | ||||
| { | ||||
|     return mProjectPath; | ||||
| } | ||||
| 
 | ||||
| const std::vector<boost::filesystem::path>& CSMDoc::Document::getContentFiles() const | ||||
| { | ||||
|     return mContentFiles; | ||||
| } | ||||
| 
 | ||||
| bool CSMDoc::Document::isNew() const | ||||
| { | ||||
|     return mNew; | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::Document::save() | ||||
| { | ||||
|     if (mSaving.isRunning()) | ||||
|  | @ -2358,10 +2331,11 @@ void CSMDoc::Document::modificationStateChanged (bool clean) | |||
|     emit stateChanged (getState(), this); | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::Document::reportMessage (const QString& message, int type) | ||||
| void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message, | ||||
|     int type) | ||||
| { | ||||
|     /// \todo find a better way to get these messages to the user.
 | ||||
|     std::cout << message.toUtf8().constData() << std::endl; | ||||
|     std::cout << message << std::endl; | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::Document::operationDone (int type) | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ | |||
| #include <QObject> | ||||
| #include <QTimer> | ||||
| 
 | ||||
| #include <components/to_utf8/to_utf8.hpp> | ||||
| 
 | ||||
| #include "../world/data.hpp" | ||||
| 
 | ||||
| #include "../tools/tools.hpp" | ||||
|  | @ -39,6 +41,7 @@ namespace CSMDoc | |||
| 
 | ||||
|             boost::filesystem::path mSavePath; | ||||
|             std::vector<boost::filesystem::path> mContentFiles; | ||||
|             bool mNew; | ||||
|             CSMWorld::Data mData; | ||||
|             CSMTools::Tools mTools; | ||||
|             boost::filesystem::path mProjectPath; | ||||
|  | @ -53,10 +56,6 @@ namespace CSMDoc | |||
|             Document (const Document&); | ||||
|             Document& operator= (const Document&); | ||||
| 
 | ||||
|             void load (const std::vector<boost::filesystem::path>::const_iterator& begin, | ||||
|                 const std::vector<boost::filesystem::path>::const_iterator& end, bool lastAsModified); | ||||
|             ///< \param lastAsModified Store the last file in Modified instead of merging it into Base.
 | ||||
| 
 | ||||
|             void createBase(); | ||||
| 
 | ||||
|             void addGmsts(); | ||||
|  | @ -72,9 +71,9 @@ namespace CSMDoc | |||
|         public: | ||||
| 
 | ||||
|             Document (const Files::ConfigurationManager& configuration, | ||||
|                       const std::vector< boost::filesystem::path >& files, | ||||
|                       const boost::filesystem::path& savePath, | ||||
|                       const boost::filesystem::path& resDir, bool new_); | ||||
|                 const std::vector< boost::filesystem::path >& files, bool new_, | ||||
|                 const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, | ||||
|                 ToUTF8::FromType encoding); | ||||
| 
 | ||||
|             ~Document(); | ||||
| 
 | ||||
|  | @ -84,10 +83,15 @@ namespace CSMDoc | |||
| 
 | ||||
|             const boost::filesystem::path& getSavePath() const; | ||||
| 
 | ||||
|             const boost::filesystem::path& getProjectPath() const; | ||||
| 
 | ||||
|             const std::vector<boost::filesystem::path>& getContentFiles() const; | ||||
|             ///< \attention The last element in this collection is the file that is being edited,
 | ||||
|             /// but with its original path instead of the save path.
 | ||||
| 
 | ||||
|             bool isNew() const; | ||||
|             ///< Is this a newly created content file?
 | ||||
| 
 | ||||
|             void save(); | ||||
| 
 | ||||
|             CSMWorld::UniversalId verify(); | ||||
|  | @ -111,7 +115,8 @@ namespace CSMDoc | |||
| 
 | ||||
|             void modificationStateChanged (bool clean); | ||||
| 
 | ||||
|             void reportMessage (const QString& message, int type); | ||||
|             void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, | ||||
|                 int type); | ||||
| 
 | ||||
|             void operationDone (int type); | ||||
| 
 | ||||
|  |  | |||
|  | @ -13,44 +13,88 @@ | |||
| #include "document.hpp" | ||||
| 
 | ||||
| CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) | ||||
| : mConfiguration (configuration) | ||||
| : mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252) | ||||
| { | ||||
|     boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; | ||||
| 
 | ||||
|     if (!boost::filesystem::is_directory (projectPath)) | ||||
|         boost::filesystem::create_directories (projectPath); | ||||
| 
 | ||||
|     mLoader.moveToThread (&mLoaderThread); | ||||
|     mLoaderThread.start(); | ||||
| 
 | ||||
|     connect (&mLoader, SIGNAL (documentLoaded (Document *)), | ||||
|         this, SLOT (documentLoaded (Document *))); | ||||
|     connect (&mLoader, SIGNAL (documentNotLoaded (Document *, const std::string&)), | ||||
|         this, SLOT (documentNotLoaded (Document *, const std::string&))); | ||||
|     connect (this, SIGNAL (loadRequest (CSMDoc::Document *)), | ||||
|         &mLoader, SLOT (loadDocument (CSMDoc::Document *))); | ||||
|     connect (&mLoader, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)), | ||||
|         this, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int))); | ||||
|     connect (&mLoader, SIGNAL (nextRecord (CSMDoc::Document *)), | ||||
|         this, SIGNAL (nextRecord (CSMDoc::Document *))); | ||||
|     connect (this, SIGNAL (cancelLoading (CSMDoc::Document *)), | ||||
|         &mLoader, SLOT (abortLoading (CSMDoc::Document *))); | ||||
|     connect (&mLoader, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)), | ||||
|         this, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&))); | ||||
| } | ||||
| 
 | ||||
| CSMDoc::DocumentManager::~DocumentManager() | ||||
| { | ||||
|     mLoaderThread.quit(); | ||||
|     mLoader.hasThingsToDo().wakeAll(); | ||||
|     mLoaderThread.wait(); | ||||
| 
 | ||||
|     for (std::vector<Document *>::iterator iter (mDocuments.begin()); iter!=mDocuments.end(); ++iter) | ||||
|         delete *iter; | ||||
| } | ||||
| 
 | ||||
| CSMDoc::Document *CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath, | ||||
| void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath, | ||||
|     bool new_) | ||||
| { | ||||
|     Document *document = new Document (mConfiguration, files, savePath, mResDir, new_); | ||||
|     Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding); | ||||
| 
 | ||||
|     mDocuments.push_back (document); | ||||
| 
 | ||||
|     return document; | ||||
|     emit loadRequest (document); | ||||
| 
 | ||||
|     mLoader.hasThingsToDo().wakeAll(); | ||||
| } | ||||
| 
 | ||||
| bool CSMDoc::DocumentManager::removeDocument (Document *document) | ||||
| void CSMDoc::DocumentManager::removeDocument (CSMDoc::Document *document) | ||||
| { | ||||
|     std::vector<Document *>::iterator iter = std::find (mDocuments.begin(), mDocuments.end(), document); | ||||
| 
 | ||||
|     if (iter==mDocuments.end()) | ||||
|             throw std::runtime_error ("removing invalid document"); | ||||
|         throw std::runtime_error ("removing invalid document"); | ||||
| 
 | ||||
|     mDocuments.erase (iter); | ||||
|     delete document; | ||||
| 
 | ||||
|     return mDocuments.empty(); | ||||
|     if (mDocuments.empty()) | ||||
|         emit lastDocumentDeleted(); | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::DocumentManager::setResourceDir (const boost::filesystem::path& parResDir) | ||||
| { | ||||
|     mResDir = boost::filesystem::system_complete(parResDir); | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding) | ||||
| { | ||||
|     mEncoding = encoding; | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::DocumentManager::documentLoaded (Document *document) | ||||
| { | ||||
|     emit documentAdded (document); | ||||
|     emit loadingStopped (document, true, ""); | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std::string& error) | ||||
| { | ||||
|     emit loadingStopped (document, false, error); | ||||
| 
 | ||||
|     if (error.empty()) // do not remove the document yet, if we have an error
 | ||||
|         removeDocument (document); | ||||
| } | ||||
|  | @ -6,6 +6,13 @@ | |||
| 
 | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| #include <QObject> | ||||
| #include <QThread> | ||||
| 
 | ||||
| #include <components/to_utf8/to_utf8.hpp> | ||||
| 
 | ||||
| #include "loader.hpp" | ||||
| 
 | ||||
| namespace Files | ||||
| { | ||||
|     class ConfigurationManager; | ||||
|  | @ -15,10 +22,15 @@ namespace CSMDoc | |||
| { | ||||
|     class Document; | ||||
| 
 | ||||
|     class DocumentManager | ||||
|     class DocumentManager : public QObject | ||||
|     { | ||||
|             Q_OBJECT | ||||
| 
 | ||||
|             std::vector<Document *> mDocuments; | ||||
|             const Files::ConfigurationManager& mConfiguration; | ||||
|             QThread mLoaderThread; | ||||
|             Loader mLoader; | ||||
|             ToUTF8::FromType mEncoding; | ||||
| 
 | ||||
|             DocumentManager (const DocumentManager&); | ||||
|             DocumentManager& operator= (const DocumentManager&); | ||||
|  | @ -29,20 +41,51 @@ namespace CSMDoc | |||
| 
 | ||||
|             ~DocumentManager(); | ||||
| 
 | ||||
|             Document *addDocument (const std::vector< boost::filesystem::path >& files, | ||||
|                                    const boost::filesystem::path& savePath, | ||||
|                                    bool new_); | ||||
|             ///< The ownership of the returned document is not transferred to the caller.
 | ||||
|             ///
 | ||||
|             /// \param new_ Do not load the last content file in \a files and instead create in an
 | ||||
|             void addDocument (const std::vector< boost::filesystem::path >& files, | ||||
|                 const boost::filesystem::path& savePath, bool new_); | ||||
|             ///< \param new_ Do not load the last content file in \a files and instead create in an
 | ||||
|             /// appropriate way.
 | ||||
| 
 | ||||
|             bool removeDocument (Document *document); | ||||
|             ///< \return last document removed?
 | ||||
| 	    void setResourceDir (const boost::filesystem::path& parResDir); | ||||
| 	     | ||||
|     private: | ||||
| 
 | ||||
|             void setEncoding (ToUTF8::FromType encoding); | ||||
| 
 | ||||
|         private: | ||||
| 
 | ||||
| 	    boost::filesystem::path mResDir; | ||||
| 
 | ||||
|         private slots: | ||||
| 
 | ||||
|             void documentLoaded (Document *document); | ||||
|             ///< The ownership of \a document is not transferred.
 | ||||
| 
 | ||||
|             void documentNotLoaded (Document *document, const std::string& error); | ||||
|             ///< Document load has been interrupted either because of a call to abortLoading
 | ||||
|             /// or a problem during loading). In the former case error will be an empty string.
 | ||||
| 
 | ||||
|         public slots: | ||||
| 
 | ||||
|             void removeDocument (CSMDoc::Document *document); | ||||
|             ///< Emits the lastDocumentDeleted signal, if applicable.
 | ||||
| 
 | ||||
|         signals: | ||||
| 
 | ||||
|             void documentAdded (CSMDoc::Document *document); | ||||
| 
 | ||||
|             void loadRequest (CSMDoc::Document *document); | ||||
| 
 | ||||
|             void lastDocumentDeleted(); | ||||
| 
 | ||||
|             void loadingStopped (CSMDoc::Document *document, bool completed, | ||||
|                 const std::string& error); | ||||
| 
 | ||||
|             void nextStage (CSMDoc::Document *document, const std::string& name, int steps); | ||||
| 
 | ||||
|             void nextRecord (CSMDoc::Document *document); | ||||
| 
 | ||||
|             void cancelLoading (CSMDoc::Document *document); | ||||
| 
 | ||||
|             void loadMessage (CSMDoc::Document *document, const std::string& message); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										130
									
								
								apps/opencs/model/doc/loader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								apps/opencs/model/doc/loader.cpp
									
									
									
									
									
										Normal 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; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										71
									
								
								apps/opencs/model/doc/loader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								apps/opencs/model/doc/loader.hpp
									
									
									
									
									
										Normal 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 | ||||
|  | @ -6,6 +6,8 @@ | |||
| 
 | ||||
| #include <QTimer> | ||||
| 
 | ||||
| #include "../world/universalid.hpp" | ||||
| 
 | ||||
| #include "state.hpp" | ||||
| #include "stage.hpp" | ||||
| 
 | ||||
|  | @ -80,7 +82,7 @@ void CSMDoc::Operation::abort() | |||
| 
 | ||||
| void CSMDoc::Operation::executeStage() | ||||
| { | ||||
|     std::vector<std::string> messages; | ||||
|     Stage::Messages messages; | ||||
| 
 | ||||
|     while (mCurrentStage!=mStages.end()) | ||||
|     { | ||||
|  | @ -97,7 +99,7 @@ void CSMDoc::Operation::executeStage() | |||
|             } | ||||
|             catch (const std::exception& e) | ||||
|             { | ||||
|                 emit reportMessage (e.what(), mType); | ||||
|                 emit reportMessage (CSMWorld::UniversalId(), e.what(), mType); | ||||
|                 abort(); | ||||
|             } | ||||
| 
 | ||||
|  | @ -108,8 +110,8 @@ void CSMDoc::Operation::executeStage() | |||
| 
 | ||||
|     emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); | ||||
| 
 | ||||
|     for (std::vector<std::string>::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter) | ||||
|         emit reportMessage (iter->c_str(), mType); | ||||
|     for (Stage::Messages::const_iterator iter (messages.begin()); iter!=messages.end(); ++iter) | ||||
|         emit reportMessage (iter->first, iter->second, mType); | ||||
| 
 | ||||
|     if (mCurrentStage==mStages.end()) | ||||
|         exit(); | ||||
|  |  | |||
|  | @ -5,6 +5,11 @@ | |||
| 
 | ||||
| #include <QThread> | ||||
| 
 | ||||
| namespace CSMWorld | ||||
| { | ||||
|     class UniversalId; | ||||
| } | ||||
| 
 | ||||
| namespace CSMDoc | ||||
| { | ||||
|     class Stage; | ||||
|  | @ -46,7 +51,8 @@ namespace CSMDoc | |||
| 
 | ||||
|             void progress (int current, int max, int type); | ||||
| 
 | ||||
|             void reportMessage (const QString& message, int type); | ||||
|             void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, | ||||
|                 int type); | ||||
| 
 | ||||
|             void done (int type); | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,8 +8,9 @@ | |||
| #include "savingstages.hpp" | ||||
| #include "document.hpp" | ||||
| 
 | ||||
| CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath) | ||||
| : Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath) | ||||
| CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& projectPath, | ||||
|     ToUTF8::FromType encoding) | ||||
| : Operation (State_Saving, true, true), mDocument (document), mState (*this, projectPath, encoding) | ||||
| { | ||||
|     // save project file
 | ||||
|     appendStage (new OpenSaveStage (mDocument, mState, true)); | ||||
|  | @ -64,7 +65,11 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje | |||
| 
 | ||||
|     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 FinalSavingStage (mDocument, mState)); | ||||
|  |  | |||
|  | @ -3,6 +3,8 @@ | |||
| 
 | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| #include <components/to_utf8/to_utf8.hpp> | ||||
| 
 | ||||
| #include "operation.hpp" | ||||
| #include "savingstate.hpp" | ||||
| 
 | ||||
|  | @ -19,7 +21,8 @@ namespace CSMDoc | |||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             Saving (Document& document, const boost::filesystem::path& projectPath); | ||||
|             Saving (Document& document, const boost::filesystem::path& projectPath, | ||||
|                 ToUTF8::FromType encoding); | ||||
| 
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -9,6 +9,8 @@ | |||
| 
 | ||||
| #include <components/esm/loaddial.hpp> | ||||
| 
 | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include "../world/infocollection.hpp" | ||||
| 
 | ||||
| #include "document.hpp" | ||||
|  | @ -23,11 +25,13 @@ int CSMDoc::OpenSaveStage::setup() | |||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::OpenSaveStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMDoc::OpenSaveStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     mState.start (mDocument, mProjectFile); | ||||
| 
 | ||||
|     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()) | ||||
|         throw std::runtime_error ("failed to open stream for saving"); | ||||
|  | @ -43,7 +47,7 @@ int CSMDoc::WriteHeaderStage::setup() | |||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::WriteHeaderStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     mState.getWriter().setVersion(); | ||||
| 
 | ||||
|  | @ -96,7 +100,7 @@ int CSMDoc::WriteDialogueCollectionStage::setup() | |||
|     return mTopics.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::WriteDialogueCollectionStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMDoc::WriteDialogueCollectionStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Dialogue>& topic = mTopics.getRecord (stage); | ||||
| 
 | ||||
|  | @ -191,7 +195,7 @@ int CSMDoc::WriteRefIdCollectionStage::setup() | |||
|     return mDocument.getData().getReferenceables().getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::WriteRefIdCollectionStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMDoc::WriteRefIdCollectionStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     mDocument.getData().getReferenceables().save (stage, mState.getWriter()); | ||||
| } | ||||
|  | @ -204,7 +208,7 @@ CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& sta | |||
|   mDocument (document), mScope (scope) | ||||
| {} | ||||
| 
 | ||||
| void CSMDoc::WriteFilterStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<CSMFilter::Filter>& record = | ||||
|         mDocument.getData().getFilters().getRecord (stage); | ||||
|  | @ -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) | ||||
| : mState (state) | ||||
| {} | ||||
|  | @ -223,7 +364,7 @@ int CSMDoc::CloseSaveStage::setup() | |||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::CloseSaveStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMDoc::CloseSaveStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     mState.getStream().close(); | ||||
| 
 | ||||
|  | @ -241,7 +382,7 @@ int CSMDoc::FinalSavingStage::setup() | |||
|     return 1; | ||||
| } | ||||
| 
 | ||||
| void CSMDoc::FinalSavingStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMDoc::FinalSavingStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     if (mState.hasError()) | ||||
|     { | ||||
|  | @ -260,4 +401,4 @@ void CSMDoc::FinalSavingStage::perform (int stage, std::vector<std::string>& mes | |||
| 
 | ||||
|         mDocument.getUndoStack().setClean(); | ||||
|     } | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -39,7 +39,7 @@ namespace CSMDoc | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| 
 | ||||
|  | @ -57,7 +57,7 @@ namespace CSMDoc | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| 
 | ||||
|  | @ -75,7 +75,7 @@ namespace CSMDoc | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| 
 | ||||
|  | @ -92,7 +92,7 @@ namespace CSMDoc | |||
|     } | ||||
| 
 | ||||
|     template<class CollectionT> | ||||
|     void WriteCollectionStage<CollectionT>::perform (int stage, std::vector<std::string>& messages) | ||||
|     void WriteCollectionStage<CollectionT>::perform (int stage, Messages& messages) | ||||
|     { | ||||
|         CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; | ||||
| 
 | ||||
|  | @ -130,7 +130,7 @@ namespace CSMDoc | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| 
 | ||||
|  | @ -147,7 +147,7 @@ namespace CSMDoc | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| 
 | ||||
|  | @ -161,10 +161,42 @@ namespace CSMDoc | |||
| 
 | ||||
|             WriteFilterStage (Document& document, SavingState& state, CSMFilter::Filter::Scope scope); | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
| 
 | ||||
|     }; | ||||
| 
 | ||||
|     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.
 | ||||
|     }; | ||||
| 
 | ||||
|     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 | ||||
|     { | ||||
|  | @ -177,7 +209,7 @@ namespace CSMDoc | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| 
 | ||||
|  | @ -193,7 +225,7 @@ namespace CSMDoc | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -4,11 +4,9 @@ | |||
| #include "operation.hpp" | ||||
| #include "document.hpp" | ||||
| 
 | ||||
| CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath) | ||||
| : mOperation (operation), | ||||
|    /// \todo set encoding properly, once config implementation has been fixed.
 | ||||
|   mEncoder (ToUTF8::calculateEncoding ("win1252")), | ||||
|   mProjectPath (projectPath), mProjectFile (false) | ||||
| CSMDoc::SavingState::SavingState (Operation& operation, const boost::filesystem::path& projectPath, | ||||
|     ToUTF8::FromType encoding) | ||||
| : mOperation (operation), mEncoder (encoding),  mProjectPath (projectPath), mProjectFile (false) | ||||
| { | ||||
|     mWriter.setEncoder (&mEncoder); | ||||
| } | ||||
|  | @ -27,6 +25,8 @@ void CSMDoc::SavingState::start (Document& document, bool project) | |||
| 
 | ||||
|     mStream.clear(); | ||||
| 
 | ||||
|     mSubRecords.clear(); | ||||
| 
 | ||||
|     if (project) | ||||
|         mPath = mProjectPath; | ||||
|     else | ||||
|  | @ -49,7 +49,7 @@ const boost::filesystem::path& CSMDoc::SavingState::getTmpPath() const | |||
|     return mTmpPath; | ||||
| } | ||||
| 
 | ||||
| std::ofstream& CSMDoc::SavingState::getStream() | ||||
| boost::filesystem::ofstream& CSMDoc::SavingState::getStream() | ||||
| { | ||||
|     return mStream; | ||||
| } | ||||
|  | @ -62,4 +62,9 @@ ESM::ESMWriter& CSMDoc::SavingState::getWriter() | |||
| bool CSMDoc::SavingState::isProjectFile() const | ||||
| { | ||||
|     return mProjectFile; | ||||
| } | ||||
| } | ||||
| 
 | ||||
| std::map<std::string, std::vector<int> >& CSMDoc::SavingState::getSubRecords() | ||||
| { | ||||
|     return mSubRecords; | ||||
| } | ||||
|  |  | |||
|  | @ -2,11 +2,15 @@ | |||
| #define CSM_DOC_SAVINGSTATE_H | ||||
| 
 | ||||
| #include <fstream> | ||||
| #include <map> | ||||
| 
 | ||||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem/fstream.hpp> | ||||
| 
 | ||||
| #include <components/esm/esmwriter.hpp> | ||||
| 
 | ||||
| #include <components/to_utf8/to_utf8.hpp> | ||||
| 
 | ||||
| namespace CSMDoc | ||||
| { | ||||
|     class Operation; | ||||
|  | @ -18,14 +22,16 @@ namespace CSMDoc | |||
|             boost::filesystem::path mPath; | ||||
|             boost::filesystem::path mTmpPath; | ||||
|             ToUTF8::Utf8Encoder mEncoder; | ||||
|             std::ofstream mStream; | ||||
|             boost::filesystem::ofstream mStream; | ||||
|             ESM::ESMWriter mWriter; | ||||
|             boost::filesystem::path mProjectPath; | ||||
|             bool mProjectFile; | ||||
|             std::map<std::string, std::vector<int> > mSubRecords; // record ID, list of subrecords
 | ||||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             SavingState (Operation& operation, const boost::filesystem::path& projectPath); | ||||
|             SavingState (Operation& operation, const boost::filesystem::path& projectPath, | ||||
|                 ToUTF8::FromType encoding); | ||||
| 
 | ||||
|             bool hasError() const; | ||||
| 
 | ||||
|  | @ -36,15 +42,17 @@ namespace CSMDoc | |||
| 
 | ||||
|             const boost::filesystem::path& getTmpPath() const; | ||||
| 
 | ||||
|             std::ofstream& getStream(); | ||||
|             boost::filesystem::ofstream& getStream(); | ||||
| 
 | ||||
|             ESM::ESMWriter& getWriter(); | ||||
| 
 | ||||
|             bool isProjectFile() const; | ||||
|             ///< Currently saving project file? (instead of content file)
 | ||||
| 
 | ||||
|             std::map<std::string, std::vector<int> >& getSubRecords(); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
| #endif | ||||
|  |  | |||
|  | @ -4,18 +4,22 @@ | |||
| #include <vector> | ||||
| #include <string> | ||||
| 
 | ||||
| #include "../world/universalid.hpp" | ||||
| 
 | ||||
| namespace CSMDoc | ||||
| { | ||||
|     class Stage | ||||
|     { | ||||
|         public: | ||||
| 
 | ||||
|             typedef std::vector<std::pair<CSMWorld::UniversalId, std::string> > Messages; | ||||
| 
 | ||||
|             virtual ~Stage(); | ||||
| 
 | ||||
|             virtual int setup() = 0; | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages) = 0; | ||||
|             virtual void perform (int stage, Messages& messages) = 0; | ||||
|             ///< Messages resulting from this stage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -3,17 +3,18 @@ | |||
| 
 | ||||
| namespace CSMDoc | ||||
| { | ||||
|         enum State | ||||
|         { | ||||
|                 State_Modified = 1, | ||||
|                 State_Locked = 2, | ||||
|                 State_Operation = 4, | ||||
|     enum State | ||||
|     { | ||||
|         State_Modified = 1, | ||||
|         State_Locked = 2, | ||||
|         State_Operation = 4, | ||||
| 
 | ||||
|                 State_Saving = 8, | ||||
|                 State_Verifying = 16, | ||||
|                 State_Compiling = 32, // not implemented yet
 | ||||
|                 State_Searching = 64 // not implemented yet
 | ||||
|         }; | ||||
|         State_Saving = 8, | ||||
|         State_Verifying = 16, | ||||
|         State_Compiling = 32, // not implemented yet
 | ||||
|         State_Searching = 64, // not implemented yet
 | ||||
|         State_Loading = 128   // pseudo-state; can not be encountered in a loaded document
 | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
							
								
								
									
										128
									
								
								apps/opencs/model/settings/connector.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								apps/opencs/model/settings/connector.cpp
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
							
								
								
									
										67
									
								
								apps/opencs/model/settings/connector.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								apps/opencs/model/settings/connector.hpp
									
									
									
									
									
										Normal 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
 | ||||
							
								
								
									
										391
									
								
								apps/opencs/model/settings/setting.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										391
									
								
								apps/opencs/model/settings/setting.cpp
									
									
									
									
									
										Normal 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); | ||||
| } | ||||
							
								
								
									
										150
									
								
								apps/opencs/model/settings/setting.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								apps/opencs/model/settings/setting.hpp
									
									
									
									
									
										Normal 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
 | ||||
|  | @ -1,82 +0,0 @@ | |||
| #include "settingcontainer.hpp" | ||||
| 
 | ||||
| #include <QStringList> | ||||
| 
 | ||||
| CSMSettings::SettingContainer::SettingContainer(QObject *parent) : | ||||
|     QObject(parent), mValue (0), mValues (0) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| CSMSettings::SettingContainer::SettingContainer(const QString &value, QObject *parent) : | ||||
|     QObject(parent), mValue (new QString (value)), mValues (0) | ||||
| { | ||||
| } | ||||
| 
 | ||||
| void CSMSettings::SettingContainer::insert (const QString &value) | ||||
| { | ||||
|     if (mValue) | ||||
|     { | ||||
|         mValues = new QStringList; | ||||
|         mValues->push_back (*mValue); | ||||
|         mValues->push_back (value); | ||||
| 
 | ||||
|         delete mValue; | ||||
|         mValue = 0; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         delete mValue; | ||||
|         mValue = new QString (value); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void CSMSettings::SettingContainer::update (const QString &value, int index) | ||||
| { | ||||
|     if (isEmpty()) | ||||
|         mValue = new QString(value); | ||||
| 
 | ||||
|     else if (mValue) | ||||
|         *mValue = value; | ||||
| 
 | ||||
|     else if (mValues) | ||||
|         mValues->replace(index, value); | ||||
| } | ||||
| 
 | ||||
| QString CSMSettings::SettingContainer::getValue (int index) const | ||||
| { | ||||
|     QString retVal(""); | ||||
| 
 | ||||
|     //if mValue is valid, it's a single-value property.
 | ||||
|     //ignore the index and return the value
 | ||||
|     if (mValue) | ||||
|         retVal = *mValue; | ||||
| 
 | ||||
|     //otherwise, if it's a multivalued property
 | ||||
|     //return the appropriate value at the index
 | ||||
|     else if (mValues) | ||||
|     { | ||||
|         if (index == -1) | ||||
|             retVal = mValues->at(0); | ||||
| 
 | ||||
|         else if (index < mValues->size()) | ||||
|             retVal = mValues->at(index); | ||||
|     } | ||||
| 
 | ||||
|     return retVal; | ||||
| } | ||||
| 
 | ||||
| int CSMSettings::SettingContainer::count () const | ||||
| { | ||||
|     int retVal = 0; | ||||
| 
 | ||||
|     if (!isEmpty()) | ||||
|     { | ||||
|         if (mValues) | ||||
|             retVal = mValues->size(); | ||||
|         else | ||||
|             retVal = 1; | ||||
|     } | ||||
| 
 | ||||
|     return retVal; | ||||
| } | ||||
|  | @ -1,47 +0,0 @@ | |||
| #ifndef SETTINGCONTAINER_HPP | ||||
| #define SETTINGCONTAINER_HPP | ||||
| 
 | ||||
| #include <QObject> | ||||
| 
 | ||||
| class QStringList; | ||||
| 
 | ||||
| namespace CSMSettings | ||||
| { | ||||
|     class SettingContainer : public QObject | ||||
|     { | ||||
|         Q_OBJECT | ||||
| 
 | ||||
|         QString *mValue; | ||||
|         QStringList *mValues; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         explicit SettingContainer (QObject *parent = 0); | ||||
|         explicit SettingContainer (const QString &value, QObject *parent = 0); | ||||
| 
 | ||||
|         /// add a value to the container
 | ||||
|         /// multiple values supported
 | ||||
|         void insert (const QString &value); | ||||
| 
 | ||||
|         /// update an existing value
 | ||||
|         /// index specifies multiple values
 | ||||
|         void update (const QString &value, int index = 0); | ||||
| 
 | ||||
|         /// return value at specified index
 | ||||
|         QString getValue (int index = -1) const; | ||||
| 
 | ||||
|         /// retrieve list of all values
 | ||||
|         inline QStringList *getValues() const  { return mValues; } | ||||
| 
 | ||||
|         /// return size of list
 | ||||
|         int count() const; | ||||
| 
 | ||||
|         /// test for empty container
 | ||||
|         /// useful for default-constructed containers returned by QMap when invalid key is passed
 | ||||
|         inline bool isEmpty() const            { return (!mValue && !mValues); } | ||||
| 
 | ||||
|         inline bool isMultiValue() const       { return (mValues); } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| #endif // SETTINGCONTAINER_HPP
 | ||||
|  | @ -1,104 +0,0 @@ | |||
| #include "settingsitem.hpp" | ||||
| 
 | ||||
| #include <QStringList> | ||||
| 
 | ||||
| bool CSMSettings::SettingsItem::updateItem (const QStringList *values) | ||||
| { | ||||
|     QStringList::ConstIterator it = values->begin(); | ||||
| 
 | ||||
|     //if the item is not multivalued,
 | ||||
|     //save the last value passed in the container
 | ||||
|     if (!mIsMultiValue) | ||||
|     { | ||||
|         it = values->end(); | ||||
|         it--; | ||||
|     } | ||||
| 
 | ||||
|     bool isValid = true; | ||||
|     QString value (""); | ||||
| 
 | ||||
|     for (; it != values->end(); ++it) | ||||
|     { | ||||
|         value = *it; | ||||
|         isValid = validate(value); | ||||
| 
 | ||||
|         //skip only the invalid values
 | ||||
|         if (!isValid) | ||||
|             continue; | ||||
| 
 | ||||
|         insert(value); | ||||
|     } | ||||
| 
 | ||||
|     return isValid; | ||||
| } | ||||
| 
 | ||||
| bool CSMSettings::SettingsItem::updateItem (const QString &value) | ||||
| { | ||||
|     //takes a value or a SettingsContainer and updates itself accordingly
 | ||||
|     //after validating the data against it's own definition
 | ||||
| 
 | ||||
|     QString newValue = value; | ||||
| 
 | ||||
|     if (!validate (newValue)) | ||||
|         newValue = mDefaultValue; | ||||
| 
 | ||||
|     bool success = (getValue() != newValue); | ||||
| 
 | ||||
|     if (success) | ||||
|     { | ||||
|         if (mIsMultiValue) | ||||
|             insert (newValue); | ||||
|         else | ||||
|             update (newValue); | ||||
|     } | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
| bool CSMSettings::SettingsItem::updateItem(int valueListIndex) | ||||
| { | ||||
|     bool success = false; | ||||
| 
 | ||||
|     if (mValueList) | ||||
|     { | ||||
|         if (mValueList->size() > valueListIndex) | ||||
|             success = updateItem (mValueList->at(valueListIndex)); | ||||
|     } | ||||
|     return success; | ||||
| } | ||||
| 
 | ||||
| bool CSMSettings::SettingsItem::validate (const QString &value) | ||||
| { | ||||
|     //if there is no value list or value pair, there is no validation to do
 | ||||
|     bool isValid = !(!mValueList->isEmpty() || mValuePair); | ||||
| 
 | ||||
|     if (!isValid && !mValueList->isEmpty()) | ||||
|     { | ||||
|         for (QStringList::Iterator it = mValueList->begin(); it != mValueList->end(); ++it) | ||||
|     //    foreach (QString listItem, *mValueList)
 | ||||
|         { | ||||
|             isValid = (value == *it); | ||||
| 
 | ||||
|             if (isValid) | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|     else if (!isValid && mValuePair) | ||||
|     { | ||||
|         int numVal = value.toInt(); | ||||
| 
 | ||||
|         isValid = (numVal > mValuePair->left.toInt() && numVal < mValuePair->right.toInt()); | ||||
|     } | ||||
| 
 | ||||
|     return isValid; | ||||
| } | ||||
| 
 | ||||
| void CSMSettings::SettingsItem::setDefaultValue (const QString &value) | ||||
| { | ||||
|     mDefaultValue = value; | ||||
|     update (value); | ||||
| } | ||||
| 
 | ||||
| QString CSMSettings::SettingsItem::getDefaultValue() const | ||||
| { | ||||
|     return mDefaultValue; | ||||
| } | ||||
|  | @ -1,67 +0,0 @@ | |||
| #ifndef SETTINGSITEM_HPP | ||||
| #define SETTINGSITEM_HPP | ||||
| 
 | ||||
| #include <QObject> | ||||
| #include "support.hpp" | ||||
| #include "settingcontainer.hpp" | ||||
| 
 | ||||
| namespace CSMSettings | ||||
| { | ||||
|     /// Represents a setting including metadata
 | ||||
|     /// (valid values, ranges, defaults, and multivalue status
 | ||||
|     class SettingsItem : public SettingContainer | ||||
|     { | ||||
|         QStringPair *mValuePair; | ||||
|         QStringList *mValueList; | ||||
|         bool mIsMultiValue; | ||||
|         QString mDefaultValue; | ||||
| 
 | ||||
|     public: | ||||
|         explicit SettingsItem(QString name, bool isMultiValue, | ||||
|                               const QString& defaultValue, QObject *parent = 0) | ||||
|             : SettingContainer(defaultValue, parent), | ||||
|               mIsMultiValue (isMultiValue), mValueList (0), | ||||
|               mValuePair (0), mDefaultValue (defaultValue) | ||||
|         { | ||||
|             QObject::setObjectName(name); | ||||
|         } | ||||
| 
 | ||||
|         /// updateItem overloads for updating setting value
 | ||||
|         /// provided a list of values (multi-valued),
 | ||||
|         /// a specific value
 | ||||
|         /// or an index value corresponding to the mValueList
 | ||||
|         bool updateItem (const QStringList *values); | ||||
|         bool updateItem (const QString &value); | ||||
|         bool updateItem (int valueListIndex); | ||||
| 
 | ||||
|         /// retrieve list of valid values for setting
 | ||||
|         inline QStringList *getValueList()                  { return mValueList; } | ||||
| 
 | ||||
|         /// write list of valid values for setting
 | ||||
|         inline void setValueList (QStringList *valueList)   { mValueList = valueList; } | ||||
| 
 | ||||
|         /// valuePair used for spin boxes (max / min)
 | ||||
|         inline QStringPair *getValuePair()                  { return mValuePair; } | ||||
| 
 | ||||
|         /// set value range (spinbox / integer use)
 | ||||
|         inline void setValuePair (QStringPair valuePair) | ||||
|         { | ||||
|           delete mValuePair; | ||||
|           mValuePair = new QStringPair(valuePair); | ||||
|         } | ||||
| 
 | ||||
|         inline bool isMultivalue ()                         { return mIsMultiValue; } | ||||
| 
 | ||||
|         void setDefaultValue (const QString &value); | ||||
|         QString getDefaultValue () const; | ||||
| 
 | ||||
|     private: | ||||
| 
 | ||||
|         /// Verifies that the supplied value is one of the following:
 | ||||
|         ///  1.  Within the limits of the value pair (min / max)
 | ||||
|         ///  2.  One of the values indicated in the value list
 | ||||
|         bool validate (const QString &value); | ||||
|     }; | ||||
| } | ||||
| #endif // SETTINGSITEM_HPP
 | ||||
| 
 | ||||
|  | @ -1 +0,0 @@ | |||
| #include "support.hpp" | ||||
|  | @ -1,39 +1,145 @@ | |||
| #ifndef MODEL_SUPPORT_HPP | ||||
| #define MODEL_SUPPORT_HPP | ||||
| #ifndef SETTING_SUPPORT_HPP | ||||
| #define SETTING_SUPPORT_HPP | ||||
| 
 | ||||
| #include <QObject> | ||||
| #include <Qt> | ||||
| #include <QPair> | ||||
| #include <QList> | ||||
| #include <QVariant> | ||||
| #include <QStringList> | ||||
| 
 | ||||
| class QLayout; | ||||
| class QWidget; | ||||
| class QListWidgetItem; | ||||
| //Enums
 | ||||
| namespace CSMSettings | ||||
| { | ||||
|     ///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 | ||||
| { | ||||
|     class SettingContainer; | ||||
| 
 | ||||
|     typedef QList<SettingContainer *>          SettingList; | ||||
|     typedef QMap<QString, SettingContainer *>  SettingMap; | ||||
|     typedef QMap<QString, SettingMap *>        SectionMap; | ||||
| 
 | ||||
|     struct QStringPair | ||||
|     ///used to construct default settings in the Setting class
 | ||||
|     struct PropertyDefaultValues | ||||
|     { | ||||
|         QStringPair(): left (""), right ("") | ||||
|         {} | ||||
|         int id; | ||||
|         QString name; | ||||
|         QVariant value; | ||||
|     }; | ||||
| 
 | ||||
|         QStringPair (const QString &leftValue, const QString &rightValue) | ||||
|             : left (leftValue), right(rightValue) | ||||
|         {} | ||||
|     ///strings which correspond to setting values.  These strings represent
 | ||||
|     ///the script language keywords which would be used to declare setting
 | ||||
|     ///views for 3rd party addons
 | ||||
|     const QString sPropertyNames[] = | ||||
|     { | ||||
|         "name", "page", "setting_type", "is_multi_value", | ||||
|         "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) | ||||
|             : left (pair.left), right (pair.right) | ||||
|         {} | ||||
| 
 | ||||
|         QString left; | ||||
|         QString right; | ||||
| 
 | ||||
|         bool isEmpty() const | ||||
|         { return (left.isEmpty() && right.isEmpty()); } | ||||
|     ///Default values for a setting.  Used in setting creation.
 | ||||
|     const QString sPropertyDefaults[] = | ||||
|     { | ||||
|         "",         //name
 | ||||
|         "",         //page
 | ||||
|         "40",       //setting type
 | ||||
|         "false",    //multivalue
 | ||||
|         "false",    //multiline
 | ||||
|         "7",        //widget width
 | ||||
|         "-1",       //view row
 | ||||
|         "-1",       //view column
 | ||||
|         ",",        //delimiter
 | ||||
|         "true",     //serialized
 | ||||
|         "1",        //column span
 | ||||
|         "1",        //row span
 | ||||
|         "0",        //value range
 | ||||
|         "0",        //value minimum
 | ||||
|         "0",        //value maximum
 | ||||
|         "",         //special text
 | ||||
|         "",         //prefix
 | ||||
|         "",         //suffix
 | ||||
|         "false",    //wrapping
 | ||||
|         "1",        //tick interval
 | ||||
|         "false",    //ticks above
 | ||||
|         "true",     //ticks below
 | ||||
|         "",         //default values
 | ||||
|         "",         //declared values
 | ||||
|         "",         //defined values
 | ||||
|         ""          //proxy values
 | ||||
|     }; | ||||
| } | ||||
| #endif // MODEL_SUPPORT_HPP
 | ||||
| 
 | ||||
| #endif // VIEW_SUPPORT_HPP
 | ||||
|  |  | |||
|  | @ -1,19 +1,15 @@ | |||
| #include "usersettings.hpp" | ||||
| 
 | ||||
| #include <QTextStream> | ||||
| #include <QDir> | ||||
| #include <QString> | ||||
| #include <QRegExp> | ||||
| #include <QMap> | ||||
| #include <QMessageBox> | ||||
| #include <QTextCodec> | ||||
| 
 | ||||
| #include <QSettings> | ||||
| #include <QFile> | ||||
| 
 | ||||
| #include <components/files/configurationmanager.hpp> | ||||
| #include "settingcontainer.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 | ||||
|  */ | ||||
|  | @ -32,43 +28,250 @@ namespace boost | |||
| 
 | ||||
| CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0; | ||||
| 
 | ||||
| CSMSettings::UserSettings::UserSettings() | ||||
| CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager) | ||||
| : mCfgMgr (configurationManager) | ||||
| { | ||||
|     assert(!mUserSettingsInstance); | ||||
|     mUserSettingsInstance = this; | ||||
| 
 | ||||
|     mReadWriteMessage = QObject::tr("<br><b>Could not open or create file for writing</b><br><br> \
 | ||||
|             Please make sure you have the right permissions and try again.<br>"); | ||||
|     mSettingDefinitions = 0; | ||||
| 
 | ||||
|     mReadOnlyMessage = QObject::tr("<br><b>Could not open file for reading</b><br><br> \
 | ||||
|             Please make sure you have the right permissions and try again.<br>"); | ||||
| 
 | ||||
|     buildEditorSettingDefaults(); | ||||
|     buildSettingModelDefaults(); | ||||
| } | ||||
| 
 | ||||
| void CSMSettings::UserSettings::buildEditorSettingDefaults() | ||||
| void CSMSettings::UserSettings::buildSettingModelDefaults() | ||||
| { | ||||
|     SettingContainer *windowHeight = new SettingContainer("768", this); | ||||
|     SettingContainer *windowWidth = new SettingContainer("1024", this); | ||||
|     SettingContainer *rsDelegate = new SettingContainer("Icon and Text", this); | ||||
|     SettingContainer *refIdTypeDelegate = new SettingContainer("Icon and Text", this); | ||||
|     QString section = "Window Size"; | ||||
|     { | ||||
|         Setting *width = createSetting (Type_LineEdit, section, "Width"); | ||||
|         Setting *height = createSetting (Type_LineEdit, section, "Height"); | ||||
| 
 | ||||
|     windowHeight->setObjectName ("Height"); | ||||
|     windowWidth->setObjectName ("Width"); | ||||
|     rsDelegate->setObjectName ("Record Status Display"); | ||||
|     refIdTypeDelegate->setObjectName ("Referenceable ID Type Display"); | ||||
|         width->setWidgetWidth (5); | ||||
|         height->setWidgetWidth (8); | ||||
| 
 | ||||
|     SettingMap *displayFormatMap = new SettingMap; | ||||
|     SettingMap *windowSizeMap = new SettingMap; | ||||
|         width->setDefaultValues (QStringList() << "1024"); | ||||
|         height->setDefaultValues (QStringList() << "768"); | ||||
| 
 | ||||
|     displayFormatMap->insert (rsDelegate->objectName(), rsDelegate ); | ||||
|     displayFormatMap->insert (refIdTypeDelegate->objectName(), refIdTypeDelegate); | ||||
|         width->setEditorSetting (true); | ||||
|         height->setEditorSetting (true); | ||||
| 
 | ||||
|     windowSizeMap->insert (windowWidth->objectName(), windowWidth ); | ||||
|     windowSizeMap->insert (windowHeight->objectName(), windowHeight ); | ||||
|         height->setViewLocation (2,2); | ||||
|         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() | ||||
|  | @ -76,230 +279,62 @@ CSMSettings::UserSettings::~UserSettings() | |||
|     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 §ionName) 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 §ionSettings) | ||||
| { | ||||
|     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) | ||||
| { | ||||
|     mSectionSettings.clear(); | ||||
|     QString userFilePath = QString::fromUtf8 | ||||
|                                 (mCfgMgr.getUserConfigPath().string().c_str()); | ||||
| 
 | ||||
|     //global
 | ||||
|     QString globalFilePath = QString::fromStdString(mCfgMgr.getGlobalPath().string()) + fileName; | ||||
|     bool globalOk = loadFromFile(globalFilePath); | ||||
|     QString globalFilePath = QString::fromUtf8 | ||||
|                                 (mCfgMgr.getGlobalPath().string().c_str()); | ||||
| 
 | ||||
|     QString otherFilePath = globalFilePath; | ||||
| 
 | ||||
|     //local
 | ||||
|     QString localFilePath = QString::fromStdString(mCfgMgr.getLocalPath().string()) + fileName; | ||||
|     bool localOk = loadFromFile(localFilePath); | ||||
| 
 | ||||
|     //user
 | ||||
|     mUserFilePath = QString::fromStdString(mCfgMgr.getUserConfigPath().string()) + fileName; | ||||
|     loadFromFile(mUserFilePath); | ||||
| 
 | ||||
|     if (!(localOk || globalOk)) | ||||
|     //test for local only if global fails (uninstalled copy)
 | ||||
|     if (!QFile (globalFilePath + fileName).exists()) | ||||
|     { | ||||
|         QString message = QObject::tr("<br><b>Could not open user settings files for reading</b><br><br> \
 | ||||
|                 Global and local settings files could not be read.\ | ||||
|                 You may have incorrect file permissions or the OpenCS installation may be corrupted.<br>"); | ||||
| 
 | ||||
|         message += QObject::tr("<br>Global filepath: ") + globalFilePath; | ||||
|         message += QObject::tr("<br>Local filepath: ") + localFilePath; | ||||
| 
 | ||||
|         displayFileErrorMessage ( message, true); | ||||
|         //if global is invalid, use the local path
 | ||||
|         otherFilePath = QString::fromUtf8 | ||||
|                                     (mCfgMgr.getLocalPath().string().c_str()); | ||||
|     } | ||||
| 
 | ||||
|     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 §ionName, const QString &settingName) | ||||
| bool CSMSettings::UserSettings::hasSettingDefinitions | ||||
|                                                 (const QString &viewKey) const | ||||
| { | ||||
| 
 | ||||
|     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()); | ||||
|         } | ||||
|     } | ||||
|     return (mSettingDefinitions->contains (viewKey)); | ||||
| } | ||||
| 
 | ||||
| QString CSMSettings::UserSettings::getSetting (const QString §ion, 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()) | ||||
|         retVal = settings->value(setting)->getValue(); | ||||
| QString CSMSettings::UserSettings::settingValue (const QString &settingKey) | ||||
| { | ||||
|     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() | ||||
|  | @ -308,48 +343,85 @@ CSMSettings::UserSettings& CSMSettings::UserSettings::instance() | |||
|     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
 | ||||
|         QMessageBox msgBox; | ||||
|         msgBox.setWindowTitle(QObject::tr("OpenCS configuration file I/O error")); | ||||
|         msgBox.setIcon(QMessageBox::Critical); | ||||
|         msgBox.setStandardButtons(QMessageBox::Ok); | ||||
|     mSettingDefinitions->setValue (settingKey ,list); | ||||
| 
 | ||||
|         if (!isReadOnly) | ||||
|             msgBox.setText (mReadWriteMessage + message); | ||||
|         else | ||||
|             msgBox.setText (message); | ||||
| 
 | ||||
|         msgBox.exec(); | ||||
|     emit userSettingUpdated (settingKey, list); | ||||
| } | ||||
| 
 | ||||
| CSMSettings::SettingMap * | ||||
| CSMSettings::UserSettings::getValidSettings (const QString §ionName) const | ||||
| CSMSettings::Setting *CSMSettings::UserSettings::findSetting | ||||
|                         (const QString &pageName, const QString &settingName) | ||||
| { | ||||
|     SettingMap *settings = 0; | ||||
| 
 | ||||
|     //copy the default values for the entire section if it's not found
 | ||||
|     if (mSectionSettings.find(sectionName) == mSectionSettings.end()) | ||||
|     foreach (Setting *setting, mSettings) | ||||
|     { | ||||
|         if (mEditorSettingDefaults.find(sectionName) != mEditorSettingDefaults.end()) | ||||
|             settings = mEditorSettingDefaults.value (sectionName); | ||||
|     } | ||||
|     //otherwise, iterate the section's settings, looking for missing values and replacing them with defaults.
 | ||||
|     else | ||||
|     { | ||||
|         SettingMap *loadedSettings = mSectionSettings[sectionName]; | ||||
|         SettingMap *defaultSettings = mEditorSettingDefaults[sectionName]; | ||||
| 
 | ||||
|         foreach (QString key, defaultSettings->uniqueKeys()) | ||||
|         if (setting->name() == settingName) | ||||
|         { | ||||
|             //write the default value to the loaded settings
 | ||||
|             if (loadedSettings->find((key))==loadedSettings->end()) | ||||
|                 loadedSettings->insert(key, defaultSettings->value(key)); | ||||
|             if (setting->page() == pageName) | ||||
|                 return setting; | ||||
|         } | ||||
|     } | ||||
|     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(); | ||||
| } | ||||
|  |  | |||
|  | @ -1,13 +1,12 @@ | |||
| #ifndef USERSETTINGS_HPP | ||||
| #define USERSETTINGS_HPP | ||||
| 
 | ||||
| #include <QTextStream> | ||||
| #include <QList> | ||||
| #include <QStringList> | ||||
| #include <QString> | ||||
| #include <QMap> | ||||
| 
 | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| #include "support.hpp" | ||||
| 
 | ||||
| #ifndef Q_MOC_RUN | ||||
|  | @ -18,77 +17,79 @@ namespace Files { typedef std::vector<boost::filesystem::path> PathContainer; | |||
|                   struct ConfigurationManager;} | ||||
| 
 | ||||
| class QFile; | ||||
| class QSettings; | ||||
| 
 | ||||
| namespace CSMSettings { | ||||
| 
 | ||||
|     struct UserSettings: public QObject | ||||
|     class Setting; | ||||
|     typedef QMap <QString, QList <Setting *> > SettingPageMap; | ||||
| 
 | ||||
|     class UserSettings: public QObject | ||||
|     { | ||||
| 
 | ||||
|         Q_OBJECT | ||||
| 
 | ||||
|         SectionMap mSectionSettings; | ||||
|         SectionMap mEditorSettingDefaults; | ||||
| 
 | ||||
|         static UserSettings *mUserSettingsInstance; | ||||
|         QString mUserFilePath; | ||||
|         Files::ConfigurationManager mCfgMgr; | ||||
|         QString mReadOnlyMessage; | ||||
|         QString mReadWriteMessage; | ||||
|         const Files::ConfigurationManager& mCfgMgr; | ||||
| 
 | ||||
|         QSettings *mSettingDefinitions; | ||||
|         QList <Setting *> mSettings; | ||||
| 
 | ||||
|     public: | ||||
| 
 | ||||
|         /// Singleton implementation
 | ||||
|         static UserSettings& instance(); | ||||
| 
 | ||||
|         UserSettings(); | ||||
|         UserSettings (const Files::ConfigurationManager& configurationManager); | ||||
|         ~UserSettings(); | ||||
| 
 | ||||
|         UserSettings (UserSettings const &);        //not implemented
 | ||||
|         void operator= (UserSettings const &);      //not implemented
 | ||||
| 
 | ||||
|         /// Writes settings to the last loaded settings file
 | ||||
|         bool writeSettings(QMap<QString, SettingList *> §ions); | ||||
| 
 | ||||
|         /// 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 §ionName, const QString &settingName = ""); | ||||
|         UserSettings (UserSettings const &); //not implemented
 | ||||
|         UserSettings& operator= (UserSettings const &); //not implemented
 | ||||
| 
 | ||||
|         /// 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); | ||||
| 
 | ||||
|         /// Returns the entire map of settings across all sections
 | ||||
|         const SectionMap &getSectionMap () const; | ||||
|         /// Updates QSettings and syncs with the ini file
 | ||||
|         void setDefinitions (const QString &key, const QStringList &defs); | ||||
| 
 | ||||
|         const SettingMap *getSettings (const QString §ionName) const; | ||||
|         QString settingValue (const QString &settingKey); | ||||
| 
 | ||||
|         /// Retrieves the value as a QString of the specified setting in the specified section
 | ||||
|         QString getSetting(const QString §ion, const QString &setting) const; | ||||
|         ///retrieve a setting object from a given page and setting name
 | ||||
|         Setting *findSetting | ||||
|             (const QString &pageName, const QString &settingName = QString()); | ||||
| 
 | ||||
|         ///remove a setting from the list
 | ||||
|         void removeSetting | ||||
|                         (const QString &pageName, const QString &settingName); | ||||
| 
 | ||||
|         ///Retreive a map of the settings, keyed by page name
 | ||||
|         SettingPageMap settingPageMap() const; | ||||
| 
 | ||||
|         ///Returns a string list of defined vlaues for the specified setting
 | ||||
|         ///in "page/name" format.
 | ||||
|         QStringList definitions (const QString &viewKey) const; | ||||
| 
 | ||||
|         ///Test to indicate whether or not a setting has any definitions
 | ||||
|         bool hasSettingDefinitions (const QString &viewKey) const; | ||||
| 
 | ||||
|         ///Save any unsaved changes in the QSettings object
 | ||||
|         void saveDefinitions() const; | ||||
| 
 | ||||
|     private: | ||||
| 
 | ||||
|         void buildSettingModelDefaults(); | ||||
| 
 | ||||
|         /// Opens a QTextStream from the provided path as read-only or read-write.
 | ||||
|         QTextStream *openFileStream (const QString &filePath, bool isReadOnly = false) const; | ||||
| 
 | ||||
|         ///  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 §ionName) const; | ||||
|         ///add a new setting to the model and return it
 | ||||
|         Setting *createSetting (CSMSettings::SettingType typ, | ||||
|                             const QString &page, const QString &name); | ||||
| 
 | ||||
|     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
 | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ int CSMTools::BirthsignCheckStage::setup() | |||
|     return mBirthsigns.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::BirthsignCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::BirthsignCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::BirthSign>& record = mBirthsigns.getRecord (stage); | ||||
| 
 | ||||
|  | @ -30,13 +30,13 @@ void CSMTools::BirthsignCheckStage::perform (int stage, std::vector<std::string> | |||
| 
 | ||||
|     // test for empty name, description and texture
 | ||||
|     if (birthsign.mName.empty()) | ||||
|         messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty name"); | ||||
|         messages.push_back (std::make_pair (id, birthsign.mId + " has an empty name")); | ||||
| 
 | ||||
|     if (birthsign.mDescription.empty()) | ||||
|         messages.push_back (id.toString() + "|" + birthsign.mId + " has an empty description"); | ||||
|         messages.push_back (std::make_pair (id, birthsign.mId + " has an empty description")); | ||||
| 
 | ||||
|     if (birthsign.mTexture.empty()) | ||||
|         messages.push_back (id.toString() + "|" + birthsign.mId + " is missing a texture"); | ||||
|         messages.push_back (std::make_pair (id, birthsign.mId + " is missing a texture")); | ||||
| 
 | ||||
|     /// \todo test if the texture exists
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ int CSMTools::ClassCheckStage::setup() | |||
|     return mClasses.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::ClassCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Class>& record = mClasses.getRecord (stage); | ||||
| 
 | ||||
|  | @ -31,10 +31,10 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& me | |||
| 
 | ||||
|     // test for empty name and description
 | ||||
|     if (class_.mName.empty()) | ||||
|         messages.push_back (id.toString() + "|" + class_.mId + " has an empty name"); | ||||
|         messages.push_back (std::make_pair (id, class_.mId + " has an empty name")); | ||||
| 
 | ||||
|     if (class_.mDescription.empty()) | ||||
|         messages.push_back (id.toString() + "|" + class_.mId + " has an empty description"); | ||||
|         messages.push_back (std::make_pair (id, class_.mId + " has an empty description")); | ||||
| 
 | ||||
|     // test for invalid attributes
 | ||||
|     for (int i=0; i<2; ++i) | ||||
|  | @ -42,18 +42,14 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& me | |||
|         { | ||||
|             std::ostringstream stream; | ||||
| 
 | ||||
|             stream << id.toString() << "|Attribute #" << i << " of " << class_.mId << " is not set"; | ||||
|             stream << "Attribute #" << i << " of " << class_.mId << " is not set"; | ||||
| 
 | ||||
|             messages.push_back (stream.str()); | ||||
|             messages.push_back (std::make_pair (id, stream.str())); | ||||
|         } | ||||
| 
 | ||||
|     if (class_.mData.mAttribute[0]==class_.mData.mAttribute[1] && class_.mData.mAttribute[0]!=-1) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
| 
 | ||||
|         stream << id.toString() << "|Class lists same attribute twice"; | ||||
| 
 | ||||
|         messages.push_back (stream.str()); | ||||
|         messages.push_back (std::make_pair (id, "Class lists same attribute twice")); | ||||
|     } | ||||
| 
 | ||||
|     // test for non-unique skill
 | ||||
|  | @ -66,12 +62,7 @@ void CSMTools::ClassCheckStage::perform (int stage, std::vector<std::string>& me | |||
|     for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) | ||||
|         if (iter->second>1) | ||||
|         { | ||||
|             std::ostringstream stream; | ||||
| 
 | ||||
|             stream | ||||
|                 << id.toString() << "|" | ||||
|                 << ESM::Skill::indexToId (iter->first) << " is listed more than once"; | ||||
| 
 | ||||
|             messages.push_back (stream.str()); | ||||
|             messages.push_back (std::make_pair (id, | ||||
|                 ESM::Skill::indexToId (iter->first) + " is listed more than once")); | ||||
|         } | ||||
| } | ||||
|  | @ -21,7 +21,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ int CSMTools::FactionCheckStage::setup() | |||
|     return mFactions.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::FactionCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Faction>& record = mFactions.getRecord (stage); | ||||
| 
 | ||||
|  | @ -31,16 +31,12 @@ void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& | |||
| 
 | ||||
|     // test for empty name
 | ||||
|     if (faction.mName.empty()) | ||||
|         messages.push_back (id.toString() + "|" + faction.mId + " has an empty name"); | ||||
|         messages.push_back (std::make_pair (id, faction.mId + " has an empty name")); | ||||
| 
 | ||||
|     // test for invalid attributes
 | ||||
|     if (faction.mData.mAttribute[0]==faction.mData.mAttribute[1] && faction.mData.mAttribute[0]!=-1) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
| 
 | ||||
|         stream << id.toString() << "|Faction lists same attribute twice"; | ||||
| 
 | ||||
|         messages.push_back (stream.str()); | ||||
|         messages.push_back (std::make_pair (id , "Faction lists same attribute twice")); | ||||
|     } | ||||
| 
 | ||||
|     // test for non-unique skill
 | ||||
|  | @ -53,13 +49,8 @@ void CSMTools::FactionCheckStage::perform (int stage, std::vector<std::string>& | |||
|     for (std::map<int, int>::const_iterator iter (skills.begin()); iter!=skills.end(); ++iter) | ||||
|         if (iter->second>1) | ||||
|         { | ||||
|             std::ostringstream stream; | ||||
| 
 | ||||
|             stream | ||||
|                 << id.toString() << "|" | ||||
|                 << ESM::Skill::indexToId (iter->first) << " is listed more than once"; | ||||
| 
 | ||||
|             messages.push_back (stream.str()); | ||||
|             messages.push_back (std::make_pair (id, | ||||
|                 ESM::Skill::indexToId (iter->first) + " is listed more than once")); | ||||
|         } | ||||
| 
 | ||||
|     /// \todo check data members that can't be edited in the table view
 | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -15,9 +15,10 @@ int CSMTools::MandatoryIdStage::setup() | |||
|     return mIds.size(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::MandatoryIdStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::MandatoryIdStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     if (mIdCollection.searchId (mIds.at (stage))==-1 || | ||||
|         mIdCollection.getRecord (mIds.at (stage)).isDeleted()) | ||||
|         messages.push_back (mCollectionId.toString() + "|Missing mandatory record: " + mIds.at (stage)); | ||||
|         messages.push_back (std::make_pair (mCollectionId, | ||||
|             "Missing mandatory record: " + mIds.at (stage))); | ||||
| } | ||||
|  | @ -30,7 +30,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -7,7 +7,7 @@ | |||
| 
 | ||||
| #include "../world/universalid.hpp" | ||||
| 
 | ||||
| void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::RaceCheckStage::performPerRecord (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Race>& record = mRaces.getRecord (stage); | ||||
| 
 | ||||
|  | @ -20,24 +20,24 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::str | |||
| 
 | ||||
|     // test for empty name and description
 | ||||
|     if (race.mName.empty()) | ||||
|         messages.push_back (id.toString() + "|" + race.mId + " has an empty name"); | ||||
|         messages.push_back (std::make_pair (id, race.mId + " has an empty name")); | ||||
| 
 | ||||
|     if (race.mDescription.empty()) | ||||
|         messages.push_back (id.toString() + "|" + race.mId + " has an empty description"); | ||||
|         messages.push_back (std::make_pair (id, race.mId + " has an empty description")); | ||||
| 
 | ||||
|     // test for positive height
 | ||||
|     if (race.mData.mHeight.mMale<=0) | ||||
|         messages.push_back (id.toString() + "|male " + race.mId + " has non-positive height"); | ||||
|         messages.push_back (std::make_pair (id, "male " + race.mId + " has non-positive height")); | ||||
| 
 | ||||
|     if (race.mData.mHeight.mFemale<=0) | ||||
|         messages.push_back (id.toString() + "|female " + race.mId + " has non-positive height"); | ||||
|         messages.push_back (std::make_pair (id, "female " + race.mId + " has non-positive height")); | ||||
| 
 | ||||
|     // test for non-negative weight
 | ||||
|     if (race.mData.mWeight.mMale<0) | ||||
|         messages.push_back (id.toString() + "|male " + race.mId + " has negative weight"); | ||||
|         messages.push_back (std::make_pair (id, "male " + race.mId + " has negative weight")); | ||||
| 
 | ||||
|     if (race.mData.mWeight.mFemale<0) | ||||
|         messages.push_back (id.toString() + "|female " + race.mId + " has negative weight"); | ||||
|         messages.push_back (std::make_pair (id, "female " + race.mId + " has negative weight")); | ||||
| 
 | ||||
|     // remember playable flag
 | ||||
|     if (race.mData.mFlags & 0x1) | ||||
|  | @ -46,12 +46,12 @@ void CSMTools::RaceCheckStage::performPerRecord (int stage, std::vector<std::str | |||
|     /// \todo check data members that can't be edited in the table view
 | ||||
| } | ||||
| 
 | ||||
| void CSMTools::RaceCheckStage::performFinal (std::vector<std::string>& messages) | ||||
| void CSMTools::RaceCheckStage::performFinal (Messages& messages) | ||||
| { | ||||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Races); | ||||
| 
 | ||||
|     if (!mPlayable) | ||||
|         messages.push_back (id.toString() + "|No playable race"); | ||||
|         messages.push_back (std::make_pair (id, "No playable race")); | ||||
| } | ||||
| 
 | ||||
| CSMTools::RaceCheckStage::RaceCheckStage (const CSMWorld::IdCollection<ESM::Race>& races) | ||||
|  | @ -64,7 +64,7 @@ int CSMTools::RaceCheckStage::setup() | |||
|     return mRaces.getSize()+1; | ||||
| } | ||||
| 
 | ||||
| void CSMTools::RaceCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::RaceCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     if (stage==mRaces.getSize()) | ||||
|         performFinal (messages); | ||||
|  |  | |||
|  | @ -15,9 +15,9 @@ namespace CSMTools | |||
|             const CSMWorld::IdCollection<ESM::Race>& mRaces; | ||||
|             bool mPlayable; | ||||
| 
 | ||||
|             void performPerRecord (int stage, std::vector<std::string>& messages); | ||||
|             void performPerRecord (int stage, Messages& messages); | ||||
| 
 | ||||
|             void performFinal (std::vector<std::string>& messages); | ||||
|             void performFinal (Messages& messages); | ||||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|  | @ -26,7 +26,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,9 @@ | |||
| #include "referenceablecheck.hpp" | ||||
| 
 | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include "../world/record.hpp" | ||||
| #include "../world/universalid.hpp" | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( | ||||
|     const CSMWorld::RefIdData& referenceable, const CSMWorld::IdCollection<ESM::Race >& races, | ||||
|  | @ -16,7 +18,7 @@ CSMTools::ReferenceableCheckStage::ReferenceableCheckStage( | |||
| { | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::perform(int stage, std::vector< std::string >& messages) | ||||
| void CSMTools::ReferenceableCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     //Checks for books, than, when stage is above mBooksSize goes to other checks, with (stage - PrevSum) as stage.
 | ||||
|     const int bookSize(mReferencables.getBooks().getSize()); | ||||
|  | @ -206,11 +208,11 @@ void CSMTools::ReferenceableCheckStage::perform(int stage, std::vector< std::str | |||
|         staticCheck(stage, mReferencables.getStatics(), messages); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     stage -= staticSize; | ||||
| 
 | ||||
|     const int creatureSize(mReferencables.getCreatures().getSize()); | ||||
|      | ||||
| 
 | ||||
|     if (stage < creatureSize) | ||||
|     { | ||||
|         creatureCheck(stage, mReferencables.getCreatures(), messages); | ||||
|  | @ -230,7 +232,7 @@ int CSMTools::ReferenceableCheckStage::setup() | |||
| void CSMTools::ReferenceableCheckStage::bookCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Book >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -248,7 +250,7 @@ void CSMTools::ReferenceableCheckStage::bookCheck( | |||
| void CSMTools::ReferenceableCheckStage::activatorCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Activator >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -262,15 +264,13 @@ void CSMTools::ReferenceableCheckStage::activatorCheck( | |||
| 
 | ||||
|     //Checking for model, IIRC all activators should have a model
 | ||||
|     if (activator.mModel.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + activator.mId + " has no model"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, activator.mId + " has no model")); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::potionCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Potion >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -290,7 +290,7 @@ void CSMTools::ReferenceableCheckStage::potionCheck( | |||
| void CSMTools::ReferenceableCheckStage::apparatusCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Apparatus >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -310,7 +310,7 @@ void CSMTools::ReferenceableCheckStage::apparatusCheck( | |||
| void CSMTools::ReferenceableCheckStage::armorCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Armor >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -326,21 +326,17 @@ void CSMTools::ReferenceableCheckStage::armorCheck( | |||
| 
 | ||||
|     //checking for armor class, armor should have poistive armor class, but 0 is considered legal
 | ||||
|     if (armor.mData.mArmor < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + armor.mId + " has negative armor class"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, armor.mId + " has negative armor class")); | ||||
| 
 | ||||
|     //checking for health. Only positive numbers are allowed, or 0 is illegal
 | ||||
|     if (armor.mData.mHealth <= 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + armor.mId + " has non positive health"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, armor.mId + " has non positive health")); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::clothingCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Clothing >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -357,7 +353,7 @@ void CSMTools::ReferenceableCheckStage::clothingCheck( | |||
| void CSMTools::ReferenceableCheckStage::containerCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Container >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -371,153 +367,109 @@ void CSMTools::ReferenceableCheckStage::containerCheck( | |||
| 
 | ||||
|     //Checking for model, IIRC all containers should have a model
 | ||||
|     if (container.mModel.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + container.mId + " has no model"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, container.mId + " has no model")); | ||||
| 
 | ||||
|     //Checking for capacity (weight)
 | ||||
|     if (container.mWeight < 0) //0 is allowed
 | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + container.mId + " has negative weight (capacity)"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, | ||||
|             container.mId + " has negative weight (capacity)")); | ||||
| 
 | ||||
|     //checking for name
 | ||||
|     if (container.mName.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + container.mId + " has an empty name"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, container.mId + " has an empty name")); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::creatureCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Creature >& records, | ||||
|     std::vector< std::string >& messages) | ||||
| void CSMTools::ReferenceableCheckStage::creatureCheck ( | ||||
|     int stage, const CSMWorld::RefIdDataContainer< ESM::Creature >& records, | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|     if (baseRecord.isDeleted()) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ESM::Creature& creature = (dynamic_cast<const CSMWorld::Record<ESM::Creature>&>(baseRecord)).get(); | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Creature, creature.mId); | ||||
| 
 | ||||
|     if (creature.mModel.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has no model"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has no model")); | ||||
| 
 | ||||
|     if (creature.mName.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has an empty name"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has an empty name")); | ||||
| 
 | ||||
|     //stats checks
 | ||||
|     if (creature.mData.mLevel < 1) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has non-postive level"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has non-postive level")); | ||||
| 
 | ||||
|     if (creature.mData.mStrength < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative strength"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative strength")); | ||||
| 
 | ||||
|     if (creature.mData.mIntelligence < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative intelligence"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative intelligence")); | ||||
| 
 | ||||
|     if (creature.mData.mWillpower < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative willpower"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative willpower")); | ||||
| 
 | ||||
|     if (creature.mData.mAgility < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative agility"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative agility")); | ||||
| 
 | ||||
|     if (creature.mData.mSpeed < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative speed"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative speed")); | ||||
| 
 | ||||
|     if (creature.mData.mEndurance < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative endurance"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative endurance")); | ||||
| 
 | ||||
|     if (creature.mData.mPersonality < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative personality"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative personality")); | ||||
| 
 | ||||
|     if (creature.mData.mLuck < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative luck"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative luck")); | ||||
| 
 | ||||
|     if (creature.mData.mHealth < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative health"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative health")); | ||||
| 
 | ||||
|     if (creature.mData.mSoul < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative soul value"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative soul value")); | ||||
| 
 | ||||
|     for (int i = 0; i < 6; ++i) | ||||
|     { | ||||
|         if (creature.mData.mAttack[i] < 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + creature.mId + " has negative attack strength"); | ||||
|             messages.push_back (std::make_pair (id, | ||||
|                 creature.mId + " has negative attack strength")); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     //TODO, find meaning of other values
 | ||||
|     if (creature.mData.mGold < 0) //It seems that this is for gold in merchant creatures
 | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + creature.mId + " has negative gold "); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, creature.mId + " has negative gold ")); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::doorCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Door >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     int stage, const CSMWorld::RefIdDataContainer< ESM::Door >& records, | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|     if (baseRecord.isDeleted()) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ESM::Door& Door = (dynamic_cast<const CSMWorld::Record<ESM::Door>&>(baseRecord)).get(); | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Door, Door.mId); | ||||
| 
 | ||||
|     //usual, name or model
 | ||||
|     if (Door.mName.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + Door.mId + " has an empty name"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, Door.mId + " has an empty name")); | ||||
| 
 | ||||
|     if (Door.mModel.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + Door.mId + " has no model"); | ||||
|     } | ||||
| 
 | ||||
|     //TODO, check what static unsigned int sRecordId; is for
 | ||||
|         messages.push_back (std::make_pair (id, Door.mId + " has no model")); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::ingredientCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Ingredient >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -535,7 +487,7 @@ void CSMTools::ReferenceableCheckStage::ingredientCheck( | |||
| void CSMTools::ReferenceableCheckStage::creaturesLevListCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::CreatureLevList >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -553,7 +505,7 @@ void CSMTools::ReferenceableCheckStage::creaturesLevListCheck( | |||
| void CSMTools::ReferenceableCheckStage::itemLevelledListCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::ItemLevList >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -569,40 +521,33 @@ void CSMTools::ReferenceableCheckStage::itemLevelledListCheck( | |||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::lightCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Light >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     int stage, const CSMWorld::RefIdDataContainer< ESM::Light >& records, | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|     if (baseRecord.isDeleted()) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ESM::Light& light = (dynamic_cast<const CSMWorld::Record<ESM::Light>& >(baseRecord)).get(); | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Light, light.mId); | ||||
| 
 | ||||
|     if (light.mData.mRadius < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + light.mId + " has negative light radius"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, light.mId + " has negative light radius")); | ||||
| 
 | ||||
|     if (light.mData.mFlags & ESM::Light::Carry) | ||||
|     { | ||||
|         inventoryItemCheck<ESM::Light>(light, messages, id.toString()); | ||||
| 
 | ||||
|         if (light.mData.mTime == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + light.mId + " has zero duration"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, light.mId + " has zero duration")); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::lockpickCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Lockpick >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -622,7 +567,7 @@ void CSMTools::ReferenceableCheckStage::lockpickCheck( | |||
| void CSMTools::ReferenceableCheckStage::miscCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Miscellaneous >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -637,20 +582,17 @@ void CSMTools::ReferenceableCheckStage::miscCheck( | |||
|     inventoryItemCheck<ESM::Miscellaneous>(miscellaneous, messages, id.toString()); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::npcCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::NPC >& records, | ||||
|     std::vector< std::string >& messages) | ||||
| void CSMTools::ReferenceableCheckStage::npcCheck ( | ||||
|     int stage, const CSMWorld::RefIdDataContainer< ESM::NPC >& records, | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|     if (baseRecord.isDeleted()) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ESM::NPC& npc = (dynamic_cast<const CSMWorld::Record<ESM::NPC>& >(baseRecord)).get(); | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Npc, npc.mId); | ||||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Npc, npc.mId); | ||||
| 
 | ||||
|     short level(npc.mNpdt52.mLevel); | ||||
|     char disposition(npc.mNpdt52.mDisposition); | ||||
|  | @ -661,15 +603,13 @@ void CSMTools::ReferenceableCheckStage::npcCheck( | |||
| 
 | ||||
|     //Detect if player is present
 | ||||
|     if (Misc::StringUtils::ciEqual(npc.mId, "player")) //Happy now, scrawl?
 | ||||
|     { | ||||
|         mPlayerPresent = true; | ||||
|     } | ||||
| 
 | ||||
|     if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated
 | ||||
|     { | ||||
|         if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0008 = autocalculated flag
 | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " mNpdtType or flags mismatch!"); //should not happend?
 | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|  | @ -681,146 +621,95 @@ void CSMTools::ReferenceableCheckStage::npcCheck( | |||
|     } | ||||
|     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) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " agility has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " agility has zero value")); | ||||
| 
 | ||||
|         if (npc.mNpdt52.mEndurance == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " endurance has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " endurance has zero value")); | ||||
| 
 | ||||
|         if (npc.mNpdt52.mIntelligence == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " intelligence has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " intelligence has zero value")); | ||||
| 
 | ||||
|         if (npc.mNpdt52.mLuck == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " luck has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " luck has zero value")); | ||||
| 
 | ||||
|         if (npc.mNpdt52.mPersonality == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " personality has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " personality has zero value")); | ||||
| 
 | ||||
|         if (npc.mNpdt52.mStrength == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " strength has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " strength has zero value")); | ||||
| 
 | ||||
|         if (npc.mNpdt52.mSpeed == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " speed has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " speed has zero value")); | ||||
| 
 | ||||
|         if (npc.mNpdt52.mWillpower == 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " willpower has zero value"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " willpower has zero value")); | ||||
|     } | ||||
| 
 | ||||
|     if (level < 1) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " level is non positive"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " level is non positive")); | ||||
| 
 | ||||
|     if (gold < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " gold has negative value"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " gold has negative value")); | ||||
| 
 | ||||
|     if (npc.mName.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " has any empty name"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has any empty name")); | ||||
| 
 | ||||
|     if (npc.mClass.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " has any empty class"); | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has any empty class")); | ||||
|     } | ||||
|     else //checking if there is such class
 | ||||
|     else if (mClasses.searchId (npc.mClass) == -1) | ||||
|     { | ||||
|         if (mClasses.searchId(npc.mClass) == -1) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " has invalid class"); | ||||
|         } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has invalid class")); | ||||
|     } | ||||
| 
 | ||||
|     if (npc.mRace.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " has any empty race"); | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has any empty race")); | ||||
|     } | ||||
|     else //checking if there is a such race
 | ||||
|     else if (mRaces.searchId (npc.mRace) == -1) | ||||
|     { | ||||
|         if (mRaces.searchId(npc.mRace) == -1) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " has invalid race"); | ||||
|         } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has invalid race")); | ||||
|     } | ||||
| 
 | ||||
|     if (disposition < 0) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " has negative disposition"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has negative disposition")); | ||||
| 
 | ||||
|     if (reputation < 0) //It seems that no character in Morrowind.esm have negative reputation. I'm assuming that negative reputation is invalid
 | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " has negative reputation"); | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has negative reputation")); | ||||
|     } | ||||
| 
 | ||||
|     if (npc.mFaction.empty() == false) | ||||
|     if (!npc.mFaction.empty()) | ||||
|     { | ||||
|         if (rank < 0) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " has negative rank"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " has negative rank")); | ||||
| 
 | ||||
|         if (mFactions.searchId(npc.mFaction) == -1) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + npc.mId + " has invalid faction"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, npc.mId + " has invalid faction")); | ||||
|     } | ||||
| 
 | ||||
|     if (npc.mHead.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " has no head"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has no head")); | ||||
| 
 | ||||
|     if (npc.mHair.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + npc.mId + " has no hair"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, npc.mId + " has no hair")); | ||||
| 
 | ||||
|     //TODO: reputation, Disposition, rank, everything else
 | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::weaponCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Weapon >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     int stage, const CSMWorld::RefIdDataContainer< ESM::Weapon >& records, | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); | ||||
| 
 | ||||
|     if (baseRecord.isDeleted()) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ESM::Weapon& weapon = (dynamic_cast<const CSMWorld::Record<ESM::Weapon>& >(baseRecord)).get(); | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Weapon, weapon.mId); | ||||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Weapon, weapon.mId); | ||||
| 
 | ||||
|     //TODO, It seems that this stuff for spellcasting is obligatory and In fact We should check if records are present
 | ||||
|     if | ||||
|  | @ -860,20 +749,17 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( | |||
|                 weapon.mData.mType == ESM::Weapon::Bolt)) | ||||
|         { | ||||
|             if (weapon.mData.mSlash[0] > weapon.mData.mSlash[1]) | ||||
|             { | ||||
|                 messages.push_back(id.toString() + "|" + weapon.mId + " has minimum slash damage higher than maximum"); | ||||
|             } | ||||
|                 messages.push_back (std::make_pair (id, | ||||
|                     weapon.mId + " has minimum slash damage higher than maximum")); | ||||
| 
 | ||||
|             if (weapon.mData.mThrust[0] > weapon.mData.mThrust[1]) | ||||
|             { | ||||
|                 messages.push_back(id.toString() + "|" + weapon.mId + " has minimum thrust damage higher than maximum"); | ||||
|             } | ||||
|                 messages.push_back (std::make_pair (id, | ||||
|                     weapon.mId + " has minimum thrust damage higher than maximum")); | ||||
|         } | ||||
| 
 | ||||
|         if (weapon.mData.mChop[0] > weapon.mData.mChop[1]) | ||||
|         { | ||||
|             messages.push_back(id.toString() + "|" + weapon.mId + " has minimum chop damage higher than maximum"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (id, | ||||
|                 weapon.mId + " has minimum chop damage higher than maximum")); | ||||
| 
 | ||||
|         if (!(weapon.mData.mType == ESM::Weapon::Arrow || | ||||
|                 weapon.mData.mType == ESM::Weapon::Bolt || | ||||
|  | @ -881,14 +767,10 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( | |||
|         { | ||||
|             //checking of health
 | ||||
|             if (weapon.mData.mHealth <= 0) | ||||
|             { | ||||
|                 messages.push_back(id.toString() + "|" + weapon.mId + " has non-positivie health"); | ||||
|             } | ||||
|                 messages.push_back (std::make_pair (id, weapon.mId + " has non-positivie health")); | ||||
| 
 | ||||
|             if (weapon.mData.mReach < 0) | ||||
|             { | ||||
|                 messages.push_back(id.toString() + "|" + weapon.mId + " has negative reach"); | ||||
|             } | ||||
|                 messages.push_back (std::make_pair (id, weapon.mId + " has negative reach")); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -896,7 +778,7 @@ void CSMTools::ReferenceableCheckStage::weaponCheck( | |||
| void CSMTools::ReferenceableCheckStage::probeCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Probe >& records, | ||||
|     std::vector< std::string >& messages) | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
| 
 | ||||
|  | @ -912,184 +794,128 @@ void CSMTools::ReferenceableCheckStage::probeCheck( | |||
|     toolCheck<ESM::Probe>(probe, messages, id.toString(), true); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::repairCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Repair >& records, | ||||
|     std::vector< std::string >& messages) | ||||
| void CSMTools::ReferenceableCheckStage::repairCheck ( | ||||
|     int stage, const CSMWorld::RefIdDataContainer< ESM::Repair >& records, | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); | ||||
| 
 | ||||
|     if (baseRecord.isDeleted()) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ESM::Repair& repair = (dynamic_cast<const CSMWorld::Record<ESM::Repair>& >(baseRecord)).get(); | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Repair, repair.mId); | ||||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Repair, repair.mId); | ||||
| 
 | ||||
|     inventoryItemCheck<ESM::Repair>(repair, messages, id.toString()); | ||||
|     toolCheck<ESM::Repair>(repair, messages, id.toString(), true); | ||||
|     inventoryItemCheck<ESM::Repair> (repair, messages, id.toString()); | ||||
|     toolCheck<ESM::Repair> (repair, messages, id.toString(), true); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::staticCheck( | ||||
|     int stage, | ||||
|     const CSMWorld::RefIdDataContainer< ESM::Static >& records, | ||||
|     std::vector< std::string >& messages) | ||||
| void CSMTools::ReferenceableCheckStage::staticCheck ( | ||||
|     int stage, const CSMWorld::RefIdDataContainer< ESM::Static >& records, | ||||
|     Messages& messages) | ||||
| { | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord(stage); | ||||
|     const CSMWorld::RecordBase& baseRecord = records.getRecord (stage); | ||||
| 
 | ||||
|     if (baseRecord.isDeleted()) | ||||
|     { | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|     const ESM::Static& staticElement = (dynamic_cast<const CSMWorld::Record<ESM::Static>& >(baseRecord)).get(); | ||||
|     CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Static, staticElement.mId); | ||||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Static, staticElement.mId); | ||||
| 
 | ||||
|     if (staticElement.mModel.empty()) | ||||
|     { | ||||
|         messages.push_back(id.toString() + "|" + staticElement.mId + " has no model"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (id, staticElement.mId + " has no model")); | ||||
| } | ||||
| 
 | ||||
| //final check
 | ||||
| 
 | ||||
| void CSMTools::ReferenceableCheckStage::finalCheck(std::vector< std::string >& messages) | ||||
| void CSMTools::ReferenceableCheckStage::finalCheck (Messages& messages) | ||||
| { | ||||
|     if (!mPlayerPresent) | ||||
|     { | ||||
|         CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_Npc); | ||||
|         messages.push_back(id.toString() + "| There is no player record"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (CSMWorld::UniversalId::Type_Referenceables, | ||||
|             "There is no player record")); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| //Templates begins here
 | ||||
| 
 | ||||
| template<typename ITEM> void CSMTools::ReferenceableCheckStage::inventoryItemCheck( | ||||
|     const ITEM& someItem, | ||||
|     std::vector< std::string >& messages, | ||||
|     const std::string& someID, bool enchantable) | ||||
| template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( | ||||
|     const Item& someItem, Messages& messages, const std::string& someID, bool enchantable) | ||||
| { | ||||
|     if (someItem.mName.empty()) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has an empty name"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); | ||||
| 
 | ||||
|     //Checking for weight
 | ||||
|     if (someItem.mData.mWeight < 0) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has negative weight"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has negative weight")); | ||||
| 
 | ||||
|     //Checking for value
 | ||||
|     if (someItem.mData.mValue < 0) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has negative value"); | ||||
|     } | ||||
| 
 | ||||
| //checking for model
 | ||||
|     if (someItem.mModel.empty()) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has no model"); | ||||
|     } | ||||
| 
 | ||||
|     //checking for icon
 | ||||
|     if (someItem.mIcon.empty()) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has no icon"); | ||||
|     } | ||||
| 
 | ||||
|     if (enchantable) | ||||
|     { | ||||
|         if (someItem.mData.mEnchant < 0) | ||||
|         { | ||||
|             messages.push_back(someID + "|" + someItem.mId + " has negative enchantment"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template<typename ITEM> void CSMTools::ReferenceableCheckStage::inventoryItemCheck( | ||||
|     const ITEM& someItem, | ||||
|     std::vector< std::string >& messages, | ||||
|     const std::string& someID) | ||||
| { | ||||
|     if (someItem.mName.empty()) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has an empty name"); | ||||
|     } | ||||
| 
 | ||||
|     //Checking for weight
 | ||||
|     if (someItem.mData.mWeight < 0) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has negative weight"); | ||||
|     } | ||||
| 
 | ||||
|     //Checking for value
 | ||||
|     if (someItem.mData.mValue < 0) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has negative value"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has negative value")); | ||||
| 
 | ||||
|     //checking for model
 | ||||
|     if (someItem.mModel.empty()) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has no model"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has no model")); | ||||
| 
 | ||||
|     //checking for icon
 | ||||
|     if (someItem.mIcon.empty()) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someItem.mId + " has no icon"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has no icon")); | ||||
| 
 | ||||
|     if (enchantable && someItem.mData.mEnchant < 0) | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has negative enchantment")); | ||||
| } | ||||
| 
 | ||||
| template<typename TOOL> void CSMTools::ReferenceableCheckStage::toolCheck( | ||||
|     const TOOL& someTool, | ||||
|     std::vector< std::string >& messages, | ||||
|     const std::string& someID, bool canBeBroken) | ||||
| template<typename Item> void CSMTools::ReferenceableCheckStage::inventoryItemCheck ( | ||||
|     const Item& someItem, Messages& messages, const std::string& someID) | ||||
| { | ||||
|     if (someItem.mName.empty()) | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has an empty name")); | ||||
| 
 | ||||
|     //Checking for weight
 | ||||
|     if (someItem.mData.mWeight < 0) | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has negative weight")); | ||||
| 
 | ||||
|     //Checking for value
 | ||||
|     if (someItem.mData.mValue < 0) | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has negative value")); | ||||
| 
 | ||||
|     //checking for model
 | ||||
|     if (someItem.mModel.empty()) | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has no model")); | ||||
| 
 | ||||
|     //checking for icon
 | ||||
|     if (someItem.mIcon.empty()) | ||||
|         messages.push_back (std::make_pair (someID, someItem.mId + " has no icon")); | ||||
| } | ||||
| 
 | ||||
| template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck ( | ||||
|     const Tool& someTool, Messages& messages, const std::string& someID, bool canBeBroken) | ||||
| { | ||||
|     if (someTool.mData.mQuality <= 0) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someTool.mId + " has non-positive quality"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); | ||||
| 
 | ||||
|     if (canBeBroken) | ||||
|     { | ||||
|         if (someTool.mData.mUses <= 0) | ||||
|         { | ||||
|             messages.push_back(someID + "|" + someTool.mId + " has non-positive uses count"); | ||||
|         } | ||||
|     } | ||||
|     if (canBeBroken && someTool.mData.mUses<=0) | ||||
|         messages.push_back (std::make_pair (someID, | ||||
|             someTool.mId + " has non-positive uses count")); | ||||
| } | ||||
| 
 | ||||
| template<typename TOOL> void CSMTools::ReferenceableCheckStage::toolCheck( | ||||
|     const TOOL& someTool, | ||||
|     std::vector< std::string >& messages, | ||||
|     const std::string& someID) | ||||
| template<typename Tool> void CSMTools::ReferenceableCheckStage::toolCheck ( | ||||
|     const Tool& someTool, Messages& messages, const std::string& someID) | ||||
| { | ||||
|     if (someTool.mData.mQuality <= 0) | ||||
|     { | ||||
|         messages.push_back(someID + "|" + someTool.mId + " has non-positive quality"); | ||||
|     } | ||||
|         messages.push_back (std::make_pair (someID, someTool.mId + " has non-positive quality")); | ||||
| } | ||||
| 
 | ||||
| template<typename LIST> void CSMTools::ReferenceableCheckStage::listCheck( | ||||
|     const LIST& someList, | ||||
|     std::vector< std::string >& messages, | ||||
|     const std::string& someID) | ||||
| template<typename List> void CSMTools::ReferenceableCheckStage::listCheck ( | ||||
|     const List& someList, Messages& messages, const std::string& someID) | ||||
| { | ||||
|     for (unsigned i = 0; i < someList.mList.size(); ++i) | ||||
|     { | ||||
|         if (mReferencables.searchId(someList.mList[i].mId).first == -1) | ||||
|         { | ||||
|             messages.push_back(someID + "|" + someList.mId + " contains item without referencable"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (someID, | ||||
|                 someList.mId + " contains item without referencable")); | ||||
| 
 | ||||
|         if (someList.mList[i].mLevel < 1) | ||||
|         { | ||||
|             messages.push_back(someID + "|" + someList.mId + " contains item with non-positive level"); | ||||
|         } | ||||
|             messages.push_back (std::make_pair (someID, | ||||
|                 someList.mId + " contains item with non-positive level")); | ||||
|     } | ||||
| } | ||||
| // kate: indent-mode cstyle; indent-width 4; replace-tabs on; 
 | ||||
|  |  | |||
|  | @ -11,63 +11,64 @@ namespace CSMTools | |||
|     class ReferenceableCheckStage : public CSMDoc::Stage | ||||
|     { | ||||
|         public: | ||||
|             ReferenceableCheckStage(const CSMWorld::RefIdData& referenceable, | ||||
| 				    const CSMWorld::IdCollection<ESM::Race>& races, | ||||
| 				    const CSMWorld::IdCollection<ESM::Class>& classes, | ||||
| 				    const CSMWorld::IdCollection<ESM::Faction>& factions); | ||||
| 
 | ||||
|             virtual void perform(int stage, std::vector< std::string >& messages); | ||||
|             ReferenceableCheckStage (const CSMWorld::RefIdData& referenceable, | ||||
|                 const CSMWorld::IdCollection<ESM::Race>& races, | ||||
|                 const CSMWorld::IdCollection<ESM::Class>& classes, | ||||
|                 const CSMWorld::IdCollection<ESM::Faction>& factions); | ||||
| 
 | ||||
|             virtual void perform(int stage, Messages& messages); | ||||
|             virtual int setup(); | ||||
| 
 | ||||
|         private: | ||||
|             //CONCRETE CHECKS
 | ||||
|             void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, std::vector< std::string >& messages); | ||||
|             void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, std::vector< std::string >& messages); | ||||
|             void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, std::vector<std::string>& messages); | ||||
|             void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, std::vector<std::string>& messages); | ||||
|             void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, std::vector<std::string>& messages); | ||||
|             void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, std::vector<std::string>& messages); | ||||
|             void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, std::vector<std::string>& messages); | ||||
|             void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, std::vector<std::string>& messages); | ||||
|             void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, std::vector<std::string>& messages); | ||||
|             void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, std::vector<std::string>& messages); | ||||
|             void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, std::vector<std::string>& messages); | ||||
|             void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, std::vector<std::string>& messages); | ||||
|             void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, std::vector<std::string>& messages); | ||||
|             void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, std::vector<std::string>& messages); | ||||
|             void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, std::vector<std::string>& messages); | ||||
|             void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, std::vector<std::string>& messages); | ||||
|             void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, std::vector<std::string>& messages); | ||||
|             void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, std::vector<std::string>& messages); | ||||
|             void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, std::vector<std::string>& messages); | ||||
|             void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, std::vector<std::string>& messages); | ||||
|              | ||||
|             void bookCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Book >& records, Messages& messages); | ||||
|             void activatorCheck(int stage, const CSMWorld::RefIdDataContainer< ESM::Activator >& records, Messages& messages); | ||||
|             void potionCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Potion>& records, Messages& messages); | ||||
|             void apparatusCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Apparatus>& records, Messages& messages); | ||||
|             void armorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Armor>& records, Messages& messages); | ||||
|             void clothingCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Clothing>& records, Messages& messages); | ||||
|             void containerCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Container>& records, Messages& messages); | ||||
|             void creatureCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Creature>& records, Messages& messages); | ||||
|             void doorCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Door>& records, Messages& messages); | ||||
|             void ingredientCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Ingredient>& records, Messages& messages); | ||||
|             void creaturesLevListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::CreatureLevList>& records, Messages& messages); | ||||
|             void itemLevelledListCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::ItemLevList>& records, Messages& messages); | ||||
|             void lightCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Light>& records, Messages& messages); | ||||
|             void lockpickCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Lockpick>& records, Messages& messages); | ||||
|             void miscCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Miscellaneous>& records, Messages& messages); | ||||
|             void npcCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::NPC>& records, Messages& messages); | ||||
|             void weaponCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Weapon>& records, Messages& messages); | ||||
|             void probeCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Probe>& records, Messages& messages); | ||||
|             void repairCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Repair>& records, Messages& messages); | ||||
|             void staticCheck(int stage, const CSMWorld::RefIdDataContainer<ESM::Static>& records, Messages& messages); | ||||
| 
 | ||||
|             //FINAL CHECK
 | ||||
|             void finalCheck(std::vector<std::string>& messages); | ||||
|              | ||||
|             void finalCheck (Messages& messages); | ||||
| 
 | ||||
| 	    //TEMPLATE CHECKS
 | ||||
| 	    template<typename ITEM> void inventoryItemCheck(const ITEM& someItem, | ||||
|                                                             std::vector<std::string>& messages, | ||||
|                                                             Messages& messages, | ||||
|                                                             const std::string& someID, | ||||
|                                                             bool enchantable); //for all enchantable items.
 | ||||
|              | ||||
| 
 | ||||
| 	    template<typename ITEM> void inventoryItemCheck(const ITEM& someItem, | ||||
|                                                             std::vector<std::string>& messages, | ||||
|                                                             Messages& messages, | ||||
|                                                             const std::string& someID); //for non-enchantable items.
 | ||||
|              | ||||
| 
 | ||||
| 	    template<typename TOOL> void toolCheck(const TOOL& someTool, | ||||
|                                                    std::vector<std::string>& messages, | ||||
|                                                    Messages& messages, | ||||
|                                                    const std::string& someID, | ||||
|                                                    bool canbebroken); //for tools with uses.
 | ||||
|              | ||||
| 
 | ||||
| 	    template<typename TOOL> void toolCheck(const TOOL& someTool, | ||||
|                                                    std::vector<std::string>& messages, | ||||
|                                                    Messages& messages, | ||||
|                                                    const std::string& someID); //for tools without uses.
 | ||||
| 
 | ||||
| 	    template<typename LIST> void listCheck(const LIST& someList, | ||||
|                                                    std::vector< std::string >& messages, | ||||
|                                                    Messages& messages, | ||||
|                                                    const std::string& someID); | ||||
| 	     | ||||
| 
 | ||||
|             const CSMWorld::RefIdData& mReferencables; | ||||
|             const CSMWorld::IdCollection<ESM::Race>& mRaces; | ||||
|             const CSMWorld::IdCollection<ESM::Class>& mClasses; | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ int CSMTools::RegionCheckStage::setup() | |||
|     return mRegions.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::RegionCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Region>& record = mRegions.getRecord (stage); | ||||
| 
 | ||||
|  | @ -30,7 +30,7 @@ void CSMTools::RegionCheckStage::perform (int stage, std::vector<std::string>& m | |||
| 
 | ||||
|     // test for empty name
 | ||||
|     if (region.mName.empty()) | ||||
|         messages.push_back (id.toString() + "|" + region.mId + " has an empty name"); | ||||
|         messages.push_back (std::make_pair (id, region.mId + " has an empty name")); | ||||
| 
 | ||||
|     /// \todo test that the ID in mSleeplist exists
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -51,16 +51,11 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ReportModel::add (const std::string& row) | ||||
| void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message) | ||||
| { | ||||
|     std::string::size_type index = row.find ('|'); | ||||
| 
 | ||||
|     if (index==std::string::npos) | ||||
|         throw std::logic_error ("invalid report message"); | ||||
| 
 | ||||
|     beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); | ||||
| 
 | ||||
|     mRows.push_back (std::make_pair (row.substr (0, index), row.substr (index+1))); | ||||
|     mRows.push_back (std::make_pair (id, message)); | ||||
| 
 | ||||
|     endInsertRows(); | ||||
| } | ||||
|  |  | |||
|  | @ -28,7 +28,7 @@ namespace CSMTools | |||
| 
 | ||||
|             virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); | ||||
| 
 | ||||
|             void add (const std::string& row); | ||||
|             void add (const CSMWorld::UniversalId& id, const std::string& message); | ||||
| 
 | ||||
|             const CSMWorld::UniversalId& getUniversalId (int row) const; | ||||
|     }; | ||||
|  |  | |||
|  | @ -16,8 +16,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi | |||
| 
 | ||||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); | ||||
| 
 | ||||
|     stream << id.toString() << "|"; | ||||
| 
 | ||||
|     if (type==ErrorMessage) | ||||
|         stream << "error "; | ||||
|     else | ||||
|  | @ -28,25 +26,15 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi | |||
|         << ", line " << loc.mLine << ", column " << loc.mColumn | ||||
|         << " (" << loc.mLiteral << "): " << message; | ||||
| 
 | ||||
|     mMessages->push_back (stream.str()); | ||||
|     mMessages->push_back (std::make_pair (id, stream.str())); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) | ||||
| { | ||||
|     std::ostringstream stream; | ||||
| 
 | ||||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); | ||||
| 
 | ||||
|     stream << id.toString() << "|"; | ||||
| 
 | ||||
|     if (type==ErrorMessage) | ||||
|         stream << "error: "; | ||||
|     else | ||||
|         stream << "warning: "; | ||||
| 
 | ||||
|     stream << message; | ||||
| 
 | ||||
|     mMessages->push_back (stream.str()); | ||||
|     mMessages->push_back (std::make_pair (id, | ||||
|         (type==ErrorMessage ? "error: " : "warning: ") + message)); | ||||
| } | ||||
| 
 | ||||
| CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data) | ||||
|  | @ -68,7 +56,7 @@ int CSMTools::ScriptCheckStage::setup() | |||
|     return mData.getScripts().getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::ScriptCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     mMessages = &messages; | ||||
|     mId = mData.getScripts().getId (stage); | ||||
|  | @ -90,13 +78,10 @@ void CSMTools::ScriptCheckStage::perform (int stage, std::vector<std::string>& m | |||
|     } | ||||
|     catch (const std::exception& error) | ||||
|     { | ||||
|         std::ostringstream stream; | ||||
| 
 | ||||
|         CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); | ||||
| 
 | ||||
|         stream << id.toString() << "|Critical compile error: " << error.what(); | ||||
| 
 | ||||
|         messages.push_back (stream.str()); | ||||
|         messages.push_back (std::make_pair (id, | ||||
|             std::string ("Critical compile error: ") + error.what())); | ||||
|     } | ||||
| 
 | ||||
|     mMessages = 0; | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ namespace CSMTools | |||
|             CSMWorld::ScriptContext mContext; | ||||
|             std::string mId; | ||||
|             std::string mFile; | ||||
|             std::vector<std::string> *mMessages; | ||||
|             Messages *mMessages; | ||||
| 
 | ||||
|             virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); | ||||
|             ///< Report error to the user.
 | ||||
|  | @ -33,7 +33,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ int CSMTools::SkillCheckStage::setup() | |||
|     return mSkills.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::SkillCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::SkillCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Skill>& record = mSkills.getRecord (stage); | ||||
| 
 | ||||
|  | @ -32,11 +32,11 @@ void CSMTools::SkillCheckStage::perform (int stage, std::vector<std::string>& me | |||
|         { | ||||
|             std::ostringstream stream; | ||||
| 
 | ||||
|             stream << id.toString() << "|Use value #" << i << " of " << skill.mId << " is negative"; | ||||
|             stream << "Use value #" << i << " of " << skill.mId << " is negative"; | ||||
| 
 | ||||
|             messages.push_back (stream.str()); | ||||
|             messages.push_back (std::make_pair (id, stream.str())); | ||||
|         } | ||||
| 
 | ||||
|     if (skill.mDescription.empty()) | ||||
|         messages.push_back (id.toString() + "|" + skill.mId + " has an empty description"); | ||||
|         messages.push_back (std::make_pair (id, skill.mId + " has an empty description")); | ||||
| } | ||||
|  | @ -21,7 +21,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -16,7 +16,7 @@ int CSMTools::SoundCheckStage::setup() | |||
|     return mSounds.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::SoundCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::SoundCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Sound>& record = mSounds.getRecord (stage); | ||||
| 
 | ||||
|  | @ -28,7 +28,7 @@ void CSMTools::SoundCheckStage::perform (int stage, std::vector<std::string>& me | |||
|     CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Sound, sound.mId); | ||||
| 
 | ||||
|     if (sound.mData.mMinRange>sound.mData.mMaxRange) | ||||
|         messages.push_back (id.toString() + "|Maximum range larger than minimum range"); | ||||
|         messages.push_back (std::make_pair (id, "Maximum range larger than minimum range")); | ||||
| 
 | ||||
|     /// \todo check, if the sound file exists
 | ||||
| } | ||||
|  | @ -21,7 +21,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ int CSMTools::SpellCheckStage::setup() | |||
|     return mSpells.getSize(); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& messages) | ||||
| void CSMTools::SpellCheckStage::perform (int stage, Messages& messages) | ||||
| { | ||||
|     const CSMWorld::Record<ESM::Spell>& record = mSpells.getRecord (stage); | ||||
| 
 | ||||
|  | @ -30,11 +30,11 @@ void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& me | |||
| 
 | ||||
|     // test for empty name and description
 | ||||
|     if (spell.mName.empty()) | ||||
|         messages.push_back (id.toString() + "|" + spell.mId + " has an empty name"); | ||||
|         messages.push_back (std::make_pair (id, spell.mId + " has an empty name")); | ||||
| 
 | ||||
|     // test for invalid cost values
 | ||||
|     if (spell.mData.mCost<0) | ||||
|         messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs"); | ||||
|         messages.push_back (std::make_pair (id, spell.mId + " has a negative spell costs")); | ||||
| 
 | ||||
|     /// \todo check data members that can't be edited in the table view
 | ||||
| } | ||||
|  | @ -21,7 +21,7 @@ namespace CSMTools | |||
|             virtual int setup(); | ||||
|             ///< \return number of steps
 | ||||
| 
 | ||||
|             virtual void perform (int stage, std::vector<std::string>& messages); | ||||
|             virtual void perform (int stage, Messages& messages); | ||||
|             ///< Messages resulting from this tage will be appended to \a messages.
 | ||||
|     }; | ||||
| } | ||||
|  |  | |||
|  | @ -45,8 +45,9 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() | |||
| 
 | ||||
|         connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); | ||||
|         connect (mVerifier, SIGNAL (done (int)), this, SIGNAL (done (int))); | ||||
|         connect (mVerifier, SIGNAL (reportMessage (const QString&, int)), | ||||
|             this, SLOT (verifierMessage (const QString&, int))); | ||||
|         connect (mVerifier, | ||||
|             SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), | ||||
|             this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int))); | ||||
| 
 | ||||
|         std::vector<std::string> mandatoryIds; //  I want C++11, damn it!
 | ||||
|         mandatoryIds.push_back ("Day"); | ||||
|  | @ -87,13 +88,17 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier() | |||
| 
 | ||||
| CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0) | ||||
| { | ||||
|     for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) | ||||
|         delete iter->second; | ||||
|     // index 0: load error log
 | ||||
|     mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); | ||||
|     mActiveReports.insert (std::make_pair (CSMDoc::State_Loading, 0)); | ||||
| } | ||||
| 
 | ||||
| CSMTools::Tools::~Tools() | ||||
| { | ||||
|     delete mVerifier; | ||||
| 
 | ||||
|     for (std::map<int, ReportModel *>::iterator iter (mReports.begin()); iter!=mReports.end(); ++iter) | ||||
|         delete iter->second; | ||||
| } | ||||
| 
 | ||||
| CSMWorld::UniversalId CSMTools::Tools::runVerifier() | ||||
|  | @ -132,17 +137,19 @@ int CSMTools::Tools::getRunningOperations() const | |||
| 
 | ||||
| CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId& id) | ||||
| { | ||||
|     if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults) | ||||
|     if (id.getType()!=CSMWorld::UniversalId::Type_VerificationResults && | ||||
|         id.getType()!=CSMWorld::UniversalId::Type_LoadErrorLog) | ||||
|         throw std::logic_error ("invalid request for report model: " + id.toString()); | ||||
| 
 | ||||
|     return mReports.at (id.getIndex()); | ||||
| } | ||||
| 
 | ||||
| void CSMTools::Tools::verifierMessage (const QString& message, int type) | ||||
| void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, | ||||
|     int type) | ||||
| { | ||||
|     std::map<int, int>::iterator iter = mActiveReports.find (type); | ||||
| 
 | ||||
|     if (iter!=mActiveReports.end()) | ||||
|         mReports[iter->second]->add (message.toUtf8().constData()); | ||||
|         mReports[iter->second]->add (id, message); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -61,7 +61,8 @@ namespace CSMTools | |||
| 
 | ||||
|         private slots: | ||||
| 
 | ||||
|             void verifierMessage (const QString& message, int type); | ||||
|             void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, | ||||
|                 int type); | ||||
| 
 | ||||
|         signals: | ||||
| 
 | ||||
|  |  | |||
|  | @ -18,8 +18,3 @@ void CSMWorld::Cell::load (ESM::ESMReader &esm) | |||
|         mId = stream.str(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void CSMWorld::Cell::addRef (const std::string& id) | ||||
| { | ||||
|     mRefs.push_back (std::make_pair (id, false)); | ||||
| } | ||||
|  | @ -15,12 +15,9 @@ namespace CSMWorld | |||
|     struct Cell : public ESM::Cell | ||||
|     { | ||||
|         std::string mId; | ||||
|         std::vector<std::pair<std::string, bool> > mRefs; // ID, modified
 | ||||
|         std::vector<std::string> mDeletedRefs; | ||||
| 
 | ||||
|         void load (ESM::ESMReader &esm); | ||||
| 
 | ||||
|         void addRef (const std::string& id); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -86,6 +86,8 @@ namespace CSMWorld | |||
| 
 | ||||
|             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 const ColumnBase& getColumn (int column) const; | ||||
|  | @ -295,6 +297,12 @@ namespace CSMWorld | |||
|         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> | ||||
|     void Collection<ESXRecordT, IdAccessorT>::setData (int index, int column, const QVariant& data) | ||||
|     { | ||||
|  |  | |||
|  | @ -2,6 +2,7 @@ | |||
| #include "collectionbase.hpp" | ||||
| 
 | ||||
| #include <stdexcept> | ||||
| #include <cassert> | ||||
| 
 | ||||
| #include "columnbase.hpp" | ||||
| 
 | ||||
|  |  | |||
|  | @ -48,6 +48,8 @@ namespace CSMWorld | |||
| 
 | ||||
|             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 setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); | ||||
|  |  | |||
|  | @ -89,7 +89,9 @@ namespace CSMWorld | |||
|             Display_RefRecordType, | ||||
|             Display_DialogueType, | ||||
|             Display_QuestStatusType, | ||||
|             Display_Gender | ||||
|             Display_Gender, | ||||
| 
 | ||||
|             Display_Nested | ||||
|         }; | ||||
| 
 | ||||
|         int mColumnId; | ||||
|  | @ -125,6 +127,12 @@ namespace CSMWorld | |||
|             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 | ||||
|  |  | |||
|  | @ -167,6 +167,7 @@ namespace CSMWorld | |||
|             ColumnId_PcRank = 154, | ||||
|             ColumnId_Scope = 155, | ||||
|             ColumnId_ReferenceableId = 156, | ||||
|             ColumnId_ContainerContent = 157, | ||||
| 
 | ||||
|             // Allocated to a separate value range, so we don't get a collision should we ever need
 | ||||
|             // to extend the number of use values.
 | ||||
|  |  | |||
							
								
								
									
										165
									
								
								apps/opencs/model/world/commanddispatcher.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								apps/opencs/model/world/commanddispatcher.cpp
									
									
									
									
									
										Normal 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(); | ||||
| } | ||||
							
								
								
									
										53
									
								
								apps/opencs/model/world/commanddispatcher.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								apps/opencs/model/world/commanddispatcher.hpp
									
									
									
									
									
										Normal 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 | ||||
|  | @ -16,11 +16,12 @@ | |||
| #include "regionmap.hpp" | ||||
| #include "columns.hpp" | ||||
| 
 | ||||
| void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, | ||||
|     UniversalId::Type type2, bool update) | ||||
| void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update) | ||||
| { | ||||
|     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) | ||||
|         mModelIndex.insert (std::make_pair (type2, model)); | ||||
|  | @ -55,7 +56,8 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec | |||
|     return number; | ||||
| } | ||||
| 
 | ||||
| CSMWorld::Data::Data() : mRefs (mCells) | ||||
| CSMWorld::Data::Data (ToUTF8::FromType encoding) | ||||
| : mEncoder (encoding), mRefs (mCells), mReader (0), mDialogue (0) | ||||
| { | ||||
|     mGlobals.addColumn (new StringIdColumn<ESM::Global>); | ||||
|     mGlobals.addColumn (new RecordStateColumn<ESM::Global>); | ||||
|  | @ -234,32 +236,34 @@ CSMWorld::Data::Data() : mRefs (mCells) | |||
|     mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>); | ||||
|     mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>); | ||||
| 
 | ||||
|     addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global); | ||||
|     addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); | ||||
|     addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill, false); | ||||
|     addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); | ||||
|     addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); | ||||
|     addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); | ||||
|     addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); | ||||
|     addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); | ||||
|     addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); | ||||
|     addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); | ||||
|     addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); | ||||
|     addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic); | ||||
|     addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal); | ||||
|     addModel (new IdTable (&mTopicInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_TopicInfos, UniversalId::Type_TopicInfo); | ||||
|     addModel (new IdTable (&mJournalInfos, IdTable::Reordering_WithinTopic), UniversalId::Type_JournalInfos, UniversalId::Type_JournalInfo); | ||||
|     addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell); | ||||
|     addModel (new IdTable (&mReferenceables, IdTable::Reordering_None, IdTable::Viewing_None, true), | ||||
|         UniversalId::Type_Referenceables, UniversalId::Type_Referenceable); | ||||
|     addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell, true), UniversalId::Type_References, UniversalId::Type_Reference, false); | ||||
|     addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false); | ||||
|     addModel (new IdTable (&mGlobals), UniversalId::Type_Global); | ||||
|     addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); | ||||
|     addModel (new IdTable (&mSkills), UniversalId::Type_Skill); | ||||
|     addModel (new IdTable (&mClasses), UniversalId::Type_Class); | ||||
|     addModel (new IdTable (&mFactions), UniversalId::Type_Faction); | ||||
|     addModel (new IdTable (&mRaces), UniversalId::Type_Race); | ||||
|     addModel (new IdTable (&mSounds), UniversalId::Type_Sound); | ||||
|     addModel (new IdTable (&mScripts), UniversalId::Type_Script); | ||||
|     addModel (new IdTable (&mRegions), UniversalId::Type_Region); | ||||
|     addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsign); | ||||
|     addModel (new IdTable (&mSpells), UniversalId::Type_Spell); | ||||
|     addModel (new IdTable (&mTopics), UniversalId::Type_Topic); | ||||
|     addModel (new IdTable (&mJournals), UniversalId::Type_Journal); | ||||
|     addModel (new IdTable (&mTopicInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_TopicInfo); | ||||
|     addModel (new IdTable (&mJournalInfos, IdTable::Feature_ReorderWithinTopic), UniversalId::Type_JournalInfo); | ||||
|     addModel (new IdTable (&mCells, IdTable::Feature_ViewId), UniversalId::Type_Cell); | ||||
|     addModel (new IdTable (&mReferenceables, IdTable::Feature_Preview), | ||||
|         UniversalId::Type_Referenceable); | ||||
|     addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference); | ||||
|     addModel (new IdTable (&mFilters), UniversalId::Type_Filter); | ||||
| } | ||||
| 
 | ||||
| CSMWorld::Data::~Data() | ||||
| { | ||||
|     for (std::vector<QAbstractItemModel *>::iterator iter (mModels.begin()); iter!=mModels.end(); ++iter) | ||||
|         delete *iter; | ||||
| 
 | ||||
|     delete mReader; | ||||
| } | ||||
| 
 | ||||
| const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const | ||||
|  | @ -453,7 +457,7 @@ CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() | |||
|     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()); | ||||
| 
 | ||||
|  | @ -466,8 +470,7 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id) | |||
|         if (id.getType()==UniversalId::Type_RegionMap) | ||||
|         { | ||||
|             RegionMap *table = 0; | ||||
|             addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, | ||||
|                 UniversalId::Type_None, false); | ||||
|             addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, false); | ||||
|             return table; | ||||
|         } | ||||
|         throw std::logic_error ("No table model available for " + id.toString()); | ||||
|  | @ -481,148 +484,171 @@ void CSMWorld::Data::merge() | |||
|     mGlobals.merge(); | ||||
| } | ||||
| 
 | ||||
| void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base, bool project) | ||||
| int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base, bool project) | ||||
| { | ||||
|     ESM::ESMReader reader; | ||||
|     delete mReader; | ||||
|     mReader = 0; | ||||
|     mDialogue = 0; | ||||
|     mRefLoadCache.clear(); | ||||
| 
 | ||||
|     /// \todo set encoding properly, once config implementation has been fixed.
 | ||||
|     ToUTF8::Utf8Encoder encoder (ToUTF8::calculateEncoding ("win1252")); | ||||
|     reader.setEncoder (&encoder); | ||||
|     mReader = new ESM::ESMReader; | ||||
|     mReader->setEncoder (&mEncoder); | ||||
|     mReader->open (path.string()); | ||||
| 
 | ||||
|     reader.open (path.string()); | ||||
|     mBase = base; | ||||
|     mProject = project; | ||||
| 
 | ||||
|     const ESM::Dialogue *dialogue = 0; | ||||
|     mAuthor = mReader->getAuthor(); | ||||
|     mDescription = mReader->getDesc(); | ||||
| 
 | ||||
|     mAuthor = reader.getAuthor(); | ||||
|     mDescription = reader.getDesc(); | ||||
|     return mReader->getRecordCount(); | ||||
| } | ||||
| 
 | ||||
|     // Note: We do not need to send update signals here, because at this point the model is not connected
 | ||||
|     // to any view.
 | ||||
|     while (reader.hasMoreRecs()) | ||||
| bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages) | ||||
| { | ||||
|     if (!mReader) | ||||
|         throw std::logic_error ("can't continue loading, because no load has been started"); | ||||
| 
 | ||||
|     if (!mReader->hasMoreRecs()) | ||||
|     { | ||||
|         ESM::NAME n = reader.getRecName(); | ||||
|         reader.getRecHeader(); | ||||
| 
 | ||||
|         switch (n.val) | ||||
|         { | ||||
|             case ESM::REC_GLOB: mGlobals.load (reader, base); break; | ||||
|             case ESM::REC_GMST: mGmsts.load (reader, base); break; | ||||
|             case ESM::REC_SKIL: mSkills.load (reader, base); break; | ||||
|             case ESM::REC_CLAS: mClasses.load (reader, base); break; | ||||
|             case ESM::REC_FACT: mFactions.load (reader, base); break; | ||||
|             case ESM::REC_RACE: mRaces.load (reader, base); break; | ||||
|             case ESM::REC_SOUN: mSounds.load (reader, base); break; | ||||
|             case ESM::REC_SCPT: mScripts.load (reader, base); break; | ||||
|             case ESM::REC_REGN: mRegions.load (reader, base); break; | ||||
|             case ESM::REC_BSGN: mBirthsigns.load (reader, base); break; | ||||
|             case ESM::REC_SPEL: mSpells.load (reader, base); break; | ||||
| 
 | ||||
|             case ESM::REC_CELL: | ||||
|                 mCells.load (reader, base); | ||||
|                 mRefs.load (reader, mCells.getSize()-1, base); | ||||
|                 break; | ||||
| 
 | ||||
|             case ESM::REC_ACTI: mReferenceables.load (reader, base, UniversalId::Type_Activator); break; | ||||
|             case ESM::REC_ALCH: mReferenceables.load (reader, base, UniversalId::Type_Potion); break; | ||||
|             case ESM::REC_APPA: mReferenceables.load (reader, base, UniversalId::Type_Apparatus); break; | ||||
|             case ESM::REC_ARMO: mReferenceables.load (reader, base, UniversalId::Type_Armor); break; | ||||
|             case ESM::REC_BOOK: mReferenceables.load (reader, base, UniversalId::Type_Book); break; | ||||
|             case ESM::REC_CLOT: mReferenceables.load (reader, base, UniversalId::Type_Clothing); break; | ||||
|             case ESM::REC_CONT: mReferenceables.load (reader, base, UniversalId::Type_Container); break; | ||||
|             case ESM::REC_CREA: mReferenceables.load (reader, base, UniversalId::Type_Creature); break; | ||||
|             case ESM::REC_DOOR: mReferenceables.load (reader, base, UniversalId::Type_Door); break; | ||||
|             case ESM::REC_INGR: mReferenceables.load (reader, base, UniversalId::Type_Ingredient); break; | ||||
|             case ESM::REC_LEVC: | ||||
|                 mReferenceables.load (reader, base, UniversalId::Type_CreatureLevelledList); break; | ||||
|             case ESM::REC_LEVI: | ||||
|                 mReferenceables.load (reader, base, UniversalId::Type_ItemLevelledList); break; | ||||
|             case ESM::REC_LIGH: mReferenceables.load (reader, base, UniversalId::Type_Light); break; | ||||
|             case ESM::REC_LOCK: mReferenceables.load (reader, base, UniversalId::Type_Lockpick); break; | ||||
|             case ESM::REC_MISC: | ||||
|                 mReferenceables.load (reader, base, UniversalId::Type_Miscellaneous); break; | ||||
|             case ESM::REC_NPC_: mReferenceables.load (reader, base, UniversalId::Type_Npc); break; | ||||
|             case ESM::REC_PROB: mReferenceables.load (reader, base, UniversalId::Type_Probe); break; | ||||
|             case ESM::REC_REPA: mReferenceables.load (reader, base, UniversalId::Type_Repair); break; | ||||
|             case ESM::REC_STAT: mReferenceables.load (reader, base, UniversalId::Type_Static); break; | ||||
|             case ESM::REC_WEAP: mReferenceables.load (reader, base, UniversalId::Type_Weapon); break; | ||||
| 
 | ||||
|             case ESM::REC_DIAL: | ||||
|             { | ||||
|                 std::string id = reader.getHNOString ("NAME"); | ||||
| 
 | ||||
|                 ESM::Dialogue record; | ||||
|                 record.mId = id; | ||||
|                 record.load (reader); | ||||
| 
 | ||||
|                 if (record.mType==ESM::Dialogue::Journal) | ||||
|                 { | ||||
|                     mJournals.load (record, base); | ||||
|                     dialogue = &mJournals.getRecord (id).get(); | ||||
|                 } | ||||
|                 else if (record.mType==ESM::Dialogue::Deleted) | ||||
|                 { | ||||
|                     dialogue = 0; // record vector can be shuffled around which would make pointer
 | ||||
|                                   // to record invalid
 | ||||
| 
 | ||||
|                     if (mJournals.tryDelete (id)) | ||||
|                     { | ||||
|                         /// \todo handle info records
 | ||||
|                     } | ||||
|                     else if (mTopics.tryDelete (id)) | ||||
|                     { | ||||
|                         /// \todo handle info records
 | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         /// \todo report deletion of non-existing record
 | ||||
|                     } | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     mTopics.load (record, base); | ||||
|                     dialogue = &mTopics.getRecord (id).get(); | ||||
|                 } | ||||
| 
 | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             case ESM::REC_INFO: | ||||
|             { | ||||
|                 if (!dialogue) | ||||
|                 { | ||||
|                     /// \todo INFO record without matching DIAL record -> report to user
 | ||||
|                     reader.skipRecord(); | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 if (dialogue->mType==ESM::Dialogue::Journal) | ||||
|                     mJournalInfos.load (reader, base, *dialogue); | ||||
|                 else | ||||
|                     mTopicInfos.load (reader, base, *dialogue); | ||||
| 
 | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             case ESM::REC_FILT: | ||||
| 
 | ||||
|                 if (project) | ||||
|                 { | ||||
|                     mFilters.load (reader, base); | ||||
|                     mFilters.setData (mFilters.getSize()-1, | ||||
|                         mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope), | ||||
|                         static_cast<int> (CSMFilter::Filter::Scope_Project)); | ||||
|                     break; | ||||
|                 } | ||||
| 
 | ||||
|                 // fall through (filter record in a content file is an error with format 0)
 | ||||
| 
 | ||||
|             default: | ||||
| 
 | ||||
|                 /// \todo throw an exception instead, once all records are implemented
 | ||||
|                 /// or maybe report error and continue?
 | ||||
|                 reader.skipRecord(); | ||||
|         } | ||||
|         delete mReader; | ||||
|         mReader = 0; | ||||
|         mDialogue = 0; | ||||
|         mRefLoadCache.clear(); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     ESM::NAME n = mReader->getRecName(); | ||||
|     mReader->getRecHeader(); | ||||
| 
 | ||||
|     switch (n.val) | ||||
|     { | ||||
|         case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break; | ||||
|         case ESM::REC_GMST: mGmsts.load (*mReader, mBase); break; | ||||
|         case ESM::REC_SKIL: mSkills.load (*mReader, mBase); break; | ||||
|         case ESM::REC_CLAS: mClasses.load (*mReader, mBase); break; | ||||
|         case ESM::REC_FACT: mFactions.load (*mReader, mBase); break; | ||||
|         case ESM::REC_RACE: mRaces.load (*mReader, mBase); break; | ||||
|         case ESM::REC_SOUN: mSounds.load (*mReader, mBase); break; | ||||
|         case ESM::REC_SCPT: mScripts.load (*mReader, mBase); break; | ||||
|         case ESM::REC_REGN: mRegions.load (*mReader, mBase); break; | ||||
|         case ESM::REC_BSGN: mBirthsigns.load (*mReader, mBase); break; | ||||
|         case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break; | ||||
| 
 | ||||
|         case ESM::REC_CELL: | ||||
|         { | ||||
|             mCells.load (*mReader, mBase); | ||||
|             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 | ||||
|  |  | |||
|  | @ -22,8 +22,12 @@ | |||
| #include <components/esm/loadspel.hpp> | ||||
| #include <components/esm/loaddial.hpp> | ||||
| 
 | ||||
| #include <components/to_utf8/to_utf8.hpp> | ||||
| 
 | ||||
| #include "../filter/filter.hpp" | ||||
| 
 | ||||
| #include "../doc/stage.hpp" | ||||
| 
 | ||||
| #include "idcollection.hpp" | ||||
| #include "universalid.hpp" | ||||
| #include "cell.hpp" | ||||
|  | @ -33,12 +37,19 @@ | |||
| 
 | ||||
| class QAbstractItemModel; | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
|     struct Dialogue; | ||||
| } | ||||
| 
 | ||||
| namespace CSMWorld | ||||
| { | ||||
|     class Data : public QObject | ||||
|     { | ||||
|             Q_OBJECT | ||||
| 
 | ||||
|             ToUTF8::Utf8Encoder mEncoder; | ||||
|             IdCollection<ESM::Global> mGlobals; | ||||
|             IdCollection<ESM::GameSetting> mGmsts; | ||||
|             IdCollection<ESM::Skill> mSkills; | ||||
|  | @ -62,13 +73,18 @@ namespace CSMWorld | |||
|             std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex; | ||||
|             std::string mAuthor; | ||||
|             std::string mDescription; | ||||
|             ESM::ESMReader *mReader; | ||||
|             const ESM::Dialogue *mDialogue; // last loaded dialogue
 | ||||
|             bool mBase; | ||||
|             bool mProject; | ||||
|             std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache; | ||||
| 
 | ||||
|             // not implemented
 | ||||
|             Data (const Data&); | ||||
|             Data& operator= (const Data&); | ||||
| 
 | ||||
|             void addModel (QAbstractItemModel *model, UniversalId::Type type1, | ||||
|                 UniversalId::Type type2 = UniversalId::Type_None, bool update = true); | ||||
|             void addModel (QAbstractItemModel *model, UniversalId::Type type, | ||||
|                 bool update = true); | ||||
| 
 | ||||
|             static void appendIds (std::vector<std::string>& ids, const CollectionBase& collection, | ||||
|                 bool listDeleted); | ||||
|  | @ -78,7 +94,7 @@ namespace CSMWorld | |||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             Data(); | ||||
|             Data (ToUTF8::FromType encoding); | ||||
| 
 | ||||
|             virtual ~Data(); | ||||
| 
 | ||||
|  | @ -167,10 +183,15 @@ namespace CSMWorld | |||
|             void merge(); | ||||
|             ///< Merge modified into base.
 | ||||
| 
 | ||||
|             void loadFile (const boost::filesystem::path& path, bool base, bool project); | ||||
|             ///< Merging content of a file into base or modified.
 | ||||
|             int startLoading (const boost::filesystem::path& path, bool base, bool project); | ||||
|             ///< Begin merging content of a file into base or modified.
 | ||||
|             ///
 | ||||
|             /// \param project load project file instead of content file
 | ||||
|             ///
 | ||||
|             ///< \return estimated number of records
 | ||||
| 
 | ||||
|             bool continueLoading (CSMDoc::Stage::Messages& messages); | ||||
|             ///< \return Finished?
 | ||||
| 
 | ||||
|             bool hasId (const std::string& id) const; | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,9 +6,8 @@ | |||
| #include "collectionbase.hpp" | ||||
| #include "columnbase.hpp" | ||||
| 
 | ||||
| CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering, | ||||
|     Viewing viewing, bool preview) | ||||
| : mIdCollection (idCollection), mReordering (reordering), mViewing (viewing), mPreview (preview) | ||||
| CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features) | ||||
| : mIdCollection (idCollection), mFeatures (features) | ||||
| {} | ||||
| 
 | ||||
| CSMWorld::IdTable::~IdTable() | ||||
|  | @ -18,10 +17,10 @@ int CSMWorld::IdTable::rowCount (const QModelIndex & parent) const | |||
| { | ||||
|     if (hasChildren(parent)) | ||||
|     { | ||||
| 	int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column()); | ||||
| 	return nestedRows; | ||||
|         int nestedRows = mIdCollection->getNestedRowsCount(parent.row(), parent.column()); | ||||
|         return nestedRows; | ||||
|     } | ||||
|        | ||||
| 
 | ||||
|     return mIdCollection->getSize(); | ||||
| } | ||||
| 
 | ||||
|  | @ -29,7 +28,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const | |||
| { | ||||
|     if (parent.isValid()) | ||||
|     { | ||||
| 	return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); | ||||
|         return mIdCollection->getNestedColumnsCount(parent.row(), parent.column()); | ||||
|     } | ||||
| 
 | ||||
|     return mIdCollection->getColumns(); | ||||
|  | @ -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 | ||||
| { | ||||
|     unsigned int encodedId = 0; | ||||
|     if (parent.isValid()) | ||||
|         return QModelIndex(); | ||||
|     { | ||||
|         encodedId = this->foldIndexAdress(parent); | ||||
|     } | ||||
| 
 | ||||
|     if (row<0 || row>=mIdCollection->getSize()) | ||||
|         return QModelIndex(); | ||||
|  | @ -126,7 +128,7 @@ QModelIndex CSMWorld::IdTable::index (int row, int column, const QModelIndex& pa | |||
|     if (column<0 || column>=mIdCollection->getColumns()) | ||||
|         return QModelIndex(); | ||||
| 
 | ||||
|     return createIndex (row, column); | ||||
|     return createIndex(row, column, encodedId); | ||||
| } | ||||
| 
 | ||||
| QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const | ||||
|  | @ -136,14 +138,14 @@ QModelIndex CSMWorld::IdTable::parent (const QModelIndex& index) const | |||
|         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()) | ||||
|     { | ||||
| 	qDebug()<<"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) | ||||
|  | @ -162,15 +164,16 @@ void CSMWorld::IdTable::cloneRecord(const std::string& origin, | |||
|                                     CSMWorld::UniversalId::Type type) | ||||
| { | ||||
|     int index = mIdCollection->getAppendIndex (destination); | ||||
| 
 | ||||
|     beginInsertRows (QModelIndex(), index, index); | ||||
|     mIdCollection->cloneRecord(origin, destination, type); | ||||
|     endInsertRows(); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| ///This method can return only indexes to the top level table cells
 | ||||
| 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) | ||||
|  | @ -218,19 +221,9 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newO | |||
|                 index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1)); | ||||
| } | ||||
| 
 | ||||
| CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const | ||||
| unsigned int CSMWorld::IdTable::getFeatures() const | ||||
| { | ||||
|     return mReordering; | ||||
| } | ||||
| 
 | ||||
| CSMWorld::IdTable::Viewing CSMWorld::IdTable::getViewing() const | ||||
| { | ||||
|     return mViewing; | ||||
| } | ||||
| 
 | ||||
| bool CSMWorld::IdTable::hasPreview() const | ||||
| { | ||||
|     return mPreview; | ||||
|     return mFeatures; | ||||
| } | ||||
| 
 | ||||
| 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 hint; | ||||
| 
 | ||||
|     if (mViewing==Viewing_Cell) | ||||
|     if (mFeatures & Feature_ViewCell) | ||||
|     { | ||||
|         int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell); | ||||
|         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()); | ||||
|         } | ||||
|     } | ||||
|     else if (mViewing==Viewing_Id) | ||||
|     else if (mFeatures & Feature_ViewId) | ||||
|     { | ||||
|         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); | ||||
| } | ||||
| 
 | ||||
| ///For top level data/columns
 | ||||
| int CSMWorld::IdTable::getColumnId(int column) const | ||||
| { | ||||
|     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 out = index.row() * this->columnCount(); | ||||
|     out += index.column(); | ||||
|     ++out; | ||||
|     return out; | ||||
|     return ++out; | ||||
| } | ||||
| 
 | ||||
| std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) const | ||||
| { | ||||
|     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"; | ||||
|     } | ||||
| 
 | ||||
|  | @ -302,3 +287,14 @@ std::pair< int, int > CSMWorld::IdTable::unfoldIndexAdress (unsigned int id) con | |||
|     int column = id - row * this->columnCount(); | ||||
|     return std::make_pair<int, int>(row, column); | ||||
| } | ||||
| 
 | ||||
| bool CSMWorld::IdTable::hasChildren(const QModelIndex& index) const | ||||
| { | ||||
|     return (index.isValid() && | ||||
|             CSMWorld::ColumnBase::Display_Nested == static_cast<CSMWorld::ColumnBase::Display> (headerData | ||||
|                                                                                                 (index.column(), | ||||
|                                                                                                  Qt::Horizontal, | ||||
|                                                                                                  CSMWorld::ColumnBase::Role_Display).toInt()) && | ||||
|             index.internalId() == 0 && | ||||
|             index.data().isValid()); | ||||
| } | ||||
|  |  | |||
|  | @ -8,19 +8,15 @@ | |||
| #include "universalid.hpp" | ||||
| #include "columns.hpp" | ||||
| 
 | ||||
| <<<<<<< Updated upstream | ||||
| ======= | ||||
| /*! \brief
 | ||||
|  * 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 | ||||
|  * to access nested data in the qt way – that is specify parent. The parent is encoded in the internalid of the index model | ||||
|  * See methods fold and unfold adress to see why. This approach has some serious limitations: it allows only | ||||
|  * a single level of the nesting. At the point of creating this code this seemed to be a good enough solution. | ||||
|  * If for some reason it turned out that in fact multiple levels of nesting are needed, change in the addressing of the | ||||
|  * index is most likely the very first to be considered. | ||||
|  * to access nested data in the qt way – that is specify parent. Since some of those nested data require multiple columns to | ||||
|  * represent informations, single int (default way to index model in the qmodelindex) is not sufficiant. Therefore tablemodelindex class | ||||
|  * can hold two ints for the sake of indexing two dimensions of the table. This model does not support multiple levels of the nested | ||||
|  * data. Vast majority of methods makes sense only for the top level data. | ||||
|  */ | ||||
| 
 | ||||
| >>>>>>> Stashed changes | ||||
| namespace CSMWorld | ||||
| { | ||||
|     class CollectionBase; | ||||
|  | @ -32,43 +28,38 @@ namespace CSMWorld | |||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             enum Reordering | ||||
|             enum Features | ||||
|             { | ||||
|                 Reordering_None, | ||||
|                 Reordering_WithinTopic | ||||
|             }; | ||||
|                 Feature_ReorderWithinTopic = 1, | ||||
| 
 | ||||
|             enum Viewing | ||||
|             { | ||||
|                 Viewing_None, | ||||
|                 Viewing_Id, // use ID column to generate view request (ID is transformed into
 | ||||
|                             // worldspace and original ID is passed as hint with c: prefix)
 | ||||
|                 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)
 | ||||
|                 /// Use ID column to generate view request (ID is transformed into
 | ||||
|                 /// worldspace and original ID is passed as hint with c: prefix).
 | ||||
|                 Feature_ViewId = 2, | ||||
| 
 | ||||
|                 /// Use cell column to generate view request (cell ID is transformed
 | ||||
|                 /// 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: | ||||
| 
 | ||||
|             CollectionBase *mIdCollection; | ||||
|             Reordering mReordering; | ||||
|             Viewing mViewing; | ||||
|             unsigned int mFeatures; | ||||
|             bool mPreview; | ||||
| 
 | ||||
|             // not implemented
 | ||||
|             IdTable (const IdTable&); | ||||
|             IdTable& operator= (const IdTable&); | ||||
| <<<<<<< Updated upstream | ||||
| ======= | ||||
| 
 | ||||
|             unsigned int foldIndexAdress(const QModelIndex& index) const; | ||||
| 
 | ||||
|             std::pair<int, int> unfoldIndexAdress(unsigned int id) const; | ||||
| >>>>>>> Stashed changes | ||||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_None, | ||||
|                 Viewing viewing = Viewing_None, bool preview = false); | ||||
|             IdTable (CollectionBase *idCollection, unsigned int features = 0); | ||||
|             ///< The ownership of \a idCollection is not transferred.
 | ||||
| 
 | ||||
|             virtual ~IdTable(); | ||||
|  | @ -91,8 +82,8 @@ namespace CSMWorld | |||
|                 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); | ||||
|             ///< \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
 | ||||
|             /// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
 | ||||
| 
 | ||||
|             Reordering getReordering() const; | ||||
| 
 | ||||
|             Viewing getViewing() const; | ||||
| 
 | ||||
|             bool hasPreview() const; | ||||
|             unsigned int getFeatures() const; | ||||
| 
 | ||||
|             std::pair<UniversalId, std::string> view (int row) const; | ||||
|             ///< Return the UniversalId and the hint for viewing \a row. If viewing is not
 | ||||
|  |  | |||
|  | @ -1,12 +1,10 @@ | |||
| 
 | ||||
| #include "ref.hpp" | ||||
| 
 | ||||
| #include "cell.hpp" | ||||
| 
 | ||||
| void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string& id) | ||||
| CSMWorld::CellRef::CellRef() | ||||
| { | ||||
|     mId = id; | ||||
|     mCell = cell.mId; | ||||
|     mRefNum.mIndex = 0; | ||||
| 
 | ||||
|     cell.addRef (mId); | ||||
|     // special marker: This reference does not have a RefNum assign to it yet.
 | ||||
|     mRefNum.mContentFile = -2; | ||||
| } | ||||
|  | @ -3,11 +3,6 @@ | |||
| 
 | ||||
| #include <components/esm/cellref.hpp> | ||||
| 
 | ||||
| namespace ESM | ||||
| { | ||||
|     class ESMReader; | ||||
| } | ||||
| 
 | ||||
| namespace CSMWorld | ||||
| { | ||||
|     class Cell; | ||||
|  | @ -18,8 +13,7 @@ namespace CSMWorld | |||
|         std::string mId; | ||||
|         std::string mCell; | ||||
| 
 | ||||
|         void load (ESM::ESMReader &esm, Cell& cell, const std::string& id); | ||||
|         ///< Load cell ref and register it with \a cell.
 | ||||
|         CellRef(); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,12 +3,15 @@ | |||
| 
 | ||||
| #include <sstream> | ||||
| 
 | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include "ref.hpp" | ||||
| #include "cell.hpp" | ||||
| #include "universalid.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); | ||||
| 
 | ||||
|  | @ -17,19 +20,73 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool | |||
|     CellRef ref; | ||||
| 
 | ||||
|     bool deleted = false; | ||||
|     while (cell2.getNextRef (reader, ref, deleted)) | ||||
| 
 | ||||
|     while (ESM::Cell::getNextRef (reader, ref, deleted)) | ||||
|     { | ||||
|         /// \todo handle deleted and moved references
 | ||||
|         ref.load (reader, cell2, getNewId()); | ||||
|         ref.mCell = cell2.mId; | ||||
| 
 | ||||
|         Record<CellRef> record2; | ||||
|         record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly; | ||||
|         (base ? record2.mBase : record2.mModified) = ref; | ||||
|         /// \todo handle moved references
 | ||||
| 
 | ||||
|         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() | ||||
|  |  | |||
|  | @ -1,6 +1,10 @@ | |||
| #ifndef CSM_WOLRD_REFCOLLECTION_H | ||||
| #define CSM_WOLRD_REFCOLLECTION_H | ||||
| 
 | ||||
| #include <map> | ||||
| 
 | ||||
| #include "../doc/stage.hpp" | ||||
| 
 | ||||
| #include "collection.hpp" | ||||
| #include "ref.hpp" | ||||
| #include "record.hpp" | ||||
|  | @ -22,7 +26,9 @@ namespace CSMWorld | |||
|               : 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.
 | ||||
| 
 | ||||
|             std::string getNewId(); | ||||
|  |  | |||
|  | @ -1,14 +1,13 @@ | |||
| 
 | ||||
| #include "refidadapter.hpp" | ||||
| 
 | ||||
| #include "cassert" | ||||
| #include <QVariant> | ||||
| 
 | ||||
| CSMWorld::RefIdAdapter::RefIdAdapter() {} | ||||
| 
 | ||||
| <<<<<<< Updated upstream | ||||
| CSMWorld::RefIdAdapter::~RefIdAdapter() {} | ||||
| ======= | ||||
| CSMWorld::RefIdAdapter::~RefIdAdapter() {} | ||||
| 
 | ||||
| CSMWorld::NestedRefIdAdapter::NestedRefIdAdapter() {} | ||||
| 
 | ||||
| CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {} | ||||
| >>>>>>> Stashed changes | ||||
| CSMWorld::NestedRefIdAdapter::~NestedRefIdAdapter() {} | ||||
|  | @ -43,15 +43,14 @@ namespace CSMWorld | |||
|             virtual ~NestedRefIdAdapter(); | ||||
|   | ||||
|             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, | ||||
| 					    int index, int subRowIndex, int subColIndex) const = 0; | ||||
|        | ||||
|        | ||||
| 	    virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const = 0; | ||||
|             virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, | ||||
|                                         int index, int subRowIndex, int subColIndex) 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; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -175,35 +175,31 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa | |||
| } | ||||
| 
 | ||||
| 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), | ||||
|   mOrganic (organic), mRespawn (respawn) | ||||
|   mOrganic (organic), mRespawn (respawn), mContent(content) | ||||
| {} | ||||
| 
 | ||||
| int CSMWorld::ContainerRefIdAdapter::getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const | ||||
| { | ||||
|     qDebug()<<"getting nested columns count"; | ||||
|     if (column==mContent) | ||||
|     { | ||||
| 	return 2; | ||||
|         return 2; | ||||
|     } else { | ||||
| 	throw "Trying to obtain nested columns count, but column does not have nested columns!"; | ||||
|         throw "Trying to obtain nested columns count, but column does not have nested columns!"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| int CSMWorld::ContainerRefIdAdapter::getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const | ||||
| { | ||||
|     qDebug()<<"getting nested rows count"; | ||||
|     const Record<ESM::Container>& record = static_cast<const Record<ESM::Container>&> ( | ||||
|         data.getRecord(RefIdData::LocalIndex (index, UniversalId::Type_Container))); | ||||
| 
 | ||||
|     qDebug() <<  "exception above"; | ||||
|     if (column==mContent) | ||||
|     { | ||||
| 	qDebug() <<  record.get().mInventory.mList.size(); | ||||
| 	return record.get().mInventory.mList.size(); | ||||
|         return record.get().mInventory.mList.size(); | ||||
|     } else { | ||||
| 	throw "Trying to obtain nested rows count, but column does not have nested columns!"; | ||||
|         throw "Trying to obtain nested rows count, but column does not have nested columns!"; | ||||
|     } | ||||
| } | ||||
| QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, const RefIdData& data, | ||||
|  | @ -220,9 +216,9 @@ QVariant CSMWorld::ContainerRefIdAdapter::getData (const RefIdColumn *column, co | |||
| 
 | ||||
|     if (column==mRespawn) | ||||
|         return (record.get().mFlags & ESM::Container::Respawn)!=0; | ||||
|      | ||||
| 
 | ||||
|     if (column==mContent) | ||||
| 	return true; | ||||
|         return true; | ||||
| 
 | ||||
|     return NameRefIdAdapter<ESM::Container>::getData (column, data, index); | ||||
| } | ||||
|  | @ -253,16 +249,14 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD | |||
|         NameRefIdAdapter<ESM::Container>::setData (column, data, index, value); | ||||
| } | ||||
| 
 | ||||
| <<<<<<< Updated upstream | ||||
| ======= | ||||
| void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, RefIdData& data, | ||||
|                                               int row, | ||||
|                                               int index, | ||||
|                                               const QVariant& value, | ||||
|                                               int subRowIndex, | ||||
|                                               int subColIndex) const | ||||
| { | ||||
|     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) | ||||
|     { | ||||
|  | @ -286,12 +280,11 @@ void CSMWorld::ContainerRefIdAdapter::setNestedData(const RefIdColumn *column, R | |||
| } | ||||
| 
 | ||||
| QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdColumn* column, | ||||
| 							 const CSMWorld::RefIdData& data, | ||||
| 							 int index, | ||||
| 							 int subRowIndex, | ||||
| 							 int subColIndex) const | ||||
|                                                         const CSMWorld::RefIdData& data, | ||||
|                                                         int index, | ||||
|                                                         int subRowIndex, | ||||
|                                                         int subColIndex) const | ||||
| { | ||||
|     qDebug()<<"Accessing content column"; | ||||
|     const Record<ESM::Container>& record = static_cast<const Record<ESM::Container>&> ( | ||||
|         data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); | ||||
| 
 | ||||
|  | @ -317,7 +310,6 @@ QVariant CSMWorld::ContainerRefIdAdapter::getNestedData (const CSMWorld::RefIdCo | |||
| } | ||||
| 
 | ||||
| 
 | ||||
| >>>>>>> Stashed changes | ||||
| CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) | ||||
| : ActorColumns (actorColumns) | ||||
| {} | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ namespace CSMWorld | |||
|             BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base); | ||||
| 
 | ||||
|             virtual std::string getId (const RecordBase& record) const; | ||||
|              | ||||
| 
 | ||||
|             virtual void setId (RecordBase& record, const std::string& id); | ||||
| 
 | ||||
|             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; | ||||
|     } | ||||
|      | ||||
| 
 | ||||
|     template<typename RecordT> | ||||
|     std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const | ||||
|     { | ||||
|  | @ -611,33 +611,27 @@ namespace CSMWorld | |||
|             const RefIdColumn *mWeight; | ||||
|             const RefIdColumn *mOrganic; | ||||
|             const RefIdColumn *mRespawn; | ||||
|             const RefIdColumn *mContent; | ||||
| 
 | ||||
|         public: | ||||
| 
 | ||||
|             ContainerRefIdAdapter (const NameColumns& columns, const RefIdColumn *weight, | ||||
| <<<<<<< Updated upstream | ||||
|                 const RefIdColumn *organic, const RefIdColumn *respawn); | ||||
| ======= | ||||
| 				   const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); | ||||
|                                    const RefIdColumn *organic, const RefIdColumn *respawn, const RefIdColumn *content); | ||||
| 
 | ||||
|             virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, | ||||
| 					    int index, int subRowIndex, int subColIndex) const; | ||||
| >>>>>>> Stashed changes | ||||
|             virtual QVariant getNestedData (const RefIdColumn *column, const RefIdData& data, int index, | ||||
|                                             int subRowIndex, int subColIndex) const; | ||||
| 
 | ||||
| 	    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, | ||||
| 					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, | ||||
| 				  const QVariant& value) const; | ||||
|                                   const QVariant& value) const; | ||||
|             ///< If the data type does not match an exception is thrown.
 | ||||
|        | ||||
| 
 | ||||
|             virtual int getNestedColumnsCount(const RefIdColumn *column, const RefIdData& data) const; | ||||
|        | ||||
| 
 | ||||
|             virtual int getNestedRowsCount(const RefIdColumn *column, const RefIdData& data, int index) const; | ||||
|     }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -166,6 +166,9 @@ CSMWorld::RefIdCollection::RefIdCollection() | |||
|     mColumns.push_back (RefIdColumn (Columns::ColumnId_Respawn, ColumnBase::Display_Boolean)); | ||||
|     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); | ||||
| 
 | ||||
|     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)); | ||||
|     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)); | ||||
|         weaponColumns.mChop[i] = &mColumns.back(); | ||||
|         const RefIdColumn **column = | ||||
|             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 | ||||
|  | @ -341,7 +351,7 @@ CSMWorld::RefIdCollection::RefIdCollection() | |||
|     mAdapters.insert (std::make_pair (UniversalId::Type_Clothing, | ||||
|         new ClothingRefIdAdapter (enchantableColumns, clothingType))); | ||||
|     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, | ||||
|         new CreatureRefIdAdapter (creatureColumns))); | ||||
|     mAdapters.insert (std::make_pair (UniversalId::Type_Door, | ||||
|  | @ -417,19 +427,15 @@ QVariant CSMWorld::RefIdCollection::getData (int index, int column) const | |||
|     return adaptor.getData (&mColumns.at (column), mData, localIndex.first); | ||||
| } | ||||
| 
 | ||||
| <<<<<<< Updated upstream | ||||
| ======= | ||||
| QVariant CSMWorld::RefIdCollection::getNestedData (int row, int column, int subRow, int subColumn) const | ||||
| { | ||||
|     RefIdData::LocalIndex localIndex = mData.globalToLocalIndex(row); | ||||
| 
 | ||||
|     const CSMWorld::NestedRefIdAdapter& adaptor = dynamic_cast<const CSMWorld::NestedRefIdAdapter&>(findAdaptor (localIndex.second)); | ||||
| 
 | ||||
|     //if this overloaded, base class method was not overriden, crash will happen (assert(false)) Don't try to use this method for non-nested columns!
 | ||||
|     return adaptor.getNestedData (&mColumns.at (column), mData, localIndex.first, subRow, subColumn); | ||||
| } | ||||
| 
 | ||||
| >>>>>>> Stashed changes | ||||
| void CSMWorld::RefIdCollection::setData (int index, int column, const QVariant& data) | ||||
| { | ||||
|     RefIdData::LocalIndex localIndex = mData.globalToLocalIndex (index); | ||||
|  |  | |||
|  | @ -55,9 +55,9 @@ namespace CSMWorld | |||
| 
 | ||||
|             virtual int getSize() const; | ||||
| 
 | ||||
| 	    virtual int getNestedRowsCount(int row, int column) const; | ||||
|             virtual int getNestedRowsCount(int row, int column) const; | ||||
| 
 | ||||
| 	    virtual int getNestedColumnsCount(int row, int column) const; | ||||
|             virtual int getNestedColumnsCount(int row, int column) const; | ||||
| 
 | ||||
|             virtual std::string getId (int index) const; | ||||
| 
 | ||||
|  | @ -69,13 +69,15 @@ namespace CSMWorld | |||
| 
 | ||||
|             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 setNestedData(int row, int column, const QVariant& data, int subRow, int subColumn); | ||||
| 
 | ||||
|             virtual void removeRows (int index, int count); | ||||
| 
 | ||||
|             virtual void cloneRecord(const std::string& origin,  | ||||
|             virtual void cloneRecord(const std::string& origin, | ||||
|                                      const std::string& destination, | ||||
|                                      const UniversalId::Type type); | ||||
| 
 | ||||
|  |  | |||
|  | @ -231,27 +231,27 @@ namespace CSMWorld | |||
| 
 | ||||
|             void save (int index, ESM::ESMWriter& writer) const; | ||||
| 
 | ||||
| 	    //RECORD CONTAINERS ACCESS METHODS
 | ||||
| 	    const RefIdDataContainer<ESM::Book>& getBooks() const; | ||||
| 	    const RefIdDataContainer<ESM::Activator>& getActivators() const; | ||||
| 	    const RefIdDataContainer<ESM::Potion>& getPotions() const; | ||||
| 	    const RefIdDataContainer<ESM::Apparatus>& getApparati() const; | ||||
| 	    const RefIdDataContainer<ESM::Armor>& getArmors() const; | ||||
| 	    const RefIdDataContainer<ESM::Clothing>& getClothing() const; | ||||
| 	    const RefIdDataContainer<ESM::Container>& getContainers() const; | ||||
| 	    const RefIdDataContainer<ESM::Creature>& getCreatures() const; | ||||
| 	    const RefIdDataContainer<ESM::Door>& getDoors() const; | ||||
| 	    const RefIdDataContainer<ESM::Ingredient>& getIngredients() const; | ||||
| 	    const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const; | ||||
| 	    const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const; | ||||
| 	    const RefIdDataContainer<ESM::Light>& getLights() const; | ||||
| 	    const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const; | ||||
| 	    const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const; | ||||
| 	    const RefIdDataContainer<ESM::NPC>& getNPCs() const; | ||||
| 	    const RefIdDataContainer<ESM::Weapon >& getWeapons() const; | ||||
| 	    const RefIdDataContainer<ESM::Probe >& getProbes() const; | ||||
| 	    const RefIdDataContainer<ESM::Repair>& getRepairs() const; | ||||
| 	    const RefIdDataContainer<ESM::Static>& getStatics() const; | ||||
|         //RECORD CONTAINERS ACCESS METHODS
 | ||||
|             const RefIdDataContainer<ESM::Book>& getBooks() const; | ||||
|             const RefIdDataContainer<ESM::Activator>& getActivators() const; | ||||
|             const RefIdDataContainer<ESM::Potion>& getPotions() const; | ||||
|             const RefIdDataContainer<ESM::Apparatus>& getApparati() const; | ||||
|             const RefIdDataContainer<ESM::Armor>& getArmors() const; | ||||
|             const RefIdDataContainer<ESM::Clothing>& getClothing() const; | ||||
|             const RefIdDataContainer<ESM::Container>& getContainers() const; | ||||
|             const RefIdDataContainer<ESM::Creature>& getCreatures() const; | ||||
|             const RefIdDataContainer<ESM::Door>& getDoors() const; | ||||
|             const RefIdDataContainer<ESM::Ingredient>& getIngredients() const; | ||||
|             const RefIdDataContainer<ESM::CreatureLevList>& getCreatureLevelledLists() const; | ||||
|             const RefIdDataContainer<ESM::ItemLevList>& getItemLevelledList() const; | ||||
|             const RefIdDataContainer<ESM::Light>& getLights() const; | ||||
|             const RefIdDataContainer<ESM::Lockpick>& getLocpicks() const; | ||||
|             const RefIdDataContainer<ESM::Miscellaneous>& getMiscellaneous() const; | ||||
|             const RefIdDataContainer<ESM::NPC>& getNPCs() const; | ||||
|             const RefIdDataContainer<ESM::Weapon >& getWeapons() const; | ||||
|             const RefIdDataContainer<ESM::Probe >& getProbes() const; | ||||
|             const RefIdDataContainer<ESM::Repair>& getRepairs() const; | ||||
|             const RefIdDataContainer<ESM::Static>& getStatics() const; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,9 @@ | |||
| #include "tablemimedata.hpp" | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include <QDebug> | ||||
| 
 | ||||
| #include "universalid.hpp" | ||||
| #include "columnbase.hpp" | ||||
| 
 | ||||
|  | @ -11,7 +14,7 @@ mDocument(document) | |||
|     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) | ||||
| { | ||||
|     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()) | ||||
|     { | ||||
|         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; | ||||
|  | @ -50,7 +54,7 @@ std::string CSMWorld::TableMimeData::getIcon() const | |||
| 
 | ||||
|         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(); | ||||
|  | @ -531,4 +535,4 @@ CSMWorld::ColumnBase::Display CSMWorld::TableMimeData::convertEnums (CSMWorld::U | |||
| const CSMDoc::Document* CSMWorld::TableMimeData::getDocumentPtr() const | ||||
| { | ||||
|     return &mDocument; | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -33,7 +33,7 @@ namespace CSMWorld | |||
|         public: | ||||
|             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(); | ||||
| 
 | ||||
|  | @ -56,6 +56,7 @@ namespace CSMWorld | |||
|             UniversalId returnMatching(CSMWorld::ColumnBase::Display type) const; | ||||
| 
 | ||||
|             static CSMWorld::UniversalId::Type convertEnums(CSMWorld::ColumnBase::Display type); | ||||
| 
 | ||||
|             static CSMWorld::ColumnBase::Display convertEnums(CSMWorld::UniversalId::Type type); | ||||
| 
 | ||||
|         private: | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ namespace | |||
| 
 | ||||
|     static const TypeData sNoArg[] = | ||||
|     { | ||||
|         { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "empty", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, "-", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Globals, "Global Variables", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Gmsts, "Game Settings", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Skills, "Skills", 0 }, | ||||
|  | @ -61,9 +61,10 @@ namespace | |||
|         { 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_Journal, "Journal", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_JournalInfo, "JournalInfo", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_SubRecord, CSMWorld::UniversalId::Type_TopicInfo, "TopicInfo", 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_Missing, "Cell", ":./cell.png" }, | ||||
|         { 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_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_Weapon, "Weapon", ":./weapon.png" }, | ||||
|         { 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_Preview, "Preview", 0 }, | ||||
|  | @ -100,6 +101,7 @@ namespace | |||
|     static const TypeData sIndexArg[] = | ||||
|     { | ||||
|         { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_VerificationResults, "Verification Results", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_LoadErrorLog, "Load Error Log", 0 }, | ||||
|         { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
 | ||||
|     }; | ||||
| } | ||||
|  | @ -318,6 +320,28 @@ std::vector<CSMWorld::UniversalId::Type> CSMWorld::UniversalId::listReferenceabl | |||
|     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) | ||||
| { | ||||
|     return left.isEqual (right); | ||||
|  |  | |||
|  | @ -32,6 +32,8 @@ namespace CSMWorld | |||
|                 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 | ||||
|             { | ||||
|                 Type_None = 0, | ||||
|  | @ -60,6 +62,7 @@ namespace CSMWorld | |||
|                 Type_Spell, | ||||
|                 Type_Cells, | ||||
|                 Type_Cell, | ||||
|                 Type_Cell_Missing, //For cells that does not exist yet.
 | ||||
|                 Type_Referenceables, | ||||
|                 Type_Referenceable, | ||||
|                 Type_Activator, | ||||
|  | @ -85,8 +88,8 @@ namespace CSMWorld | |||
|                 Type_References, | ||||
|                 Type_Reference, | ||||
|                 Type_RegionMap, | ||||
|                 Type_Filter, | ||||
|                 Type_Filters, | ||||
|                 Type_Filter, | ||||
|                 Type_Topics, | ||||
|                 Type_Topic, | ||||
|                 Type_Journals, | ||||
|  | @ -96,10 +99,11 @@ namespace CSMWorld | |||
|                 Type_JournalInfos, | ||||
|                 Type_JournalInfo, | ||||
|                 Type_Scene, | ||||
|                 Type_Preview | ||||
|                 Type_Preview, | ||||
|                 Type_LoadErrorLog | ||||
|             }; | ||||
| 
 | ||||
|             enum { NumberOfTypes = Type_Scene+1 }; | ||||
|             enum { NumberOfTypes = Type_LoadErrorLog+1 }; | ||||
| 
 | ||||
|         private: | ||||
| 
 | ||||
|  | @ -145,6 +149,11 @@ namespace CSMWorld | |||
|             ///< Will return an empty string, if no icon is available.
 | ||||
| 
 | ||||
|             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); | ||||
|  |  | |||
							
								
								
									
										193
									
								
								apps/opencs/view/doc/loader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								apps/opencs/view/doc/loader.cpp
									
									
									
									
									
										Normal 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); | ||||
| } | ||||
							
								
								
									
										99
									
								
								apps/opencs/view/doc/loader.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								apps/opencs/view/doc/loader.hpp
									
									
									
									
									
										Normal 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
		Loading…
	
		Reference in a new issue