Merge branch 'master' into HEAD

Conflicts:
	CMakeLists.txt
	apps/launcher/CMakeLists.txt
loadfix
scrawl 10 years ago
commit 4fa303d7c4

3
.gitignore vendored

@ -37,11 +37,12 @@ resources
/omwlauncher /omwlauncher
/openmw /openmw
/opencs /opencs
/niftest
## generated objects ## generated objects
apps/openmw/config.hpp apps/openmw/config.hpp
components/version/version.hpp components/version/version.hpp
Docs/mainpage.hpp docs/mainpage.hpp
moc_*.cxx moc_*.cxx
*.cxx_parameters *.cxx_parameters
*qrc_launcher.cxx *qrc_launcher.cxx

@ -1,38 +1,25 @@
os:
- linux
- osx
language: cpp language: cpp
compiler:
- gcc
branches: branches:
only: only:
- master - master
- /openmw-.*$/ - /openmw-.*$/
before_install: before_install:
- pwd - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_install.linux.sh; fi
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse" - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_install.osx.sh; fi
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
- sudo apt-get update -qq
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock
- sudo apt-get install -qq libqt4-dev
- sudo apt-get install -qq libopenal-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
- sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1
- sudo make -j4
- sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
- sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so
before_script: before_script:
- cd - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./CI/before_script.linux.sh; fi
- mkdir build - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
- cd build
- cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DBUILD_WITH_DPKG=1
script: script:
- cd ./build
- make -j4 - make -j4
after_script: after_script:
- ./openmw_test_suite - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi
notifications: notifications:
recipients: recipients:
- lgromanowski+travis.ci@gmail.com - corrmage+travis-ci@gmail.com
email: email:
on_success: change on_success: change
on_failure: always on_failure: always

@ -0,0 +1,18 @@
#!/bin/sh
export CXX=g++
export CC=gcc
echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
echo "yes" | sudo apt-add-repository ppa:openmw/openmw
sudo apt-get update -qq
sudo apt-get install -qq libgtest-dev google-mock
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
sudo mkdir /usr/src/gtest/build
cd /usr/src/gtest/build
sudo cmake .. -DBUILD_SHARED_LIBS=1
sudo make -j4
sudo ln -s /usr/src/gtest/build/libgtest.so /usr/lib/libgtest.so
sudo ln -s /usr/src/gtest/build/libgtest_main.so /usr/lib/libgtest_main.so

@ -0,0 +1,9 @@
#!/bin/sh
export CXX=clang++
export CC=clang
brew tap openmw/openmw
brew update
brew unlink boost
brew install cmake openmw-mygui openmw-bullet openmw-sdl2 openmw-ffmpeg pkg-config qt unshield

@ -0,0 +1,5 @@
#!/bin/sh
mkdir build
cd build
cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE

@ -0,0 +1,5 @@
#!/bin/sh
mkdir build
cd build
cmake -DCMAKE_FRAMEWORK_PATH="/usr/local/lib/macosx/Release" -DCMAKE_EXE_LINKER_FLAGS="-F/usr/local/lib/macosx/Release" -DCMAKE_CXX_FLAGS="-stdlib=libstdc++" -DCMAKE_BUILD_TYPE=Debug -DBUILD_MYGUI_PLUGIN=OFF -G"Unix Makefiles" ..

@ -12,8 +12,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
message(STATUS "Configuring OpenMW...") message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0) set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 30) set(OPENMW_VERSION_MINOR 33)
set(OPENMW_VERSION_RELEASE 0) set(OPENMW_VERSION_RELEASE 1)
set(OPENMW_VERSION_COMMITHASH "") set(OPENMW_VERSION_COMMITHASH "")
set(OPENMW_VERSION_TAGHASH "") set(OPENMW_VERSION_TAGHASH "")
@ -54,9 +54,13 @@ endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
# Macros # Macros
include(OpenMWMacros) include(OpenMWMacros)
if (ANDROID)
set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}")
endif (ANDROID)
# doxygen main page # doxygen main page
configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp") configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_DIR}/docs/mainpage.hpp")
option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE) option(MYGUI_STATIC "Link static build of Mygui into the binaries" FALSE)
option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE)
@ -66,38 +70,30 @@ option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE) option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
# Apps and tools # Apps and tools
option(BUILD_BSATOOL "build BSA extractor" OFF) option(BUILD_BSATOOL "build BSA extractor" ON)
option(BUILD_ESMTOOL "build ESM inspector" ON) option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON) option(BUILD_LAUNCHER "build Launcher" ON)
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON) option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
option(BUILD_OPENCS "build OpenMW Construction Set" ON) option(BUILD_OPENCS "build OpenMW Construction Set" ON)
option(BUILD_WIZARD "build Installation Wizard" ON) option(BUILD_WIZARD "build Installation Wizard" ON)
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF) option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" OFF)
option(BUILD_NIFTEST "build nif file tester" OFF)
# Sound source selection option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
option(USE_FFMPEG "use ffmpeg for sound" ON)
# OS X deployment # OS X deployment
option(OPENMW_OSX_DEPLOYMENT OFF) option(OPENMW_OSX_DEPLOYMENT OFF)
if(UNIX AND NOT APPLE)
option(BUILD_WITH_DPKG "enable dpkg-based install for debian and debian derivatives" OFF)
if(BUILD_WITH_DPKG)
find_program(DPKG_PROGRAM dpkg DOC "dpkg program of Debian-based systems")
endif(BUILD_WITH_DPKG)
endif(UNIX AND NOT APPLE)
# Location of morrowind data files # Location of morrowind data files
if (APPLE) if (APPLE)
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files") set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
set(MORROWIND_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files") set(OPENMW_RESOURCE_FILES "./resources" CACHE PATH "location of OpenMW resources files")
elseif(UNIX) elseif(UNIX)
set(MORROWIND_DATA_FILES "/usr/share/games/openmw/data/" CACHE PATH "location of Morrowind data files") set(MORROWIND_DATA_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/data/" CACHE PATH "location of Morrowind data files")
set(MORROWIND_RESOURCE_FILES "/usr/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files") set(OPENMW_RESOURCE_FILES "${CMAKE_INSTALL_PREFIX}/share/games/openmw/resources/" CACHE PATH "location of OpenMW resources files")
else() else()
set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files") set(MORROWIND_DATA_FILES "data" CACHE PATH "location of Morrowind data files")
set(MORROWIND_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files") set(OPENMW_RESOURCE_FILES "resources" CACHE PATH "location of OpenMW resources files")
endif(APPLE) endif(APPLE)
if (WIN32) if (WIN32)
@ -109,33 +105,32 @@ cmake_minimum_required(VERSION 2.6)
# source directory: libs # source directory: libs
set(LIBDIR ${CMAKE_SOURCE_DIR}/libs) set(LIBS_DIR ${CMAKE_SOURCE_DIR}/libs)
set(OENGINE_OGRE set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp ${LIBS_DIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/fader.cpp ${LIBS_DIR}/openengine/ogre/lights.cpp
${LIBDIR}/openengine/ogre/lights.cpp ${LIBS_DIR}/openengine/ogre/selectionbuffer.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp ${LIBS_DIR}/openengine/ogre/imagerotate.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
) )
set(OENGINE_GUI set(OENGINE_GUI
${LIBDIR}/openengine/gui/loglistener.cpp ${LIBS_DIR}/openengine/gui/loglistener.cpp
${LIBDIR}/openengine/gui/manager.cpp ${LIBS_DIR}/openengine/gui/manager.cpp
${LIBDIR}/openengine/gui/layout.hpp ${LIBS_DIR}/openengine/gui/layout.hpp
) )
set(OENGINE_BULLET set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/BtOgre.cpp ${LIBS_DIR}/openengine/bullet/BtOgre.cpp
${LIBDIR}/openengine/bullet/BtOgreExtras.h ${LIBS_DIR}/openengine/bullet/BtOgreExtras.h
${LIBDIR}/openengine/bullet/BtOgreGP.h ${LIBS_DIR}/openengine/bullet/BtOgreGP.h
${LIBDIR}/openengine/bullet/BtOgrePG.h ${LIBS_DIR}/openengine/bullet/BtOgrePG.h
${LIBDIR}/openengine/bullet/physic.cpp ${LIBS_DIR}/openengine/bullet/physic.cpp
${LIBDIR}/openengine/bullet/physic.hpp ${LIBS_DIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.cpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.h ${LIBS_DIR}/openengine/bullet/BulletShapeLoader.h
${LIBDIR}/openengine/bullet/trace.cpp ${LIBS_DIR}/openengine/bullet/trace.cpp
${LIBDIR}/openengine/bullet/trace.h ${LIBS_DIR}/openengine/bullet/trace.h
) )
@ -146,32 +141,24 @@ set(OPENMW_LIBS ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER) set(OPENMW_LIBS_HEADER)
# Sound setup # Sound setup
set(GOT_SOUND_INPUT 0) set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
set(SOUND_INPUT_INCLUDES "") unset(FFMPEG_LIBRARIES CACHE)
set(SOUND_INPUT_LIBRARY "") find_package(FFmpeg)
set(SOUND_DEFINE "") if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND )
if (USE_FFMPEG) message(FATAL_ERROR "FFmpeg component required, but not found!")
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE) endif()
find_package(FFmpeg) set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
if (FFMPEG_FOUND) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS}) if( SWRESAMPLE_FOUND )
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES}) add_definitions(-DHAVE_LIBSWRESAMPLE)
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
set(GOT_SOUND_INPUT 1) else()
endif (FFMPEG_FOUND) if( AVRESAMPLE_FOUND )
endif (USE_FFMPEG) set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
else()
if (NOT GOT_SOUND_INPUT) message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
message(WARNING "--------------------") endif()
message(WARNING "Failed to find any sound input packages") endif()
message(WARNING "--------------------")
endif (NOT GOT_SOUND_INPUT)
if (NOT FFMPEG_FOUND)
message(WARNING "--------------------")
message(WARNING "FFmpeg not found, video playback will be disabled")
message(WARNING "--------------------")
endif (NOT FFMPEG_FOUND)
# TinyXML # TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF) option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
@ -235,32 +222,74 @@ IF(BOOST_STATIC)
endif() endif()
find_package(OGRE REQUIRED) find_package(OGRE REQUIRED)
if (${OGRE_VERSION} VERSION_LESS "1.9")
message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org")
endif()
find_package(MyGUI REQUIRED) find_package(MyGUI REQUIRED)
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info")
endif()
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(SDL2 REQUIRED) find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED) find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED) find_package(Bullet REQUIRED)
IF(OGRE_STATIC)
find_package(Cg) set(OGRE_PLUGIN_INCLUDE_DIRS "")
IF(WIN32) set(OGRE_STATIC_PLUGINS "")
set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_Direct3D9_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS})
ELSE(WIN32) macro(add_static_ogre_plugin PLUGIN)
set(OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_Plugin_CgProgramManager_INCLUDE_DIRS} ${OGRE_Plugin_OctreeSceneManager_INCLUDE_DIRS} ${OGRE_Plugin_ParticleFX_INCLUDE_DIRS} ${OGRE_RenderSystem_GL_INCLUDE_DIRS}) if(OGRE_${PLUGIN}_FOUND)
ENDIF(WIN32) # strip RenderSystem_ or Plugin_ prefix from plugin name
ENDIF(OGRE_STATIC) string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN})
string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP})
add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME})
list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS})
list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES})
endif(OGRE_${PLUGIN}_FOUND)
endmacro(add_static_ogre_plugin)
if(OGRE_STATIC)
# set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS
add_static_ogre_plugin(Plugin_OctreeSceneManager)
add_static_ogre_plugin(Plugin_ParticleFX)
find_package(Cg)
if(Cg_FOUND)
add_static_ogre_plugin(Plugin_CgProgramManager)
list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES})
endif(Cg_FOUND)
if (ANDROID)
add_static_ogre_plugin(RenderSystem_GLES2)
else ()
add_static_ogre_plugin(RenderSystem_GL)
endif ()
if(WIN32)
add_static_ogre_plugin(RenderSystem_Direct3D9)
endif(WIN32)
endif(OGRE_STATIC)
include_directories("." include_directories("."
${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_PLUGIN_INCLUDE_DIRS} ${OGRE_INCLUDE_DIR} ${OGRE_INCLUDE_DIR}/Ogre ${OGRE_INCLUDE_DIR}/OGRE ${OGRE_INCLUDE_DIRS} ${OGRE_PLUGIN_INCLUDE_DIRS}
${OGRE_INCLUDE_DIR}/Overlay ${OGRE_Overlay_INCLUDE_DIR}
${SDL2_INCLUDE_DIR} ${SDL2_INCLUDE_DIR}
${Boost_INCLUDE_DIR} ${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR} ${PLATFORM_INCLUDE_DIR}
${MYGUI_INCLUDE_DIRS} ${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS} ${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}
${LIBDIR} ${LIBS_DIR}
) )
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
if(MYGUI_STATIC)
add_definitions(-DMYGUI_STATIC)
endif (MYGUI_STATIC)
if (APPLE) if (APPLE)
# List used Ogre plugins # List used Ogre plugins
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL} SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
@ -305,12 +334,14 @@ else ()
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d") add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d")
endif() endif()
add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
if (APPLE AND OPENMW_OSX_DEPLOYMENT) if (APPLE AND OPENMW_OSX_DEPLOYMENT)
# make it empty so plugin loading code can check this and try to find plugins inside app bundle # make it empty so plugin loading code can check this and try to find plugins inside app bundle
add_definitions(-DOGRE_PLUGIN_DIR="") add_definitions(-DOGRE_PLUGIN_DIR="")
else() else()
if (NOT DEFINED ${OGRE_PLUGIN_DIR})
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
endif()
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}") add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
endif() endif()
@ -322,8 +353,10 @@ add_subdirectory(files/mygui)
if (APPLE) if (APPLE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
else (APPLE) else (APPLE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
endif (APPLE) endif (APPLE)
# Other files # Other files
@ -357,9 +390,6 @@ endif()
if (CMAKE_COMPILER_IS_GNUCC) if (CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
# Silence warnings in OGRE headers. Remove once OGRE got fixed!
SET(CMAKE_CXX_FLAGS "-Wno-ignored-qualifiers ${CMAKE_CXX_FLAGS}")
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION) OUTPUT_VARIABLE GCC_VERSION)
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
@ -368,50 +398,52 @@ if (CMAKE_COMPILER_IS_GNUCC)
endif (CMAKE_COMPILER_IS_GNUCC) endif (CMAKE_COMPILER_IS_GNUCC)
IF(NOT WIN32 AND NOT APPLE) IF(NOT WIN32 AND NOT APPLE)
## Debian and non debian Linux building # Linux building
# Paths # Paths
IF (DPKG_PROGRAM) SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
## Debian specific SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Where to install libraries")
SET(CMAKE_INSTALL_PREFIX "/usr") SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location")
SET(DATAROOTDIR "share" CACHE PATH "Sets the root of data directories to a non-default location") SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix")
SET(DATADIR "share/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
SET(ICONDIR "share/pixmaps" CACHE PATH "Set icon dir") SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir")
SET(SYSCONFDIR "../etc/openmw" CACHE PATH "Set config dir") SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.")
ELSE () IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr")
## Non debian specific SET(GLOBAL_CONFIG_PATH "/etc/" CACHE PATH "Set config dir prefix")
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries") ELSE()
SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location") SET(GLOBAL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/etc/" CACHE PATH "Set config dir prefix")
SET(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location") ENDIF()
SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir") SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir")
SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.")
SET(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir") # Install binaries
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
# Install binaries IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" )
IF(BUILD_LAUNCHER) ENDIF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/omwlauncher" DESTINATION "${BINDIR}" ) IF(BUILD_BSATOOL)
ENDIF(BUILD_LAUNCHER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" )
IF(BUILD_BSATOOL) ENDIF(BUILD_BSATOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/bsatool" DESTINATION "${BINDIR}" ) IF(BUILD_ESMTOOL)
ENDIF(BUILD_BSATOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" )
IF(BUILD_ESMTOOL) ENDIF(BUILD_ESMTOOL)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/esmtool" DESTINATION "${BINDIR}" ) IF(BUILD_MWINIIMPORTER)
ENDIF(BUILD_ESMTOOL) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" )
IF(BUILD_MWINIIMPORTER) ENDIF(BUILD_MWINIIMPORTER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/mwiniimport" DESTINATION "${BINDIR}" ) IF(BUILD_OPENCS)
ENDIF(BUILD_MWINIIMPORTER) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
IF(BUILD_OPENCS) ENDIF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" ) IF(BUILD_NIFTEST)
ENDIF(BUILD_OPENCS) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
IF(BUILD_WIZARD) ENDIF(BUILD_NIFTEST)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/wizard" DESTINATION "${BINDIR}" ) IF(BUILD_WIZARD)
ENDIF(BUILD_WIZARD) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/wizard" DESTINATION "${BINDIR}" )
ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN)
# Install licenses INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
INSTALL(FILES "DejaVu Font License.txt" DESTINATION "${LICDIR}" ) ENDIF(BUILD_MYGUI_PLUGIN)
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
ENDIF (DPKG_PROGRAM) # Install licenses
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
# Install icon and desktop file # Install icon and desktop file
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ COMPONENT "openmw")
@ -440,8 +472,8 @@ if(WIN32)
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "." RENAME "openmw.cfg")
INSTALL(FILES INSTALL(FILES
"${OpenMW_SOURCE_DIR}/readme.txt" "${OpenMW_SOURCE_DIR}/readme.txt"
"${OpenMW_SOURCE_DIR}/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
"${OpenMW_SOURCE_DIR}/DejaVu Font License.txt" "${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg" "${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg" "${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
"${OpenMW_BINARY_DIR}/Release/openmw.exe" "${OpenMW_BINARY_DIR}/Release/openmw.exe"
@ -460,7 +492,9 @@ if(WIN32)
IF(BUILD_WIZARD) IF(BUILD_WIZARD)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".") INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/openmw-wizard.exe" DESTINATION ".")
ENDIF(BUILD_WIZARD) ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".")
ENDIF(BUILD_MYGUI_PLUGIN)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
@ -493,8 +527,8 @@ if(WIN32)
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org") SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe") SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico") SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico") SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp") SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe") SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
@ -525,12 +559,23 @@ endif(WIN32)
# Extern # Extern
add_subdirectory (extern/shiny) add_subdirectory (extern/shiny)
add_subdirectory (extern/ogre-ffmpeg-videoplayer)
add_subdirectory (extern/oics) add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre) add_subdirectory (extern/sdl4ogre)
# Components # Components
add_subdirectory (components) add_subdirectory (components)
# Plugins
if (BUILD_MYGUI_PLUGIN)
add_subdirectory(plugins/mygui_resource_plugin)
endif()
#Testing
if (BUILD_NIFTEST)
add_subdirectory(components/nif/tests/)
endif(BUILD_NIFTEST)
# Apps and tools # Apps and tools
add_subdirectory( apps/openmw ) add_subdirectory( apps/openmw )
@ -570,6 +615,16 @@ endif()
if (WIN32) if (WIN32)
if (MSVC) if (MSVC)
if (MULTITHREADED_BUILD)
set( MT_BUILD "/MP")
endif (MULTITHREADED_BUILD)
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(SolutionDir)$(Configuration)" )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" )
endforeach( OUTPUTCONFIG )
if (USE_DEBUG_CONSOLE) if (USE_DEBUG_CONSOLE)
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
@ -610,14 +665,19 @@ if (WIN32)
4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY' 4251 # class 'XXXX' needs to have dll-interface to be used by clients of class 'YYYY'
4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY' 4275 # non dll-interface struct 'XXXX' used as base for dll-interface class 'YYYY'
# caused by boost
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
# OpenMW specific warnings # OpenMW specific warnings
4099 # Type mismatch, declared class or struct is defined with other type 4099 # Type mismatch, declared class or struct is defined with other type
4100 # Unreferenced formal parameter (-Wunused-parameter) 4100 # Unreferenced formal parameter (-Wunused-parameter)
4127 # Conditional expression is constant 4127 # Conditional expression is constant
4242 # Storing value in a variable of a smaller type, possible loss of data 4242 # Storing value in a variable of a smaller type, possible loss of data
4244 # Storing value of one type in variable of another (size_t in int, for example) 4244 # Storing value of one type in variable of another (size_t in int, for example)
4267 # Conversion from 'size_t' to 'int', possible loss of data
4305 # Truncating value (double to float, for example) 4305 # Truncating value (double to float, for example)
4309 # Variable overflow, trying to store 128 in a signed char for example 4309 # Variable overflow, trying to store 128 in a signed char for example
4351 # New behavior: elements of array 'array' will be default initialized (desired behavior)
4355 # Using 'this' in member initialization list 4355 # Using 'this' in member initialization list
4505 # Unreferenced local function has been removed 4505 # Unreferenced local function has been removed
4701 # Potentially uninitialized local variable used 4701 # Potentially uninitialized local variable used
@ -631,31 +691,35 @@ if (WIN32)
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here # boost::wave has a few issues with signed / unsigned conversions, so we suppress those here
set(SHINY_WARNINGS "${WARNINGS} /wd4245") set(SHINY_WARNINGS "${WARNINGS} /wd4245")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS ${SHINY_WARNINGS}) set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
# there's an unreferenced local variable in the ogre platform, suppress it # there's an unreferenced local variable in the ogre platform, suppress it
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101") set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${SHINY_OGRE_WARNINGS}) set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}")
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
set_target_properties(oics PROPERTIES COMPILE_FLAGS ${WARNINGS}) # oics uses tinyxml, which has an initialized but unused variable
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS}) set(OICS_WARNINGS "${WARNINGS} /wd4189")
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
if (BUILD_LAUNCHER) if (BUILD_LAUNCHER)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_LAUNCHER) endif (BUILD_LAUNCHER)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
if (BUILD_BSATOOL) if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_BSATOOL) endif (BUILD_BSATOOL)
if (BUILD_ESMTOOL) if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_ESMTOOL) endif (BUILD_ESMTOOL)
if (BUILD_WIZARD) if (BUILD_WIZARD)
set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS ${WARNINGS})
endif (BUILD_WIZARD) endif (BUILD_WIZARD)
if (BUILD_OPENCS) if (BUILD_OPENCS)
set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${WARNINGS}) # QT triggers an informational warning that the object layout may differ when compiled with /vd2
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435")
set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS})
endif (BUILD_OPENCS) endif (BUILD_OPENCS)
if (BUILD_MWINIIMPORTER) if (BUILD_MWINIIMPORTER)
set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS ${WARNINGS}) set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_MWINIIMPORTER) endif (BUILD_MWINIIMPORTER)
endif(MSVC) endif(MSVC)
@ -789,3 +853,26 @@ if (APPLE)
include(CPack) include(CPack)
endif (APPLE) endif (APPLE)
# Doxygen Target -- simply run 'make doc' or 'make doc_pages'
# output directory for 'make doc' is "${OpenMW_BINARY_DIR}/docs/Doxygen"
# output directory for 'make doc_pages' is "${DOXYGEN_PAGES_OUTPUT_DIR}" if defined
# or "${OpenMW_BINARY_DIR}/docs/Pages" otherwise
find_package(Doxygen)
if (DOXYGEN_FOUND)
# determine output directory for doc_pages
if (NOT DEFINED DOXYGEN_PAGES_OUTPUT_DIR)
set(DOXYGEN_PAGES_OUTPUT_DIR "${OpenMW_BINARY_DIR}/docs/Pages")
endif ()
configure_file(${OpenMW_SOURCE_DIR}/docs/Doxyfile.cmake ${OpenMW_BINARY_DIR}/docs/Doxyfile @ONLY)
configure_file(${OpenMW_SOURCE_DIR}/docs/DoxyfilePages.cmake ${OpenMW_BINARY_DIR}/docs/DoxyfilePages @ONLY)
add_custom_target(doc
${DOXYGEN_EXECUTABLE} ${OpenMW_BINARY_DIR}/docs/Doxyfile
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
COMMENT "Generating Doxygen documentation at ${OpenMW_BINARY_DIR}/docs/Doxygen"
VERBATIM)
add_custom_target(doc_pages
${DOXYGEN_EXECUTABLE} ${OpenMW_BINARY_DIR}/docs/DoxyfilePages
WORKING_DIRECTORY ${OpenMW_BINARY_DIR}
COMMENT "Generating documentation for the github-pages at ${DOXYGEN_PAGES_OUTPUT_DIR}" VERBATIM)
endif ()

File diff suppressed because it is too large Load Diff

@ -51,7 +51,7 @@ bool parseOptions (int argc, char** argv, Arguments &info)
("help,h", "print help message.") ("help,h", "print help message.")
("version,v", "print version information and quit.") ("version,v", "print version information and quit.")
("long,l", "Include extra information in archive listing.") ("long,l", "Include extra information in archive listing.")
("full-path,f", "Create diretory hierarchy on file extraction " ("full-path,f", "Create directory hierarchy on file extraction "
"(always true for extractall).") "(always true for extractall).")
; ;

@ -249,6 +249,9 @@ void loadCell(ESM::Cell &cell, ESM::ESMReader &esm, Arguments& info)
std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl; std::cout << " Refnum: " << ref.mRefNum.mIndex << std::endl;
std::cout << " ID: '" << ref.mRefID << "'\n"; std::cout << " ID: '" << ref.mRefID << "'\n";
std::cout << " Owner: '" << ref.mOwner << "'\n"; std::cout << " Owner: '" << ref.mOwner << "'\n";
std::cout << " Global: '" << ref.mGlobalVariable << "'" << std::endl;
std::cout << " Faction: '" << ref.mFaction << "'" << std::endl;
std::cout << " Faction rank: '" << ref.mFactionRank << "'" << std::endl;
std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n"; std::cout << " Enchantment charge: '" << ref.mEnchantmentCharge << "'\n";
std::cout << " Uses/health: '" << ref.mCharge << "'\n"; std::cout << " Uses/health: '" << ref.mCharge << "'\n";
std::cout << " Gold value: '" << ref.mGoldValue << "'\n"; std::cout << " Gold value: '" << ref.mGoldValue << "'\n";

File diff suppressed because it is too large Load Diff

@ -412,7 +412,7 @@ void Record<ESM::Armor>::print()
std::cout << " Armor: " << mData.mData.mArmor << std::endl; std::cout << " Armor: " << mData.mData.mArmor << std::endl;
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
std::vector<ESM::PartReference>::iterator pit; std::vector<ESM::PartReference>::iterator pit;
for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); pit++) for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); ++pit)
{ {
std::cout << " Body Part: " << bodyPartLabel(pit->mPart) std::cout << " Body Part: " << bodyPartLabel(pit->mPart)
<< " (" << (int)(pit->mPart) << ")" << std::endl; << " (" << (int)(pit->mPart) << ")" << std::endl;
@ -484,7 +484,7 @@ void Record<ESM::BirthSign>::print()
std::cout << " Texture: " << mData.mTexture << std::endl; std::cout << " Texture: " << mData.mTexture << std::endl;
std::cout << " Description: " << mData.mDescription << std::endl; std::cout << " Description: " << mData.mDescription << std::endl;
std::vector<std::string>::iterator pit; std::vector<std::string>::iterator pit;
for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); pit++) for (pit = mData.mPowers.mList.begin(); pit != mData.mPowers.mList.end(); ++pit)
std::cout << " Power: " << *pit << std::endl; std::cout << " Power: " << *pit << std::endl;
} }
@ -513,7 +513,7 @@ void Record<ESM::Cell>::print()
else else
std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl; std::cout << " Map Color: " << boost::format("0x%08X") % mData.mMapColor << std::endl;
std::cout << " Water Level Int: " << mData.mWaterInt << std::endl; std::cout << " Water Level Int: " << mData.mWaterInt << std::endl;
std::cout << " NAM0: " << mData.mNAM0 << std::endl; std::cout << " RefId counter: " << mData.mRefNumCounter << std::endl;
} }
@ -554,7 +554,7 @@ void Record<ESM::Clothing>::print()
std::cout << " Value: " << mData.mData.mValue << std::endl; std::cout << " Value: " << mData.mData.mValue << std::endl;
std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl; std::cout << " Enchantment Points: " << mData.mData.mEnchant << std::endl;
std::vector<ESM::PartReference>::iterator pit; std::vector<ESM::PartReference>::iterator pit;
for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); pit++) for (pit = mData.mParts.mParts.begin(); pit != mData.mParts.mParts.end(); ++pit)
{ {
std::cout << " Body Part: " << bodyPartLabel(pit->mPart) std::cout << " Body Part: " << bodyPartLabel(pit->mPart)
<< " (" << (int)(pit->mPart) << ")" << std::endl; << " (" << (int)(pit->mPart) << ")" << std::endl;
@ -574,7 +574,7 @@ void Record<ESM::Container>::print()
std::cout << " Flags: " << containerFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << containerFlags(mData.mFlags) << std::endl;
std::cout << " Weight: " << mData.mWeight << std::endl; std::cout << " Weight: " << mData.mWeight << std::endl;
std::vector<ESM::ContItem>::iterator cit; std::vector<ESM::ContItem>::iterator cit;
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++) for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit)
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
<< " Item: " << cit->mItem.toString() << std::endl; << " Item: " << cit->mItem.toString() << std::endl;
} }
@ -619,12 +619,12 @@ void Record<ESM::Creature>::print()
std::cout << " Gold: " << mData.mData.mGold << std::endl; std::cout << " Gold: " << mData.mData.mGold << std::endl;
std::vector<ESM::ContItem>::iterator cit; std::vector<ESM::ContItem>::iterator cit;
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++) for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit)
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
<< " Item: " << cit->mItem.toString() << std::endl; << " Item: " << cit->mItem.toString() << std::endl;
std::vector<std::string>::iterator sit; std::vector<std::string>::iterator sit;
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); sit++) for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit)
std::cout << " Spell: " << *sit << std::endl; std::cout << " Spell: " << *sit << std::endl;
std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl; std::cout << " Artifical Intelligence: " << mData.mHasAI << std::endl;
@ -639,7 +639,7 @@ void Record<ESM::Creature>::print()
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
std::vector<ESM::AIPackage>::iterator pit; std::vector<ESM::AIPackage>::iterator pit;
for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); pit++) for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit)
printAIPackage(*pit); printAIPackage(*pit);
} }
@ -682,13 +682,11 @@ void Record<ESM::Faction>::print()
{ {
std::cout << " Name: " << mData.mName << std::endl; std::cout << " Name: " << mData.mName << std::endl;
std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl; std::cout << " Hidden: " << mData.mData.mIsHidden << std::endl;
if (mData.mData.mUnknown != -1)
std::cout << " Unknown: " << mData.mData.mUnknown << std::endl;
std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0]) std::cout << " Attribute1: " << attributeLabel(mData.mData.mAttribute[0])
<< " (" << mData.mData.mAttribute[0] << ")" << std::endl; << " (" << mData.mData.mAttribute[0] << ")" << std::endl;
std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1]) std::cout << " Attribute2: " << attributeLabel(mData.mData.mAttribute[1])
<< " (" << mData.mData.mAttribute[1] << ")" << std::endl; << " (" << mData.mData.mAttribute[1] << ")" << std::endl;
for (int i = 0; i != 6; i++) for (int i = 0; i < 7; i++)
if (mData.mData.mSkills[i] != -1) if (mData.mData.mSkills[i] != -1)
std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i]) std::cout << " Skill: " << skillLabel(mData.mData.mSkills[i])
<< " (" << mData.mData.mSkills[i] << ")" << std::endl; << " (" << mData.mData.mSkills[i] << ")" << std::endl;
@ -708,7 +706,7 @@ void Record<ESM::Faction>::print()
<< mData.mData.mRankData[i].mFactReaction << std::endl; << mData.mData.mRankData[i].mFactReaction << std::endl;
} }
std::map<std::string, int>::iterator rit; std::map<std::string, int>::iterator rit;
for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); rit++) for (rit = mData.mReactions.begin(); rit != mData.mReactions.end(); ++rit)
std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl; std::cout << " Reaction: " << rit->second << " = " << rit->first << std::endl;
} }
@ -765,7 +763,7 @@ void Record<ESM::DialInfo>::print()
std::cout << " Unknown2: " << (int)mData.mData.mUnknown2 << std::endl; std::cout << " Unknown2: " << (int)mData.mData.mUnknown2 << std::endl;
std::vector<ESM::DialInfo::SelectStruct>::iterator sit; std::vector<ESM::DialInfo::SelectStruct>::iterator sit;
for (sit = mData.mSelects.begin(); sit != mData.mSelects.end(); sit++) for (sit = mData.mSelects.begin(); sit != mData.mSelects.end(); ++sit)
std::cout << " Select Rule: " << ruleString(*sit) << std::endl; std::cout << " Select Rule: " << ruleString(*sit) << std::endl;
if (mData.mResultScript != "") if (mData.mResultScript != "")
@ -837,7 +835,7 @@ void Record<ESM::CreatureLevList>::print()
std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << creatureListFlags(mData.mFlags) << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit; std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++) for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit)
std::cout << " Creature: Level: " << iit->mLevel std::cout << " Creature: Level: " << iit->mLevel
<< " Creature: " << iit->mId << std::endl; << " Creature: " << iit->mId << std::endl;
} }
@ -849,7 +847,7 @@ void Record<ESM::ItemLevList>::print()
std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl; std::cout << " Flags: " << itemListFlags(mData.mFlags) << std::endl;
std::cout << " Number of items: " << mData.mList.size() << std::endl; std::cout << " Number of items: " << mData.mList.size() << std::endl;
std::vector<ESM::LeveledListBase::LevelItem>::iterator iit; std::vector<ESM::LeveledListBase::LevelItem>::iterator iit;
for (iit = mData.mList.begin(); iit != mData.mList.end(); iit++) for (iit = mData.mList.begin(); iit != mData.mList.end(); ++iit)
std::cout << " Inventory: Level: " << iit->mLevel std::cout << " Inventory: Level: " << iit->mLevel
<< " Item: " << iit->mId << std::endl; << " Item: " << iit->mId << std::endl;
} }
@ -952,9 +950,9 @@ void Record<ESM::MagicEffect>::print()
std::cout << " School: " << schoolLabel(mData.mData.mSchool) std::cout << " School: " << schoolLabel(mData.mData.mSchool)
<< " (" << mData.mData.mSchool << ")" << std::endl; << " (" << mData.mData.mSchool << ")" << std::endl;
std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl; std::cout << " Base Cost: " << mData.mData.mBaseCost << std::endl;
std::cout << " Unknown 1: " << mData.mData.mUnknown1 << std::endl;
std::cout << " Speed: " << mData.mData.mSpeed << std::endl; std::cout << " Speed: " << mData.mData.mSpeed << std::endl;
std::cout << " Size: " << mData.mData.mSize << std::endl; std::cout << " Unknown 2: " << mData.mData.mUnknown2 << std::endl;
std::cout << " Size Cap: " << mData.mData.mSizeCap << std::endl;
std::cout << " RGB Color: " << "(" std::cout << " RGB Color: " << "("
<< mData.mData.mRed << "," << mData.mData.mRed << ","
<< mData.mData.mGreen << "," << mData.mData.mGreen << ","
@ -994,7 +992,6 @@ void Record<ESM::NPC>::print()
std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl; std::cout << " Level: " << mData.mNpdt12.mLevel << std::endl;
std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl; std::cout << " Reputation: " << (int)mData.mNpdt12.mReputation << std::endl;
std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl; std::cout << " Disposition: " << (int)mData.mNpdt12.mDisposition << std::endl;
std::cout << " Faction: " << (int)mData.mNpdt52.mFactionID << std::endl;
std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl; std::cout << " Rank: " << (int)mData.mNpdt12.mRank << std::endl;
std::cout << " Unknown1: " std::cout << " Unknown1: "
<< (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl; << (unsigned int)((unsigned char)mData.mNpdt12.mUnknown1) << std::endl;
@ -1009,6 +1006,7 @@ void Record<ESM::NPC>::print()
std::cout << " Reputation: " << (int)mData.mNpdt52.mReputation << std::endl; std::cout << " Reputation: " << (int)mData.mNpdt52.mReputation << std::endl;
std::cout << " Disposition: " << (int)mData.mNpdt52.mDisposition << std::endl; std::cout << " Disposition: " << (int)mData.mNpdt52.mDisposition << std::endl;
std::cout << " Rank: " << (int)mData.mNpdt52.mRank << std::endl; std::cout << " Rank: " << (int)mData.mNpdt52.mRank << std::endl;
std::cout << " FactionID: " << (int)mData.mNpdt52.mFactionID << std::endl;
std::cout << " Attributes:" << std::endl; std::cout << " Attributes:" << std::endl;
std::cout << " Strength: " << (int)mData.mNpdt52.mStrength << std::endl; std::cout << " Strength: " << (int)mData.mNpdt52.mStrength << std::endl;
@ -1033,16 +1031,16 @@ void Record<ESM::NPC>::print()
} }
std::vector<ESM::ContItem>::iterator cit; std::vector<ESM::ContItem>::iterator cit;
for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); cit++) for (cit = mData.mInventory.mList.begin(); cit != mData.mInventory.mList.end(); ++cit)
std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount std::cout << " Inventory: Count: " << boost::format("%4d") % cit->mCount
<< " Item: " << cit->mItem.toString() << std::endl; << " Item: " << cit->mItem.toString() << std::endl;
std::vector<std::string>::iterator sit; std::vector<std::string>::iterator sit;
for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); sit++) for (sit = mData.mSpells.mList.begin(); sit != mData.mSpells.mList.end(); ++sit)
std::cout << " Spell: " << *sit << std::endl; std::cout << " Spell: " << *sit << std::endl;
std::vector<ESM::NPC::Dest>::iterator dit; std::vector<ESM::NPC::Dest>::iterator dit;
for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); dit++) for (dit = mData.mTransport.begin(); dit != mData.mTransport.end(); ++dit)
{ {
std::cout << " Destination Position: " std::cout << " Destination Position: "
<< boost::format("%12.3f") % dit->mPos.pos[0] << "," << boost::format("%12.3f") % dit->mPos.pos[0] << ","
@ -1068,7 +1066,7 @@ void Record<ESM::NPC>::print()
std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl; std::cout << " AI Services:" << boost::format("0x%08X") % mData.mAiData.mServices << std::endl;
std::vector<ESM::AIPackage>::iterator pit; std::vector<ESM::AIPackage>::iterator pit;
for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); pit++) for (pit = mData.mAiPackage.mList.begin(); pit != mData.mAiPackage.mList.end(); ++pit)
printAIPackage(*pit); printAIPackage(*pit);
} }
@ -1142,7 +1140,7 @@ void Record<ESM::Race>::print()
<< mData.mData.mBonus[i].mBonus << std::endl; << mData.mData.mBonus[i].mBonus << std::endl;
std::vector<std::string>::iterator sit; std::vector<std::string>::iterator sit;
for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); sit++) for (sit = mData.mPowers.mList.begin(); sit != mData.mPowers.mList.end(); ++sit)
std::cout << " Power: " << *sit << std::endl; std::cout << " Power: " << *sit << std::endl;
} }
@ -1166,7 +1164,7 @@ void Record<ESM::Region>::print()
if (mData.mSleepList != "") if (mData.mSleepList != "")
std::cout << " Sleep List: " << mData.mSleepList << std::endl; std::cout << " Sleep List: " << mData.mSleepList << std::endl;
std::vector<ESM::Region::SoundRef>::iterator sit; std::vector<ESM::Region::SoundRef>::iterator sit;
for (sit = mData.mSoundList.begin(); sit != mData.mSoundList.end(); sit++) for (sit = mData.mSoundList.begin(); sit != mData.mSoundList.end(); ++sit)
std::cout << " Sound: " << (int)sit->mChance << " = " << sit->mSound.toString() << std::endl; std::cout << " Sound: " << (int)sit->mChance << " = " << sit->mSound.toString() << std::endl;
} }
@ -1183,12 +1181,12 @@ void Record<ESM::Script>::print()
std::vector<std::string>::iterator vit; std::vector<std::string>::iterator vit;
for (vit = mData.mVarNames.begin(); vit != mData.mVarNames.end(); vit++) for (vit = mData.mVarNames.begin(); vit != mData.mVarNames.end(); ++vit)
std::cout << " Variable: " << *vit << std::endl; std::cout << " Variable: " << *vit << std::endl;
std::cout << " ByteCode: "; std::cout << " ByteCode: ";
std::vector<unsigned char>::iterator cit; std::vector<unsigned char>::iterator cit;
for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); cit++) for (cit = mData.mScriptData.begin(); cit != mData.mScriptData.end(); ++cit)
std::cout << boost::format("%02X") % (int)(*cit); std::cout << boost::format("%02X") % (int)(*cit);
std::cout << std::endl; std::cout << std::endl;

@ -13,7 +13,7 @@ set(LAUNCHER
utils/textinputdialog.cpp utils/textinputdialog.cpp
utils/lineedit.cpp utils/lineedit.cpp
${CMAKE_SOURCE_DIR}/files/launcher/launcher.rc ${CMAKE_SOURCE_DIR}/files/windows/launcher.rc
) )
set(LAUNCHER_HEADER set(LAUNCHER_HEADER
@ -74,19 +74,10 @@ QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI})
include(${QT_USE_FILE}) include(${QT_USE_FILE})
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
if(NOT WIN32) if(NOT WIN32)
include_directories(${LIBUNSHIELD_INCLUDE}) include_directories(${LIBUNSHIELD_INCLUDE_DIR})
endif(NOT WIN32) endif(NOT WIN32)
# Main executable # Main executable
IF(OGRE_STATIC)
IF(WIN32)
ADD_DEFINITIONS(-DENABLE_PLUGIN_Direct3D9 -DENABLE_PLUGIN_GL)
set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_Direct3D9_LIBRARIES} ${OGRE_RenderSystem_GL_LIBRARIES})
ELSE(WIN32)
ADD_DEFINITIONS(-DENABLE_PLUGIN_GL)
set(OGRE_STATIC_PLUGINS ${OGRE_RenderSystem_GL_LIBRARIES})
ENDIF(WIN32)
ENDIF(OGRE_STATIC)
add_executable(omwlauncher add_executable(omwlauncher
${GUI_TYPE} ${GUI_TYPE}
${LAUNCHER} ${LAUNCHER}
@ -100,16 +91,13 @@ target_link_libraries(omwlauncher
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS} ${OGRE_STATIC_PLUGINS}
${SDL2_LIBRARY} ${SDL2_LIBRARY_ONLY}
${QT_LIBRARIES} ${QT_LIBRARIES}
components components
) )
if(DPKG_PROGRAM)
INSTALL(TARGETS omwlauncher RUNTIME DESTINATION games COMPONENT omwlauncher)
endif()
if(BUILD_WITH_CODE_COVERAGE) if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage) add_definitions (--coverage)
target_link_libraries(omwlauncher gcov) target_link_libraries(omwlauncher gcov)
endif() endif()

@ -33,7 +33,11 @@ QString getAspect(int x, int y)
} }
Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent) Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsSettings &graphicsSetting, QWidget *parent)
: mCfgMgr(cfg) : mOgre(NULL)
, mSelectedRenderSystem(NULL)
, mOpenGLRenderSystem(NULL)
, mDirect3DRenderSystem(NULL)
, mCfgMgr(cfg)
, mGraphicsSettings(graphicsSetting) , mGraphicsSettings(graphicsSetting)
, QWidget(parent) , QWidget(parent)
{ {

@ -22,8 +22,3 @@ if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage) add_definitions (--coverage)
target_link_libraries(mwiniimport gcov) target_link_libraries(mwiniimport gcov)
endif() endif()
if(DPKG_PROGRAM)
INSTALL(TARGETS mwiniimport RUNTIME DESTINATION games COMPONENT mwiniimport)
endif()

@ -15,6 +15,7 @@ namespace bfs = boost::filesystem;
MwIniImporter::MwIniImporter() MwIniImporter::MwIniImporter()
: mVerbose(false) : mVerbose(false)
, mEncoding(ToUTF8::WINDOWS_1250)
{ {
const char *map[][2] = const char *map[][2] =
{ {
@ -709,8 +710,7 @@ MwIniImporter::multistrmap MwIniImporter::loadIniFile(const std::string& filenam
continue; continue;
} }
multistrmap::iterator it; if(map.find(key) == map.end()) {
if((it = map.find(key)) == map.end()) {
map.insert( std::make_pair (key, std::vector<std::string>() ) ); map.insert( std::make_pair (key, std::vector<std::string>() ) );
} }
map[key].push_back(value); map[key].push_back(value);
@ -746,8 +746,7 @@ MwIniImporter::multistrmap MwIniImporter::loadCfgFile(const std::string& filenam
std::string key(line.substr(0,pos)); std::string key(line.substr(0,pos));
std::string value(line.substr(pos+1)); std::string value(line.substr(pos+1));
multistrmap::iterator it; if(map.find(key) == map.end()) {
if((it = map.find(key)) == map.end()) {
map.insert( std::make_pair (key, std::vector<std::string>() ) ); map.insert( std::make_pair (key, std::vector<std::string>() ) );
} }
map[key].push_back(value); map[key].push_back(value);

@ -37,6 +37,8 @@ public:
char **get() const { return const_cast<char **>(argv); } char **get() const { return const_cast<char **>(argv); }
private: private:
utf8argv(const utf8argv&);
utf8argv& operator=(const utf8argv&);
const char **argv; const char **argv;
std::vector<std::string> args; std::vector<std::string> args;

@ -1,15 +1,17 @@
set (OPENCS_SRC main.cpp) set (OPENCS_SRC main.cpp
${CMAKE_SOURCE_DIR}/files/windows/opencs.rc
)
opencs_units (. editor) opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG) set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc opencs_units (model/doc
document operation saving documentmanager loader document operation saving documentmanager loader runner
) )
opencs_units_noqt (model/doc opencs_units_noqt (model/doc
stage savingstate savingstages stage savingstate savingstages blacklist
) )
opencs_hdrs_noqt (model/doc opencs_hdrs_noqt (model/doc
@ -18,17 +20,18 @@ opencs_hdrs_noqt (model/doc
opencs_units (model/world opencs_units (model/world
idtable idtableproxymodel regionmap data idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable
) )
opencs_units_noqt (model/world opencs_units_noqt (model/world
universalid record commands columnbase scriptcontext cell refidcollection universalid record commands columnbase scriptcontext cell refidcollection
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world
columnimp idcollection collection info columnimp idcollection collection info subcellcollection
) )
@ -38,13 +41,13 @@ opencs_units (model/tools
opencs_units_noqt (model/tools opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referenceablecheck scriptcheck birthsigncheck spellcheck referenceablecheck scriptcheck bodypartcheck
) )
opencs_units (view/doc opencs_units (view/doc
viewmanager view operations operation subview startup filedialog newgame viewmanager view operations operation subview startup filedialog newgame
filewidget adjusterwidget loader filewidget adjusterwidget loader globaldebugprofilemenu runlogsubview
) )
@ -59,23 +62,31 @@ opencs_hdrs_noqt (view/doc
opencs_units (view/world opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview scenetoolbar scenetool cellcreator referenceablecreator referencecreator scenesubview
scenetoolmode infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable
)
opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator physicssystem physicsmanager
)
opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
) )
opencs_units (view/render opencs_units (view/render
scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget scenewidget worldspacewidget pagedworldspacewidget unpagedworldspacewidget
previewwidget previewwidget editmode
) )
opencs_units_noqt (view/render opencs_units_noqt (view/render
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
lightingbright lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate
) )
opencs_units_noqt (view/world opencs_hdrs_noqt (view/render
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate elements
scripthighlighter idvalidator dialoguecreator
) )
@ -118,12 +129,8 @@ opencs_units_noqt (model/filter
node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode
) )
opencs_hdrs_noqt (model/filter
filter
)
opencs_units (view/filter opencs_units (view/filter
filtercreator filterbox recordfilterbox editwidget filterbox recordfilterbox editwidget
) )
set (OPENCS_US set (OPENCS_US
@ -158,7 +165,7 @@ qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT}) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES}) qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${BULLET_INCLUDE_DIRS})
if(APPLE) if(APPLE)
set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns) set (OPENCS_MAC_ICON ${CMAKE_SOURCE_DIR}/files/mac/opencs.icns)
@ -168,6 +175,7 @@ endif(APPLE)
add_executable(opencs add_executable(opencs
MACOSX_BUNDLE MACOSX_BUNDLE
${OENGINE_BULLET}
${OPENCS_SRC} ${OPENCS_SRC}
${OPENCS_UI_HDR} ${OPENCS_UI_HDR}
${OPENCS_MOC_SRC} ${OPENCS_MOC_SRC}
@ -192,16 +200,15 @@ endif(APPLE)
target_link_libraries(opencs target_link_libraries(opencs
${OGRE_LIBRARIES} ${OGRE_LIBRARIES}
${OGRE_Overlay_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES} ${SHINY_LIBRARIES}
${Boost_LIBRARIES} ${Boost_LIBRARIES}
${BULLET_LIBRARIES}
${QT_LIBRARIES} ${QT_LIBRARIES}
components components
) )
if(DPKG_PROGRAM)
INSTALL(TARGETS opencs RUNTIME DESTINATION games COMPONENT opencs)
endif()
if(APPLE) if(APPLE)
INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) INSTALL(TARGETS opencs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
endif() endif()

@ -20,8 +20,9 @@
#include "model/world/data.hpp" #include "model/world/data.hpp"
CS::Editor::Editor (OgreInit::OgreInit& ogreInit) CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr), mViewManager (mDocumentManager), : mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr),
mIpcServerName ("org.openmw.OpenCS") mViewManager (mDocumentManager), mPhysicsManager (0),
mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
{ {
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(); std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig();
@ -32,9 +33,14 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
mOverlaySystem.reset (new CSVRender::OverlaySystem);
mPhysicsManager.reset (new CSVWorld::PhysicsManager);
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,
mFsStrict); mFsStrict);
mDocumentManager.listResources();
mNewGame.setLocalData (mLocal); mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal); mFileDialog.setLocalData (mLocal);
@ -63,6 +69,9 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
this, SLOT (createNewGame (const boost::filesystem::path&))); this, SLOT (createNewGame (const boost::filesystem::path&)));
} }
CS::Editor::~Editor ()
{}
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
{ {
for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter) for (Files::PathContainer::const_iterator iter = dataDirs.begin(); iter != dataDirs.end(); ++iter)
@ -78,13 +87,17 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options"); boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
desc.add_options() desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()) ("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()->composing())
("data-local", boost::program_options::value<std::string>()->default_value("")) ("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false)) ("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252")) ("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
("resources", boost::program_options::value<std::string>()->default_value("resources")) ("resources", boost::program_options::value<std::string>()->default_value("resources"))
("fallback-archive", boost::program_options::value<std::vector<std::string> >()-> ("fallback-archive", boost::program_options::value<std::vector<std::string> >()->
default_value(std::vector<std::string>(), "fallback-archive")->multitoken()); default_value(std::vector<std::string>(), "fallback-archive")->multitoken())
("script-blacklist", boost::program_options::value<std::vector<std::string> >()->default_value(std::vector<std::string>(), "")
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)")
("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
->default_value(true), "enable script blacklisting");
boost::program_options::notify(variables); boost::program_options::notify(variables);
@ -95,6 +108,10 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>()); mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
if (variables["script-blacklist-use"].as<bool>())
mDocumentManager.setBlacklistedScripts (
variables["script-blacklist"].as<std::vector<std::string> >());
mFsStrict = variables["fs-strict"].as<bool>(); mFsStrict = variables["fs-strict"].as<bool>();
Files::PathContainer dataDirs, dataLocal; Files::PathContainer dataDirs, dataLocal;
@ -179,7 +196,7 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath)
files.push_back(path.toUtf8().constData()); files.push_back(path.toUtf8().constData());
} }
files.push_back(mFileDialog.filename().toUtf8().constData()); files.push_back (savePath);
mDocumentManager.addDocument (files, savePath, true); mDocumentManager.addDocument (files, savePath, true);
@ -249,26 +266,49 @@ int CS::Editor::run()
std::auto_ptr<sh::Factory> CS::Editor::setupGraphics() std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
{ {
// TODO: setting std::string renderer =
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName("OpenGL Rendering Subsystem")); #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
"Direct3D9 Rendering Subsystem";
#else
"OpenGL Rendering Subsystem";
#endif
std::string renderSystem = mUserSettings.setting("Video/render system", renderer.c_str()).toStdString();
Ogre::Root::getSingleton().setRenderSystem(Ogre::Root::getSingleton().getRenderSystemByName(renderSystem));
// Initialise Ogre::OverlaySystem after Ogre::Root but before initialisation
mOverlaySystem.get();
Ogre::Root::getSingleton().initialise(false); Ogre::Root::getSingleton().initialise(false);
// Create a hidden background window to keep resources // Create a hidden background window to keep resources
Ogre::NameValuePairList params; Ogre::NameValuePairList params;
params.insert(std::make_pair("title", "")); params.insert(std::make_pair("title", ""));
params.insert(std::make_pair("FSAA", "0"));
std::string antialiasing = mUserSettings.settingValue("Video/antialiasing").toStdString();
if(antialiasing == "MSAA 16") antialiasing = "16";
else if(antialiasing == "MSAA 8") antialiasing = "8";
else if(antialiasing == "MSAA 4") antialiasing = "4";
else if(antialiasing == "MSAA 2") antialiasing = "2";
else antialiasing = "0";
params.insert(std::make_pair("FSAA", antialiasing));
params.insert(std::make_pair("vsync", "false")); params.insert(std::make_pair("vsync", "false"));
params.insert(std::make_pair("hidden", "true")); params.insert(std::make_pair("hidden", "true"));
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
params.insert(std::make_pair("macAPI", "cocoa")); params.insert(std::make_pair("macAPI", "cocoa"));
#endif #endif
// NOTE: fullscreen mode not supported (doesn't really make sense for opencs)
Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params); Ogre::RenderWindow* hiddenWindow = Ogre::Root::getSingleton().createRenderWindow("InactiveHidden", 1, 1, false, &params);
hiddenWindow->setActive(false); hiddenWindow->setActive(false);
sh::OgrePlatform* platform = sh::OgrePlatform* platform =
new sh::OgrePlatform ("General", (mResources / "materials").string()); new sh::OgrePlatform ("General", (mResources / "materials").string());
// for font used in overlays
Ogre::Root::getSingleton().addResourceLocation ((mResources / "mygui").string(),
"FileSystem", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true);
if (!boost::filesystem::exists (mCfgMgr.getCachePath())) if (!boost::filesystem::exists (mCfgMgr.getCachePath()))
boost::filesystem::create_directories (mCfgMgr.getCachePath()); boost::filesystem::create_directories (mCfgMgr.getCachePath());
@ -276,7 +316,28 @@ std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
std::auto_ptr<sh::Factory> factory (new sh::Factory (platform)); std::auto_ptr<sh::Factory> factory (new sh::Factory (platform));
factory->setCurrentLanguage (sh::Language_GLSL); /// \todo make this configurable QString shLang = mUserSettings.settingValue("General/shader mode");
QString rend = renderSystem.c_str();
bool openGL = rend.contains(QRegExp("^OpenGL", Qt::CaseInsensitive));
bool glES = rend.contains(QRegExp("^OpenGL ES", Qt::CaseInsensitive));
// force shader language based on render system
if(shLang == ""
|| (openGL && shLang == "hlsl")
|| (!openGL && shLang == "glsl")
|| (glES && shLang != "glsles"))
{
shLang = openGL ? (glES ? "glsles" : "glsl") : "hlsl";
//no group means "General" group in the "ini" file standard
mUserSettings.setDefinitions("shader mode", (QStringList() << shLang));
}
enum sh::Language lang;
if(shLang == "glsl") lang = sh::Language_GLSL;
else if(shLang == "glsles") lang = sh::Language_GLSLES;
else if(shLang == "hlsl") lang = sh::Language_HLSL;
else lang = sh::Language_CG;
factory->setCurrentLanguage (lang);
factory->setWriteSourceCache (true); factory->setWriteSourceCache (true);
factory->setReadSourceCache (true); factory->setReadSourceCache (true);
factory->setReadMicrocodeCache (true); factory->setReadMicrocodeCache (true);
@ -284,16 +345,27 @@ std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
factory->loadAllFiles(); factory->loadAllFiles();
sh::Factory::getInstance().setGlobalSetting ("fog", "true"); bool shaders = mUserSettings.setting("3d-render/shaders", QString("true")) == "true" ? true : false;
sh::Factory::getInstance ().setShadersEnabled (shaders);
std::string fog = mUserSettings.setting("Shader/fog", QString("true")).toStdString();
sh::Factory::getInstance().setGlobalSetting ("fog", fog);
std::string shadows = mUserSettings.setting("Shader/shadows", QString("false")).toStdString();
sh::Factory::getInstance().setGlobalSetting ("shadows", shadows);
sh::Factory::getInstance().setGlobalSetting ("shadows", "false"); std::string shadows_pssm = mUserSettings.setting("Shader/shadows_pssm", QString("false")).toStdString();
sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", "false"); sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", shadows_pssm);
sh::Factory::getInstance ().setGlobalSetting ("render_refraction", "false"); std::string render_refraction = mUserSettings.setting("Shader/render_refraction", QString("false")).toStdString();
sh::Factory::getInstance ().setGlobalSetting ("render_refraction", render_refraction);
// internal setting - may be switched on or off by the use of shader configurations
sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false"); sh::Factory::getInstance ().setGlobalSetting ("viewproj_fix", "false");
sh::Factory::getInstance ().setGlobalSetting ("num_lights", "8"); std::string num_lights = mUserSettings.setting("3d-render-adv/num_lights", QString("8")).toStdString();
sh::Factory::getInstance ().setGlobalSetting ("num_lights", num_lights);
/// \todo add more configurable shiny settings /// \todo add more configurable shiny settings

@ -16,6 +16,8 @@
#include <components/files/multidircollection.hpp> #include <components/files/multidircollection.hpp>
#include <components/nifcache/nifcache.hpp>
#include "model/settings/usersettings.hpp" #include "model/settings/usersettings.hpp"
#include "model/doc/documentmanager.hpp" #include "model/doc/documentmanager.hpp"
@ -25,6 +27,8 @@
#include "view/doc/newgame.hpp" #include "view/doc/newgame.hpp"
#include "view/settings/dialog.hpp" #include "view/settings/dialog.hpp"
#include "view/render/overlaysystem.hpp"
#include "view/world/physicsmanager.hpp"
namespace OgreInit namespace OgreInit
{ {
@ -37,8 +41,11 @@ namespace CS
{ {
Q_OBJECT Q_OBJECT
Nif::Cache mNifCache;
Files::ConfigurationManager mCfgMgr; Files::ConfigurationManager mCfgMgr;
CSMSettings::UserSettings mUserSettings; CSMSettings::UserSettings mUserSettings;
std::auto_ptr<CSVRender::OverlaySystem> mOverlaySystem;
std::auto_ptr<CSVWorld::PhysicsManager> mPhysicsManager;
CSMDoc::DocumentManager mDocumentManager; CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager; CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup; CSVDoc::StartupDialogue mStartup;
@ -61,6 +68,7 @@ namespace CS
public: public:
Editor (OgreInit::OgreInit& ogreInit); Editor (OgreInit::OgreInit& ogreInit);
~Editor ();
bool makeIPCServer(); bool makeIPCServer();
void connectToIPCServer(); void connectToIPCServer();

@ -0,0 +1,31 @@
#include "blacklist.hpp"
#include <algorithm>
#include <components/misc/stringops.hpp>
bool CSMDoc::Blacklist::isBlacklisted (const CSMWorld::UniversalId& id) const
{
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> >::const_iterator iter =
mIds.find (id.getType());
if (iter==mIds.end())
return false;
return std::binary_search (iter->second.begin(), iter->second.end(),
Misc::StringUtils::lowerCase (id.getId()));
}
void CSMDoc::Blacklist::add (CSMWorld::UniversalId::Type type,
const std::vector<std::string>& ids)
{
std::vector<std::string>& list = mIds[type];
int size = list.size();
list.resize (size+ids.size());
std::transform (ids.begin(), ids.end(), list.begin()+size, Misc::StringUtils::lowerCase);
std::sort (list.begin(), list.end());
}

@ -0,0 +1,25 @@
#ifndef CSM_DOC_BLACKLIST_H
#define CSM_DOC_BLACKLIST_H
#include <map>
#include <vector>
#include <string>
#include "../world/universalid.hpp"
namespace CSMDoc
{
/// \brief ID blacklist sorted by UniversalId type
class Blacklist
{
std::map<CSMWorld::UniversalId::Type, std::vector<std::string> > mIds;
public:
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
void add (CSMWorld::UniversalId::Type type, const std::vector<std::string>& ids);
};
}
#endif

@ -1,6 +1,7 @@
#include "document.hpp" #include "document.hpp"
#include <cassert> #include <cassert>
#include <fstream>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@ -2022,6 +2023,7 @@ void CSMDoc::Document::addOptionalGmsts()
{ {
ESM::GameSetting gmst; ESM::GameSetting gmst;
gmst.mId = sFloats[i]; gmst.mId = sFloats[i];
gmst.blank();
gmst.mValue.setType (ESM::VT_Float); gmst.mValue.setType (ESM::VT_Float);
addOptionalGmst (gmst); addOptionalGmst (gmst);
} }
@ -2030,6 +2032,7 @@ void CSMDoc::Document::addOptionalGmsts()
{ {
ESM::GameSetting gmst; ESM::GameSetting gmst;
gmst.mId = sIntegers[i]; gmst.mId = sIntegers[i];
gmst.blank();
gmst.mValue.setType (ESM::VT_Int); gmst.mValue.setType (ESM::VT_Int);
addOptionalGmst (gmst); addOptionalGmst (gmst);
} }
@ -2038,6 +2041,7 @@ void CSMDoc::Document::addOptionalGmsts()
{ {
ESM::GameSetting gmst; ESM::GameSetting gmst;
gmst.mId = sStrings[i]; gmst.mId = sStrings[i];
gmst.blank();
gmst.mValue.setType (ESM::VT_String); gmst.mValue.setType (ESM::VT_String);
gmst.mValue.setString ("<no text>"); gmst.mValue.setString ("<no text>");
addOptionalGmst (gmst); addOptionalGmst (gmst);
@ -2058,6 +2062,7 @@ void CSMDoc::Document::addOptionalGlobals()
{ {
ESM::Global global; ESM::Global global;
global.mId = sGlobals[i]; global.mId = sGlobals[i];
global.blank();
global.mValue.setType (ESM::VT_Long); global.mValue.setType (ESM::VT_Long);
if (i==0) if (i==0)
@ -2067,6 +2072,19 @@ void CSMDoc::Document::addOptionalGlobals()
} }
} }
void CSMDoc::Document::addOptionalMagicEffects()
{
for (int i=ESM::MagicEffect::SummonFabricant; i<=ESM::MagicEffect::SummonCreature05; ++i)
{
ESM::MagicEffect effect;
effect.mIndex = i;
effect.mId = ESM::MagicEffect::indexToId (i);
effect.blank();
addOptionalMagicEffect (effect);
}
}
void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst) void CSMDoc::Document::addOptionalGmst (const ESM::GameSetting& gmst)
{ {
if (getData().getGmsts().searchId (gmst.mId)==-1) if (getData().getGmsts().searchId (gmst.mId)==-1)
@ -2089,6 +2107,17 @@ void CSMDoc::Document::addOptionalGlobal (const ESM::Global& global)
} }
} }
void CSMDoc::Document::addOptionalMagicEffect (const ESM::MagicEffect& magicEffect)
{
if (getData().getMagicEffects().searchId (magicEffect.mId)==-1)
{
CSMWorld::Record<ESM::MagicEffect> record;
record.mBase = magicEffect;
record.mState = CSMWorld::RecordBase::State_BaseOnly;
getData().getMagicEffects().appendRecord (record);
}
}
void CSMDoc::Document::createBase() void CSMDoc::Document::createBase()
{ {
static const char *sGlobals[] = static const char *sGlobals[] =
@ -2200,33 +2229,49 @@ void CSMDoc::Document::createBase()
getData().getTopics().add (record); getData().getTopics().add (record);
} }
for (int i=0; i<ESM::MagicEffect::Length; ++i)
{
ESM::MagicEffect record;
record.mIndex = i;
record.mId = ESM::MagicEffect::indexToId (i);
record.blank();
getData().getMagicEffects().add (record);
}
} }
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_, const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding) ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding), mTools (mData), const std::vector<std::string>& blacklistedScripts)
mResDir(resDir), : mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
mTools (*this), mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") / mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")), (savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding) mSaving (*this, mProjectPath, encoding),
mRunner (mProjectPath)
{ {
if (mContentFiles.empty()) if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence"); throw std::runtime_error ("Empty content file sequence");
if (!boost::filesystem::exists (mProjectPath)) if (!boost::filesystem::exists (mProjectPath))
{ {
boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath()); boost::filesystem::path customFiltersPath (configuration.getUserDataPath());
locCustomFiltersPath /= "defaultfilters"; customFiltersPath /= "defaultfilters";
std::ofstream destination (mProjectPath.string().c_str(), std::ios::binary);
if (boost::filesystem::exists (locCustomFiltersPath)) if (boost::filesystem::exists (customFiltersPath))
{ {
boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath); destination << std::ifstream(customFiltersPath.c_str(), std::ios::binary).rdbuf();
} }
else else
{ {
boost::filesystem::copy_file (mResDir / "defaultfilters", mProjectPath); destination << std::ifstream(std::string(mResDir.string() + "/defaultfilters").c_str(), std::ios::binary).rdbuf();
} }
} }
@ -2239,20 +2284,25 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
createBase(); createBase();
} }
mBlacklist.add (CSMWorld::UniversalId::Type_Script, blacklistedScripts);
addOptionalGmsts(); addOptionalGmsts();
addOptionalGlobals(); addOptionalGlobals();
addOptionalMagicEffects();
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool))); connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int))); connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int))); connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mSaving, SIGNAL (done (int)), this, SLOT (operationDone (int))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect ( connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), &mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int))); this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
} }
CSMDoc::Document::~Document() CSMDoc::Document::~Document()
@ -2274,6 +2324,9 @@ int CSMDoc::Document::getState() const
if (mSaving.isRunning()) if (mSaving.isRunning())
state |= State_Locked | State_Saving | State_Operation; state |= State_Locked | State_Saving | State_Operation;
if (mRunner.isRunning())
state |= State_Locked | State_Running;
if (int operations = mTools.getRunningOperations()) if (int operations = mTools.getRunningOperations())
state |= State_Locked | State_Operation | operations; state |= State_Locked | State_Operation | operations;
@ -2338,7 +2391,7 @@ void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std
std::cout << message << std::endl; std::cout << message << std::endl;
} }
void CSMDoc::Document::operationDone (int type) void CSMDoc::Document::operationDone (int type, bool failed)
{ {
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
@ -2358,6 +2411,55 @@ CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId&
return mTools.getReport (id); return mTools.getReport (id);
} }
bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id)
const
{
return mBlacklist.isBlacklisted (id);
}
void CSMDoc::Document::startRunning (const std::string& profile,
const std::string& startupInstruction)
{
std::vector<std::string> contentFiles;
for (std::vector<boost::filesystem::path>::const_iterator iter (mContentFiles.begin());
iter!=mContentFiles.end(); ++iter)
contentFiles.push_back (iter->filename().string());
mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles,
startupInstruction);
int state = getState();
if (state & State_Modified)
{
// need to save first
mRunner.start (true);
new SaveWatcher (&mRunner, &mSaving); // no, that is not a memory leak. Qt is weird.
if (!(state & State_Saving))
save();
}
else
mRunner.start();
}
void CSMDoc::Document::stopRunning()
{
mRunner.stop();
}
QTextDocument *CSMDoc::Document::getRunLog()
{
return mRunner.getLog();
}
void CSMDoc::Document::runStateChanged()
{
emit stateChanged (getState(), this);
}
void CSMDoc::Document::progress (int current, int max, int type) void CSMDoc::Document::progress (int current, int max, int type)
{ {
emit progress (current, max, type, 1, this); emit progress (current, max, type, 1, this);

@ -17,6 +17,8 @@
#include "state.hpp" #include "state.hpp"
#include "saving.hpp" #include "saving.hpp"
#include "blacklist.hpp"
#include "runner.hpp"
class QAbstractItemModel; class QAbstractItemModel;
@ -24,6 +26,7 @@ namespace ESM
{ {
struct GameSetting; struct GameSetting;
struct Global; struct Global;
struct MagicEffect;
} }
namespace Files namespace Files
@ -31,6 +34,11 @@ namespace Files
class ConfigurationManager; class ConfigurationManager;
} }
namespace CSMWorld
{
class ResourcesManager;
}
namespace CSMDoc namespace CSMDoc
{ {
class Document : public QObject class Document : public QObject
@ -47,6 +55,8 @@ namespace CSMDoc
boost::filesystem::path mProjectPath; boost::filesystem::path mProjectPath;
Saving mSaving; Saving mSaving;
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
Blacklist mBlacklist;
Runner mRunner;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is // It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late. // using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
@ -64,16 +74,21 @@ namespace CSMDoc
void addOptionalGlobals(); void addOptionalGlobals();
void addOptionalMagicEffects();
void addOptionalGmst (const ESM::GameSetting& gmst); void addOptionalGmst (const ESM::GameSetting& gmst);
void addOptionalGlobal (const ESM::Global& global); void addOptionalGlobal (const ESM::Global& global);
void addOptionalMagicEffect (const ESM::MagicEffect& effect);
public: public:
Document (const Files::ConfigurationManager& configuration, Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_, const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir, const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding); ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts);
~Document(); ~Document();
@ -105,6 +120,15 @@ namespace CSMDoc
CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id); CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id);
///< The ownership of the returned report is not transferred. ///< The ownership of the returned report is not transferred.
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
void startRunning (const std::string& profile,
const std::string& startupInstruction = "");
void stopRunning();
QTextDocument *getRunLog();
signals: signals:
void stateChanged (int state, CSMDoc::Document *document); void stateChanged (int state, CSMDoc::Document *document);
@ -118,7 +142,9 @@ namespace CSMDoc
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type); int type);
void operationDone (int type); void operationDone (int type, bool failed);
void runStateChanged();
public slots: public slots:

@ -31,8 +31,8 @@ CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& con
&mLoader, SLOT (loadDocument (CSMDoc::Document *))); &mLoader, SLOT (loadDocument (CSMDoc::Document *)));
connect (&mLoader, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)), connect (&mLoader, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)),
this, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int))); this, SIGNAL (nextStage (CSMDoc::Document *, const std::string&, int)));
connect (&mLoader, SIGNAL (nextRecord (CSMDoc::Document *)), connect (&mLoader, SIGNAL (nextRecord (CSMDoc::Document *, int)),
this, SIGNAL (nextRecord (CSMDoc::Document *))); this, SIGNAL (nextRecord (CSMDoc::Document *, int)));
connect (this, SIGNAL (cancelLoading (CSMDoc::Document *)), connect (this, SIGNAL (cancelLoading (CSMDoc::Document *)),
&mLoader, SLOT (abortLoading (CSMDoc::Document *))); &mLoader, SLOT (abortLoading (CSMDoc::Document *)));
connect (&mLoader, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)), connect (&mLoader, SIGNAL (loadMessage (CSMDoc::Document *, const std::string&)),
@ -52,7 +52,7 @@ CSMDoc::DocumentManager::~DocumentManager()
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath, void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
bool new_) bool new_)
{ {
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding); Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
mDocuments.push_back (document); mDocuments.push_back (document);
@ -85,6 +85,16 @@ void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding)
mEncoding = encoding; mEncoding = encoding;
} }
void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector<std::string>& scriptIds)
{
mBlacklistedScripts = scriptIds;
}
void CSMDoc::DocumentManager::listResources()
{
mResourcesManager.listResources();
}
void CSMDoc::DocumentManager::documentLoaded (Document *document) void CSMDoc::DocumentManager::documentLoaded (Document *document)
{ {
emit documentAdded (document); emit documentAdded (document);

@ -11,6 +11,8 @@
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
#include "../world/resourcesmanager.hpp"
#include "loader.hpp" #include "loader.hpp"
namespace Files namespace Files
@ -31,6 +33,8 @@ namespace CSMDoc
QThread mLoaderThread; QThread mLoaderThread;
Loader mLoader; Loader mLoader;
ToUTF8::FromType mEncoding; ToUTF8::FromType mEncoding;
CSMWorld::ResourcesManager mResourcesManager;
std::vector<std::string> mBlacklistedScripts;
DocumentManager (const DocumentManager&); DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&); DocumentManager& operator= (const DocumentManager&);
@ -50,6 +54,11 @@ namespace CSMDoc
void setEncoding (ToUTF8::FromType encoding); void setEncoding (ToUTF8::FromType encoding);
void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
/// Ask OGRE for a list of available resources.
void listResources();
private: private:
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
@ -79,9 +88,10 @@ namespace CSMDoc
void loadingStopped (CSMDoc::Document *document, bool completed, void loadingStopped (CSMDoc::Document *document, bool completed,
const std::string& error); const std::string& error);
void nextStage (CSMDoc::Document *document, const std::string& name, int steps); void nextStage (CSMDoc::Document *document, const std::string& name,
int totalRecords);
void nextRecord (CSMDoc::Document *document); void nextRecord (CSMDoc::Document *document, int records);
void cancelLoading (CSMDoc::Document *document); void cancelLoading (CSMDoc::Document *document);

@ -8,7 +8,7 @@
#include "document.hpp" #include "document.hpp"
#include "state.hpp" #include "state.hpp"
CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLeft (false) {} CSMDoc::Loader::Stage::Stage() : mFile (0), mRecordsLoaded (0), mRecordsLeft (false) {}
CSMDoc::Loader::Loader() CSMDoc::Loader::Loader()
@ -39,13 +39,14 @@ void CSMDoc::Loader::load()
Document *document = iter->first; Document *document = iter->first;
int size = static_cast<int> (document->getContentFiles().size()); int size = static_cast<int> (document->getContentFiles().size());
int editedIndex = size-1; // index of the file to be edited/created
if (document->isNew()) if (document->isNew())
--size; --size;
bool done = false; bool done = false;
const int batchingSize = 100; const int batchingSize = 50;
try try
{ {
@ -58,17 +59,21 @@ void CSMDoc::Loader::load()
iter->second.mRecordsLeft = false; iter->second.mRecordsLeft = false;
break; break;
} }
else
++(iter->second.mRecordsLoaded);
CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0); CSMWorld::UniversalId log (CSMWorld::UniversalId::Type_LoadErrorLog, 0);
{ // silence a g++ warning
for (CSMDoc::Stage::Messages::const_iterator iter (messages.begin()); for (CSMDoc::Stage::Messages::const_iterator iter (messages.begin());
iter!=messages.end(); ++iter) iter!=messages.end(); ++iter)
{ {
document->getReport (log)->add (iter->first, iter->second); document->getReport (log)->add (iter->first, iter->second);
emit loadMessage (document, iter->second); emit loadMessage (document, iter->second);
} }
}
emit nextRecord (document); emit nextRecord (document, iter->second.mRecordsLoaded);
return; return;
} }
@ -77,17 +82,19 @@ void CSMDoc::Loader::load()
{ {
boost::filesystem::path path = document->getContentFiles()[iter->second.mFile]; boost::filesystem::path path = document->getContentFiles()[iter->second.mFile];
int steps = document->getData().startLoading (path, iter->second.mFile<size-1, false); int steps = document->getData().startLoading (path, iter->second.mFile!=editedIndex, false);
iter->second.mRecordsLeft = true; iter->second.mRecordsLeft = true;
iter->second.mRecordsLoaded = 0;
emit nextStage (document, path.filename().string(), steps/batchingSize); emit nextStage (document, path.filename().string(), steps);
} }
else if (iter->second.mFile==size) else if (iter->second.mFile==size)
{ {
int steps = document->getData().startLoading (document->getProjectPath(), false, true); int steps = document->getData().startLoading (document->getProjectPath(), false, true);
iter->second.mRecordsLeft = true; iter->second.mRecordsLeft = true;
iter->second.mRecordsLoaded = 0;
emit nextStage (document, "Project File", steps/batchingSize); emit nextStage (document, "Project File", steps);
} }
else else
{ {

@ -18,6 +18,7 @@ namespace CSMDoc
struct Stage struct Stage
{ {
int mFile; int mFile;
int mRecordsLoaded;
bool mRecordsLeft; bool mRecordsLeft;
Stage(); Stage();
@ -56,9 +57,10 @@ namespace CSMDoc
///< Document load has been interrupted either because of a call to abortLoading ///< 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. /// 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 nextStage (CSMDoc::Document *document, const std::string& name,
int totalRecords);
void nextRecord (CSMDoc::Document *document); void nextRecord (CSMDoc::Document *document, int records);
///< \note This signal is only given once per group of records. The group size is ///< \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 /// approximately the total number of records divided by the steps value of the
/// previous nextStage signal. /// previous nextStage signal.

@ -27,7 +27,9 @@ void CSMDoc::Operation::prepareStages()
} }
CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways) CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways)
: mType (type), mOrdered (ordered), mFinalAlways (finalAlways) : mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()),
mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered),
mFinalAlways (finalAlways), mError(false)
{ {
connect (this, SIGNAL (finished()), this, SLOT (operationDone())); connect (this, SIGNAL (finished()), this, SLOT (operationDone()));
} }
@ -119,5 +121,5 @@ void CSMDoc::Operation::executeStage()
void CSMDoc::Operation::operationDone() void CSMDoc::Operation::operationDone()
{ {
emit done (mType); emit done (mType, mError);
} }

@ -54,7 +54,7 @@ namespace CSMDoc
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type); int type);
void done (int type); void done (int type, bool failed);
public slots: public slots:

@ -0,0 +1,162 @@
#include "runner.hpp"
#include <QApplication>
#include <QDir>
#include <QTemporaryFile>
#include <QTextStream>
#include "operation.hpp"
CSMDoc::Runner::Runner (const boost::filesystem::path& projectPath)
: mRunning (false), mStartup (0), mProjectPath (projectPath)
{
connect (&mProcess, SIGNAL (finished (int, QProcess::ExitStatus)),
this, SLOT (finished (int, QProcess::ExitStatus)));
connect (&mProcess, SIGNAL (readyReadStandardOutput()),
this, SLOT (readyReadStandardOutput()));
mProcess.setProcessChannelMode (QProcess::MergedChannels);
mProfile.blank();
}
CSMDoc::Runner::~Runner()
{
if (mRunning)
{
disconnect (&mProcess, 0, this, 0);
mProcess.kill();
mProcess.waitForFinished();
}
}
void CSMDoc::Runner::start (bool delayed)
{
if (mStartup)
{
delete mStartup;
mStartup = 0;
}
if (!delayed)
{
mLog.clear();
QString path = "openmw";
#ifdef Q_OS_WIN
path.append(QString(".exe"));
#elif defined(Q_OS_MAC)
QDir dir(QCoreApplication::applicationDirPath());
dir.cdUp();
dir.cdUp();
dir.cdUp();
path = dir.absoluteFilePath(path.prepend("OpenMW.app/Contents/MacOS/"));
#else
path.prepend(QString("./"));
#endif
mStartup = new QTemporaryFile (this);
mStartup->open();
{
QTextStream stream (mStartup);
if (!mStartupInstruction.empty())
stream << QString::fromUtf8 (mStartupInstruction.c_str()) << '\n';
stream << QString::fromUtf8 (mProfile.mScriptText.c_str());
}
mStartup->close();
QStringList arguments;
arguments << "--skip-menu";
if (mProfile.mFlags & ESM::DebugProfile::Flag_BypassNewGame)
arguments << "--new-game=0";
else
arguments << "--new-game=1";
arguments << ("--script-run="+mStartup->fileName());;
arguments <<
QString::fromUtf8 (("--data="+mProjectPath.parent_path().string()).c_str());
for (std::vector<std::string>::const_iterator iter (mContentFiles.begin());
iter!=mContentFiles.end(); ++iter)
{
arguments << QString::fromUtf8 (("--content="+*iter).c_str());
}
arguments
<< QString::fromUtf8 (("--content="+mProjectPath.filename().string()).c_str());
mProcess.start (path, arguments);
}
mRunning = true;
emit runStateChanged();
}
void CSMDoc::Runner::stop()
{
delete mStartup;
mStartup = 0;
if (mProcess.state()==QProcess::NotRunning)
{
mRunning = false;
emit runStateChanged();
}
else
mProcess.kill();
}
bool CSMDoc::Runner::isRunning() const
{
return mRunning;
}
void CSMDoc::Runner::configure (const ESM::DebugProfile& profile,
const std::vector<std::string>& contentFiles, const std::string& startupInstruction)
{
mProfile = profile;
mContentFiles = contentFiles;
mStartupInstruction = startupInstruction;
}
void CSMDoc::Runner::finished (int exitCode, QProcess::ExitStatus exitStatus)
{
mRunning = false;
emit runStateChanged();
}
QTextDocument *CSMDoc::Runner::getLog()
{
return &mLog;
}
void CSMDoc::Runner::readyReadStandardOutput()
{
mLog.setPlainText (
mLog.toPlainText() + QString::fromUtf8 (mProcess.readAllStandardOutput()));
}
CSMDoc::SaveWatcher::SaveWatcher (Runner *runner, Operation *operation)
: QObject (runner), mRunner (runner)
{
connect (operation, SIGNAL (done (int, bool)), this, SLOT (saveDone (int, bool)));
}
void CSMDoc::SaveWatcher::saveDone (int type, bool failed)
{
if (failed)
mRunner->stop();
else
mRunner->start();
deleteLater();
}

@ -0,0 +1,85 @@
#ifndef CSM_DOC_RUNNER_H
#define CSM_DOC_RUNNER_H
#include <vector>
#include <string>
#include <boost/filesystem/path.hpp>
#include <QObject>
#include <QProcess>
#include <QTextDocument>
#include <components/esm/debugprofile.hpp>
class QTemporaryFile;
namespace CSMDoc
{
class Runner : public QObject
{
Q_OBJECT
QProcess mProcess;
bool mRunning;
ESM::DebugProfile mProfile;
std::vector<std::string> mContentFiles;
std::string mStartupInstruction;
QTemporaryFile *mStartup;
QTextDocument mLog;
boost::filesystem::path mProjectPath;
public:
Runner (const boost::filesystem::path& projectPath);
~Runner();
/// \param delayed Flag as running but do not start the OpenMW process yet (the
/// process must be started by another call of start with delayed==false)
void start (bool delayed = false);
void stop();
/// \note Running state is entered when the start function is called. This
/// is not necessarily identical to the moment the child process is started.
bool isRunning() const;
void configure (const ESM::DebugProfile& profile,
const std::vector<std::string>& contentFiles,
const std::string& startupInstruction);
QTextDocument *getLog();
signals:
void runStateChanged();
private slots:
void finished (int exitCode, QProcess::ExitStatus exitStatus);
void readyReadStandardOutput();
};
class Operation;
/// \brief Watch for end of save operation and restart or stop runner
class SaveWatcher : public QObject
{
Q_OBJECT
Runner *mRunner;
public:
/// *this attaches itself to runner
SaveWatcher (Runner *runner, Operation *operation);
private slots:
void saveDone (int type, bool failed);
};
}
#endif

@ -17,7 +17,14 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
appendStage (new WriteHeaderStage (mDocument, mState, true)); appendStage (new WriteHeaderStage (mDocument, mState, true));
appendStage (new WriteFilterStage (mDocument, mState, CSMFilter::Filter::Scope_Project)); appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Filter> > (
mDocument.getData().getFilters(), mState, CSMWorld::Scope_Project));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::DebugProfile> > (
mDocument.getData().getDebugProfiles(), mState, CSMWorld::Scope_Project));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Script> > (
mDocument.getData().getScripts(), mState, CSMWorld::Scope_Project));
appendStage (new CloseSaveStage (mState)); appendStage (new CloseSaveStage (mState));
@ -59,13 +66,31 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Spell> > appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Spell> >
(mDocument.getData().getSpells(), mState)); (mDocument.getData().getSpells(), mState));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Enchantment> >
(mDocument.getData().getEnchantments(), mState));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::BodyPart> >
(mDocument.getData().getBodyParts(), mState));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::SoundGenerator> >
(mDocument.getData().getSoundGens(), mState));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::MagicEffect> >
(mDocument.getData().getMagicEffects(), mState));
appendStage (new WriteDialogueCollectionStage (mDocument, mState, false)); appendStage (new WriteDialogueCollectionStage (mDocument, mState, false));
appendStage (new WriteDialogueCollectionStage (mDocument, mState, true)); appendStage (new WriteDialogueCollectionStage (mDocument, mState, true));
appendStage (new WriteRefIdCollectionStage (mDocument, mState)); appendStage (new WriteRefIdCollectionStage (mDocument, mState));
appendStage (new CollectionReferencesStage (mDocument, mState));
appendStage (new WriteCellCollectionStage (mDocument, mState));
appendStage (new WritePathgridCollectionStage (mDocument, mState));
// close file and clean up
appendStage (new CloseSaveStage (mState)); appendStage (new CloseSaveStage (mState));
appendStage (new FinalSavingStage (mDocument, mState)); appendStage (new FinalSavingStage (mDocument, mState));

@ -9,6 +9,8 @@
#include <components/esm/loaddial.hpp> #include <components/esm/loaddial.hpp>
#include <components/misc/stringops.hpp>
#include "../world/infocollection.hpp" #include "../world/infocollection.hpp"
#include "document.hpp" #include "document.hpp"
@ -199,20 +201,155 @@ void CSMDoc::WriteRefIdCollectionStage::perform (int stage, Messages& messages)
} }
CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& state, CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document,
CSMFilter::Filter::Scope scope) SavingState& state)
: WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> > (document.getData().getFilters(), : mDocument (document), mState (state)
state), {}
mDocument (document), mScope (scope)
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())
{
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)
{
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::WritePathgridCollectionStage::WritePathgridCollectionStage (Document& document,
SavingState& state)
: mDocument (document), mState (state)
{} {}
void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages) int CSMDoc::WritePathgridCollectionStage::setup()
{ {
const CSMWorld::Record<CSMFilter::Filter>& record = return mDocument.getData().getPathgrids().getSize();
mDocument.getData().getFilters().getRecord (stage); }
void CSMDoc::WritePathgridCollectionStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<CSMWorld::Pathgrid>& pathgrid =
mDocument.getData().getPathgrids().getRecord (stage);
if (pathgrid.mState==CSMWorld::RecordBase::State_Modified ||
pathgrid.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{
CSMWorld::Pathgrid record = pathgrid.get();
if (record.get().mScope==mScope) if (record.mId.substr (0, 1)=="#")
WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >::perform (stage, messages); {
std::istringstream stream (record.mId.c_str());
char ignore;
stream >> ignore >> record.mData.mX >> record.mData.mY;
}
else
record.mCell = record.mId;
mState.getWriter().startRecord (record.sRecordId);
record.save (mState.getWriter());
mState.getWriter().endRecord (record.sRecordId);
}
else if (pathgrid.mState==CSMWorld::RecordBase::State_Deleted)
{
/// \todo write record with delete flag
}
} }

@ -5,8 +5,7 @@
#include "../world/record.hpp" #include "../world/record.hpp"
#include "../world/idcollection.hpp" #include "../world/idcollection.hpp"
#include "../world/scope.hpp"
#include "../filter/filter.hpp"
#include "savingstate.hpp" #include "savingstate.hpp"
@ -67,10 +66,12 @@ namespace CSMDoc
{ {
const CollectionT& mCollection; const CollectionT& mCollection;
SavingState& mState; SavingState& mState;
CSMWorld::Scope mScope;
public: public:
WriteCollectionStage (const CollectionT& collection, SavingState& state); WriteCollectionStage (const CollectionT& collection, SavingState& state,
CSMWorld::Scope scope = CSMWorld::Scope_Content);
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps
@ -81,8 +82,8 @@ namespace CSMDoc
template<class CollectionT> template<class CollectionT>
WriteCollectionStage<CollectionT>::WriteCollectionStage (const CollectionT& collection, WriteCollectionStage<CollectionT>::WriteCollectionStage (const CollectionT& collection,
SavingState& state) SavingState& state, CSMWorld::Scope scope)
: mCollection (collection), mState (state) : mCollection (collection), mState (state), mScope (scope)
{} {}
template<class CollectionT> template<class CollectionT>
@ -94,16 +95,14 @@ namespace CSMDoc
template<class CollectionT> template<class CollectionT>
void WriteCollectionStage<CollectionT>::perform (int stage, Messages& messages) void WriteCollectionStage<CollectionT>::perform (int stage, Messages& messages)
{ {
if (CSMWorld::getScopeFromId (mCollection.getRecord (stage).get().mId)!=mScope)
return;
CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState; CSMWorld::RecordBase::State state = mCollection.getRecord (stage).mState;
if (state==CSMWorld::RecordBase::State_Modified || if (state==CSMWorld::RecordBase::State_Modified ||
state==CSMWorld::RecordBase::State_ModifiedOnly) state==CSMWorld::RecordBase::State_ModifiedOnly)
{ {
std::string type;
for (int i=0; i<4; ++i)
/// \todo make endianess agnostic (change ESMWriter interface?)
type += reinterpret_cast<const char *> (&mCollection.getRecord (stage).mModified.sRecordId)[i];
mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId); mState.getWriter().startRecord (mCollection.getRecord (stage).mModified.sRecordId);
mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage)); mState.getWriter().writeHNCString ("NAME", mCollection.getId (stage));
mCollection.getRecord (stage).mModified.save (mState.getWriter()); mCollection.getRecord (stage).mModified.save (mState.getWriter());
@ -152,19 +151,54 @@ namespace CSMDoc
}; };
class WriteFilterStage : public WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> > class CollectionReferencesStage : public Stage
{ {
Document& mDocument; Document& mDocument;
CSMFilter::Filter::Scope mScope; SavingState& mState;
public: public:
WriteFilterStage (Document& document, SavingState& state, CSMFilter::Filter::Scope scope); CollectionReferencesStage (Document& document, SavingState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, Messages& messages); virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages. ///< Messages resulting from this stage will be appended to \a messages.
}; };
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 WritePathgridCollectionStage : public Stage
{
Document& mDocument;
SavingState& mState;
public:
WritePathgridCollectionStage (Document& document, SavingState& state);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, Messages& messages);
///< Messages resulting from this stage will be appended to \a messages.
};
class CloseSaveStage : public Stage class CloseSaveStage : public Stage
{ {

@ -25,6 +25,8 @@ void CSMDoc::SavingState::start (Document& document, bool project)
mStream.clear(); mStream.clear();
mSubRecords.clear();
if (project) if (project)
mPath = mProjectPath; mPath = mProjectPath;
else else
@ -61,3 +63,8 @@ bool CSMDoc::SavingState::isProjectFile() const
{ {
return mProjectFile; return mProjectFile;
} }
std::map<std::string, std::vector<int> >& CSMDoc::SavingState::getSubRecords()
{
return mSubRecords;
}

@ -2,6 +2,7 @@
#define CSM_DOC_SAVINGSTATE_H #define CSM_DOC_SAVINGSTATE_H
#include <fstream> #include <fstream>
#include <map>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem/fstream.hpp> #include <boost/filesystem/fstream.hpp>
@ -25,6 +26,7 @@ namespace CSMDoc
ESM::ESMWriter mWriter; ESM::ESMWriter mWriter;
boost::filesystem::path mProjectPath; boost::filesystem::path mProjectPath;
bool mProjectFile; bool mProjectFile;
std::map<std::string, std::vector<int> > mSubRecords; // record ID, list of subrecords
public: public:
@ -46,6 +48,8 @@ namespace CSMDoc
bool isProjectFile() const; bool isProjectFile() const;
///< Currently saving project file? (instead of content file) ///< Currently saving project file? (instead of content file)
std::map<std::string, std::vector<int> >& getSubRecords();
}; };

@ -8,12 +8,13 @@ namespace CSMDoc
State_Modified = 1, State_Modified = 1,
State_Locked = 2, State_Locked = 2,
State_Operation = 4, State_Operation = 4,
State_Running = 8,
State_Saving = 8, State_Saving = 16,
State_Verifying = 16, State_Verifying = 32,
State_Compiling = 32, // not implemented yet State_Compiling = 64, // not implemented yet
State_Searching = 64, // not implemented yet State_Searching = 128, // not implemented yet
State_Loading = 128 // pseudo-state; can not be encountered in a loaded document State_Loading = 256 // pseudo-state; can not be encountered in a loaded document
}; };
} }

@ -7,7 +7,7 @@ CSMFilter::AndNode::AndNode (const std::vector<boost::shared_ptr<Node> >& nodes)
: NAryNode (nodes, "and") : NAryNode (nodes, "and")
{} {}
bool CSMFilter::AndNode::test (const CSMWorld::IdTable& table, int row, bool CSMFilter::AndNode::test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const const std::map<int, int>& columns) const
{ {
int size = getSize(); int size = getSize();

@ -11,7 +11,7 @@ namespace CSMFilter
AndNode (const std::vector<boost::shared_ptr<Node> >& nodes); AndNode (const std::vector<boost::shared_ptr<Node> >& nodes);
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const; const std::map<int, int>& columns) const;
///< \return Can the specified table row pass through to filter? ///< \return Can the specified table row pass through to filter?
/// \param columns column ID to column index mapping /// \param columns column ID to column index mapping

@ -3,7 +3,7 @@
CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {} CSMFilter::BooleanNode::BooleanNode (bool true_) : mTrue (true_) {}
bool CSMFilter::BooleanNode::test (const CSMWorld::IdTable& table, int row, bool CSMFilter::BooleanNode::test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const const std::map<int, int>& columns) const
{ {
return mTrue; return mTrue;

@ -13,7 +13,7 @@ namespace CSMFilter
BooleanNode (bool true_); BooleanNode (bool true_);
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const; const std::map<int, int>& columns) const;
///< \return Can the specified table row pass through to filter? ///< \return Can the specified table row pass through to filter?
/// \param columns column ID to column index mapping /// \param columns column ID to column index mapping

@ -1,25 +0,0 @@
#ifndef CSM_FILTER_FILTER_H
#define CSM_FILTER_FILTER_H
#include <vector>
#include <string>
#include <components/esm/filter.hpp>
namespace CSMFilter
{
/// \brief Wrapper for Filter record
struct Filter : public ESM::Filter
{
enum Scope
{
Scope_Project = 0, // per project
Scope_Session = 1, // exists only for one editing session; not saved
Scope_Content = 2 // embedded in the edited content file
};
Scope mScope;
};
}
#endif

@ -11,7 +11,7 @@
namespace CSMWorld namespace CSMWorld
{ {
class IdTable; class IdTableBase;
} }
namespace CSMFilter namespace CSMFilter
@ -32,7 +32,7 @@ namespace CSMFilter
virtual ~Node(); virtual ~Node();
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const = 0; const std::map<int, int>& columns) const = 0;
///< \return Can the specified table row pass through to filter? ///< \return Can the specified table row pass through to filter?
/// \param columns column ID to column index mapping /// \param columns column ID to column index mapping

@ -3,7 +3,7 @@
CSMFilter::NotNode::NotNode (boost::shared_ptr<Node> child) : UnaryNode (child, "not") {} CSMFilter::NotNode::NotNode (boost::shared_ptr<Node> child) : UnaryNode (child, "not") {}
bool CSMFilter::NotNode::test (const CSMWorld::IdTable& table, int row, bool CSMFilter::NotNode::test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const const std::map<int, int>& columns) const
{ {
return !getChild().test (table, row, columns); return !getChild().test (table, row, columns);

@ -11,7 +11,7 @@ namespace CSMFilter
NotNode (boost::shared_ptr<Node> child); NotNode (boost::shared_ptr<Node> child);
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const; const std::map<int, int>& columns) const;
///< \return Can the specified table row pass through to filter? ///< \return Can the specified table row pass through to filter?
/// \param columns column ID to column index mapping /// \param columns column ID to column index mapping

@ -7,7 +7,7 @@ CSMFilter::OrNode::OrNode (const std::vector<boost::shared_ptr<Node> >& nodes)
: NAryNode (nodes, "or") : NAryNode (nodes, "or")
{} {}
bool CSMFilter::OrNode::test (const CSMWorld::IdTable& table, int row, bool CSMFilter::OrNode::test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const const std::map<int, int>& columns) const
{ {
int size = getSize(); int size = getSize();

@ -11,7 +11,7 @@ namespace CSMFilter
OrNode (const std::vector<boost::shared_ptr<Node> >& nodes); OrNode (const std::vector<boost::shared_ptr<Node> >& nodes);
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const; const std::map<int, int>& columns) const;
///< \return Can the specified table row pass through to filter? ///< \return Can the specified table row pass through to filter?
/// \param columns column ID to column index mapping /// \param columns column ID to column index mapping

@ -550,7 +550,12 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined)
if (allowPredefined) if (allowPredefined)
token = getNextToken(); token = getNextToken();
if (!allowPredefined || token==Token (Token::Type_OneShot)) if (allowPredefined && token==Token (Token::Type_EOS))
{
mFilter.reset();
return true;
}
else if (!allowPredefined || token==Token (Token::Type_OneShot))
{ {
boost::shared_ptr<Node> node = parseImp (true, token!=Token (Token::Type_OneShot)); boost::shared_ptr<Node> node = parseImp (true, token!=Token (Token::Type_OneShot));
@ -591,7 +596,7 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined)
return false; return false;
} }
const CSMWorld::Record<CSMFilter::Filter>& record = mData.getFilters().getRecord (index); const CSMWorld::Record<ESM::Filter>& record = mData.getFilters().getRecord (index);
if (record.isDeleted()) if (record.isDeleted())
{ {

@ -7,13 +7,13 @@
#include <QRegExp> #include <QRegExp>
#include "../world/columns.hpp" #include "../world/columns.hpp"
#include "../world/idtable.hpp" #include "../world/idtablebase.hpp"
CSMFilter::TextNode::TextNode (int columnId, const std::string& text) CSMFilter::TextNode::TextNode (int columnId, const std::string& text)
: mColumnId (columnId), mText (text) : mColumnId (columnId), mText (text)
{} {}
bool CSMFilter::TextNode::test (const CSMWorld::IdTable& table, int row, bool CSMFilter::TextNode::test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const const std::map<int, int>& columns) const
{ {
const std::map<int, int>::const_iterator iter = columns.find (mColumnId); const std::map<int, int>::const_iterator iter = columns.find (mColumnId);

@ -14,7 +14,7 @@ namespace CSMFilter
TextNode (int columnId, const std::string& text); TextNode (int columnId, const std::string& text);
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const; const std::map<int, int>& columns) const;
///< \return Can the specified table row pass through to filter? ///< \return Can the specified table row pass through to filter?
/// \param columns column ID to column index mapping /// \param columns column ID to column index mapping

@ -5,13 +5,13 @@
#include <stdexcept> #include <stdexcept>
#include "../world/columns.hpp" #include "../world/columns.hpp"
#include "../world/idtable.hpp" #include "../world/idtablebase.hpp"
CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType, CSMFilter::ValueNode::ValueNode (int columnId, Type lowerType, Type upperType,
double lower, double upper) double lower, double upper)
: mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){} : mColumnId (columnId), mLowerType (lowerType), mUpperType (upperType), mLower (lower), mUpper (upper){}
bool CSMFilter::ValueNode::test (const CSMWorld::IdTable& table, int row, bool CSMFilter::ValueNode::test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const const std::map<int, int>& columns) const
{ {
const std::map<int, int>::const_iterator iter = columns.find (mColumnId); const std::map<int, int>::const_iterator iter = columns.find (mColumnId);

@ -27,7 +27,7 @@ namespace CSMFilter
ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper); ValueNode (int columnId, Type lowerType, Type upperType, double lower, double upper);
virtual bool test (const CSMWorld::IdTable& table, int row, virtual bool test (const CSMWorld::IdTableBase& table, int row,
const std::map<int, int>& columns) const; const std::map<int, int>& columns) const;
///< \return Can the specified table row pass through to filter? ///< \return Can the specified table row pass through to filter?
/// \param columns column ID to column index mapping /// \param columns column ID to column index mapping

@ -2,8 +2,8 @@
#include "support.hpp" #include "support.hpp"
CSMSettings::Setting::Setting(SettingType typ, const QString &settingName, CSMSettings::Setting::Setting(SettingType typ, const QString &settingName,
const QString &pageName) const QString &pageName, const QString& label)
: mIsEditorSetting (false) : mIsEditorSetting (true)
{ {
buildDefaultSetting(); buildDefaultSetting();
@ -17,6 +17,7 @@ CSMSettings::Setting::Setting(SettingType typ, const QString &settingName,
setProperty (Property_SettingType, QVariant (settingType).toString()); setProperty (Property_SettingType, QVariant (settingType).toString());
setProperty (Property_Page, pageName); setProperty (Property_Page, pageName);
setProperty (Property_Name, settingName); setProperty (Property_Name, settingName);
setProperty (Property_Label, label.isEmpty() ? settingName : label);
} }
void CSMSettings::Setting::buildDefaultSetting() void CSMSettings::Setting::buildDefaultSetting()
@ -194,6 +195,16 @@ QString CSMSettings::Setting::page() const
return property (Property_Page).at(0); return property (Property_Page).at(0);
} }
void CSMSettings::Setting::setStyleSheet (const QString &value)
{
setProperty (Property_StyleSheet, value);
}
QString CSMSettings::Setting::styleSheet() const
{
return property (Property_StyleSheet).at(0);
}
void CSMSettings::Setting::setPrefix (const QString &value) void CSMSettings::Setting::setPrefix (const QString &value)
{ {
setProperty (Property_Prefix, value); setProperty (Property_Prefix, value);
@ -280,14 +291,16 @@ CSMSettings::SettingType CSMSettings::Setting::type() const
Property_SettingType).at(0).toInt()); Property_SettingType).at(0).toInt());
} }
void CSMSettings::Setting::setMaximum (int value) void CSMSettings::Setting::setRange (int min, int max)
{ {
setProperty (Property_Maximum, value); setProperty (Property_Minimum, min);
setProperty (Property_Maximum, max);
} }
void CSMSettings::Setting::setMaximum (double value) void CSMSettings::Setting::setRange (double min, double max)
{ {
setProperty (Property_Maximum, value); setProperty (Property_Minimum, min);
setProperty (Property_Maximum, max);
} }
QString CSMSettings::Setting::maximum() const QString CSMSettings::Setting::maximum() const
@ -295,16 +308,6 @@ QString CSMSettings::Setting::maximum() const
return property (Property_Maximum).at(0); 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 QString CSMSettings::Setting::minimum() const
{ {
return property (Property_Minimum).at(0); return property (Property_Minimum).at(0);
@ -362,6 +365,26 @@ bool CSMSettings::Setting::wrapping() const
return (property (Property_Wrapping).at(0) == "true"); return (property (Property_Wrapping).at(0) == "true");
} }
void CSMSettings::Setting::setLabel (const QString& label)
{
setProperty (Property_Label, label);
}
QString CSMSettings::Setting::getLabel() const
{
return property (Property_Label).at (0);
}
void CSMSettings::Setting::setToolTip (const QString& toolTip)
{
setProperty (Property_ToolTip, toolTip);
}
QString CSMSettings::Setting::getToolTip() const
{
return property (Property_ToolTip).at (0);
}
void CSMSettings::Setting::setProperty (SettingProperty prop, bool value) void CSMSettings::Setting::setProperty (SettingProperty prop, bool value)
{ {
setProperty (prop, QStringList() << QVariant (value).toString()); setProperty (prop, QStringList() << QVariant (value).toString());

@ -29,8 +29,8 @@ namespace CSMSettings
public: public:
explicit Setting(SettingType typ, const QString &settingName, Setting(SettingType typ, const QString &settingName,
const QString &pageName); const QString &pageName, const QString& label = "");
void addProxy (const Setting *setting, const QStringList &vals); void addProxy (const Setting *setting, const QStringList &vals);
void addProxy (const Setting *setting, const QList <QStringList> &list); void addProxy (const Setting *setting, const QList <QStringList> &list);
@ -66,12 +66,11 @@ namespace CSMSettings
void setMask (const QString &value); void setMask (const QString &value);
QString mask() const; QString mask() const;
void setMaximum (int value); void setRange (int min, int max);
void setMaximum (double value); void setRange (double min, double max);
QString maximum() const; QString maximum() const;
void setMinimum (int value);
void setMinimum (double value);
QString minimum() const; QString minimum() const;
void setName (const QString &value); void setName (const QString &value);
@ -80,6 +79,9 @@ namespace CSMSettings
void setPage (const QString &value); void setPage (const QString &value);
QString page() const; QString page() const;
void setStyleSheet (const QString &value);
QString styleSheet() const;
void setPrefix (const QString &value); void setPrefix (const QString &value);
QString prefix() const; QString prefix() const;
@ -129,6 +131,13 @@ namespace CSMSettings
void setWidgetWidth (int value); void setWidgetWidth (int value);
int widgetWidth() const; int widgetWidth() const;
/// This is the text the user gets to see.
void setLabel (const QString& label);
QString getLabel() const;
void setToolTip (const QString& toolTip);
QString getToolTip() const;
///returns the specified property value ///returns the specified property value
QStringList property (SettingProperty prop) const; QStringList property (SettingProperty prop) const;

@ -35,12 +35,15 @@ namespace CSMSettings
Property_TickInterval = 19, Property_TickInterval = 19,
Property_TicksAbove = 20, Property_TicksAbove = 20,
Property_TicksBelow = 21, Property_TicksBelow = 21,
Property_StyleSheet = 22,
Property_Label = 23,
Property_ToolTip = 24,
//Stringlists should always be the last items //Stringlists should always be the last items
Property_DefaultValues = 22, Property_DefaultValues = 25,
Property_DeclaredValues = 23, Property_DeclaredValues = 26,
Property_DefinedValues = 24, Property_DefinedValues = 27,
Property_Proxies = 25 Property_Proxies = 28
}; };
///Basic setting widget types. ///Basic setting widget types.
@ -106,7 +109,7 @@ namespace CSMSettings
"is_multi_line", "widget_width", "view_row", "view_column", "delimiter", "is_multi_line", "widget_width", "view_row", "view_column", "delimiter",
"is_serializable","column_span", "row_span", "minimum", "maximum", "is_serializable","column_span", "row_span", "minimum", "maximum",
"special_value_text", "prefix", "suffix", "single_step", "wrapping", "special_value_text", "prefix", "suffix", "single_step", "wrapping",
"tick_interval", "ticks_above", "ticks_below", "tick_interval", "ticks_above", "ticks_below", "stylesheet",
"defaults", "declarations", "definitions", "proxies" "defaults", "declarations", "definitions", "proxies"
}; };
@ -135,6 +138,7 @@ namespace CSMSettings
"1", //tick interval "1", //tick interval
"false", //ticks above "false", //ticks above
"true", //ticks below "true", //ticks below
"", //StyleSheet
"", //default values "", //default values
"", //declared values "", //declared values
"", //defined values "", //defined values

@ -4,12 +4,16 @@
#include <QFile> #include <QFile>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/settings/settings.hpp>
#include <boost/version.hpp> #include <boost/version.hpp>
#include "setting.hpp" #include "setting.hpp"
#include "support.hpp" #include "support.hpp"
#include <QTextCodec>
#include <QDebug> #include <QDebug>
#include <extern/shiny/Main/Factory.hpp>
/** /**
* Workaround for problems with whitespaces in paths in older versions of Boost library * Workaround for problems with whitespaces in paths in older versions of Boost library
*/ */
@ -26,81 +30,184 @@ namespace boost
} /* namespace boost */ } /* namespace boost */
#endif /* (BOOST_VERSION <= 104600) */ #endif /* (BOOST_VERSION <= 104600) */
CSMSettings::UserSettings *CSMSettings::UserSettings::mUserSettingsInstance = 0; CSMSettings::UserSettings *CSMSettings::UserSettings::sUserSettingsInstance = 0;
CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager) CSMSettings::UserSettings::UserSettings (const Files::ConfigurationManager& configurationManager)
: mCfgMgr (configurationManager) : mCfgMgr (configurationManager)
, mSettingDefinitions(NULL)
{ {
assert(!mUserSettingsInstance); assert(!sUserSettingsInstance);
mUserSettingsInstance = this; sUserSettingsInstance = this;
mSettingDefinitions = 0;
buildSettingModelDefaults(); buildSettingModelDefaults();
} }
void CSMSettings::UserSettings::buildSettingModelDefaults() void CSMSettings::UserSettings::buildSettingModelDefaults()
{ {
QString section = "Window Size"; QString section;
{
Setting *width = createSetting (Type_LineEdit, section, "Width");
Setting *height = createSetting (Type_LineEdit, section, "Height");
width->setWidgetWidth (5);
height->setWidgetWidth (8);
width->setDefaultValues (QStringList() << "1024");
height->setDefaultValues (QStringList() << "768");
width->setEditorSetting (true);
height->setEditorSetting (true);
height->setViewLocation (2,2); declareSection ("3d-render", "3D Rendering");
width->setViewLocation (2,1); {
Setting *shaders = createSetting (Type_CheckBox, "shaders", "Enable Shaders");
shaders->setDefaultValue ("true");
Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance");
farClipDist->setDefaultValue (300000);
farClipDist->setRange (0, 1000000);
farClipDist->setToolTip ("The maximum distance objects are still rendered at.");
QString defaultValue = "None";
Setting *antialiasing = createSetting (Type_ComboBox, "antialiasing", "Antialiasing");
antialiasing->setDeclaredValues (QStringList()
<< defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16");
antialiasing->setDefaultValue (defaultValue);
}
/* declareSection ("3d-render-adv", "3D Rendering (Advanced)");
*Create the proxy setting for predefined values {
*/ Setting *numLights = createSetting (Type_SpinBox, "num_lights",
Setting *preDefined = createSetting (Type_ComboBox, section, "Number of lights per pass");
"Pre-Defined"); numLights->setDefaultValue (8);
numLights->setRange (1, 100);
}
preDefined->setDeclaredValues (QStringList() << "640 x 480" declareSection ("scene-input", "Scene Input");
<< "800 x 600" << "1024 x 768" << "1440 x 900"); {
Setting *timer = createSetting (Type_SpinBox, "timer", "Input responsiveness");
timer->setDefaultValue (20);
timer->setRange (1, 100);
timer->setToolTip ("The time between two checks for user input in milliseconds.<p>"
"Lower value result in higher responsiveness.");
Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor",
"Fast movement factor");
fastFactor->setDefaultValue (4);
fastFactor->setRange (1, 100);
fastFactor->setToolTip (
"Factor by which movement is speed up while the shift key is held down.");
}
declareSection ("window", "Window");
{
Setting *preDefined = createSetting (Type_ComboBox, "pre-defined",
"Default window size");
preDefined->setEditorSetting (false);
preDefined->setDeclaredValues (
QStringList() << "640 x 480" << "800 x 600" << "1024 x 768" << "1440 x 900");
preDefined->setViewLocation (1, 1); preDefined->setViewLocation (1, 1);
preDefined->setWidgetWidth (10);
preDefined->setColumnSpan (2); preDefined->setColumnSpan (2);
preDefined->setToolTip ("Newly opened top-level windows will open with this size "
"(picked from a list of pre-defined values)");
preDefined->addProxy (width, Setting *width = createSetting (Type_LineEdit, "default-width",
QStringList() << "640" << "800" << "1024" << "1440" "Default window width");
); width->setDefaultValues (QStringList() << "1024");
width->setViewLocation (2, 1);
width->setColumnSpan (1);
width->setToolTip ("Newly opened top-level windows will open with this width.");
preDefined->addProxy (width, QStringList() << "640" << "800" << "1024" << "1440");
preDefined->addProxy (height, Setting *height = createSetting (Type_LineEdit, "default-height",
QStringList() << "480" << "600" << "768" << "900" "Default window height");
); height->setDefaultValues (QStringList() << "768");
height->setViewLocation (2, 2);
height->setColumnSpan (1);
height->setToolTip ("Newly opened top-level windows will open with this height.");
preDefined->addProxy (height, QStringList() << "480" << "600" << "768" << "900");
Setting *reuse = createSetting (Type_CheckBox, "reuse", "Reuse Subviews");
reuse->setDefaultValue ("true");
reuse->setToolTip ("When a new subview is requested and a matching subview already "
" exist, do not open a new subview and use the existing one instead.");
Setting *statusBar = createSetting (Type_CheckBox, "show-statusbar", "Show Status Bar");
statusBar->setDefaultValue ("true");
statusBar->setToolTip ("If a newly open top level window is showing status bars or not. "
" Note that this does not affect existing windows.");
Setting *maxSubView = createSetting (Type_SpinBox, "max-subviews",
"Maximum number of subviews per top-level window");
maxSubView->setDefaultValue (256);
maxSubView->setRange (1, 256);
maxSubView->setToolTip ("If the maximum number is reached and a new subview is opened "
"it will be placed into a new top-level window.");
Setting *hide = createSetting (Type_CheckBox, "hide-subview", "Hide single subview");
hide->setDefaultValue ("false");
hide->setToolTip ("When a view contains only a single subview, hide the subview title "
"bar and if this subview is closed also close the view (unless it is the last "
"view for this document)");
Setting *minWidth = createSetting (Type_SpinBox, "minimum-width",
"Minimum subview width");
minWidth->setDefaultValue (325);
minWidth->setRange (50, 10000);
minWidth->setToolTip ("Minimum width of subviews.");
} }
section = "Display Format"; declareSection ("records", "Records");
{ {
QString defaultValue = "Icon and Text"; QString defaultValue = "Icon and Text";
QStringList values = QStringList() << defaultValue << "Icon Only" << "Text Only";
QStringList values = QStringList() Setting *rsd = createSetting (Type_RadioButton, "status-format",
<< defaultValue << "Icon Only" << "Text Only"; "Modification status display format");
rsd->setDefaultValue (defaultValue);
Setting *rsd = createSetting (Type_RadioButton,
section, "Record Status Display");
Setting *ritd = createSetting (Type_RadioButton,
section, "Referenceable ID Type Display");
rsd->setDeclaredValues (values); rsd->setDeclaredValues (values);
Setting *ritd = createSetting (Type_RadioButton, "type-format",
"ID type display format");
ritd->setDefaultValue (defaultValue);
ritd->setDeclaredValues (values); ritd->setDeclaredValues (values);
}
rsd->setEditorSetting (true); declareSection ("table-input", "Table Input");
ritd->setEditorSetting (true); {
QString inPlaceEdit ("Edit in Place");
QString editRecord ("Edit Record");
QString view ("View");
QString editRecordAndClose ("Edit Record and Close");
QStringList values;
values
<< "None" << inPlaceEdit << editRecord << view << "Revert" << "Delete"
<< editRecordAndClose << "View and Close";
QString toolTip = "<ul>"
"<li>None</li>"
"<li>Edit in Place: Edit the clicked cell</li>"
"<li>Edit Record: Open a dialogue subview for the clicked record</li>"
"<li>View: Open a scene subview for the clicked record (not available everywhere)</li>"
"<li>Revert: Revert record</li>"
"<li>Delete: Delete recordy</li>"
"<li>Edit Record and Close: Open a dialogue subview for the clicked record and close the table subview</li>"
"<li>View And Close: Open a scene subview for the clicked record and close the table subview</li>"
"</ul>";
Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click");
doubleClick->setDeclaredValues (values);
doubleClick->setDefaultValue (inPlaceEdit);
doubleClick->setToolTip ("Action on double click in table:<p>" + toolTip);
Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s",
"Shift Double Click");
shiftDoubleClick->setDeclaredValues (values);
shiftDoubleClick->setDefaultValue (editRecord);
shiftDoubleClick->setToolTip ("Action on shift double click in table:<p>" + toolTip);
Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c",
"Control Double Click");
ctrlDoubleClick->setDeclaredValues (values);
ctrlDoubleClick->setDefaultValue (view);
ctrlDoubleClick->setToolTip ("Action on control double click in table:<p>" + toolTip);
Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc",
"Shift Control Double Click");
shiftCtrlDoubleClick->setDeclaredValues (values);
shiftCtrlDoubleClick->setDefaultValue (editRecordAndClose);
shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in table:<p>" + toolTip);
} }
section = "Proxy Selection Test";
{ {
/****************************************************************** /******************************************************************
* There are three types of values: * There are three types of values:
@ -276,7 +383,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
CSMSettings::UserSettings::~UserSettings() CSMSettings::UserSettings::~UserSettings()
{ {
mUserSettingsInstance = 0; sUserSettingsInstance = 0;
} }
void CSMSettings::UserSettings::loadSettings (const QString &fileName) void CSMSettings::UserSettings::loadSettings (const QString &fileName)
@ -307,8 +414,21 @@ void CSMSettings::UserSettings::loadSettings (const QString &fileName)
(QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this); (QSettings::IniFormat, QSettings::UserScope, "opencs", QString(), this);
} }
bool CSMSettings::UserSettings::hasSettingDefinitions // if the key is not found create one with a default value
(const QString &viewKey) const QString CSMSettings::UserSettings::setting(const QString &viewKey, const QString &value)
{
if(mSettingDefinitions->contains(viewKey))
return settingValue(viewKey);
else if(value != QString())
{
mSettingDefinitions->setValue (viewKey, QStringList() << value);
return value;
}
return QString();
}
bool CSMSettings::UserSettings::hasSettingDefinitions (const QString &viewKey) const
{ {
return (mSettingDefinitions->contains (viewKey)); return (mSettingDefinitions->contains (viewKey));
} }
@ -326,10 +446,12 @@ void CSMSettings::UserSettings::saveDefinitions() const
QString CSMSettings::UserSettings::settingValue (const QString &settingKey) QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
{ {
QStringList defs;
if (!mSettingDefinitions->contains (settingKey)) if (!mSettingDefinitions->contains (settingKey))
return QString(); return QString();
QStringList defs = mSettingDefinitions->value (settingKey).toStringList(); defs = mSettingDefinitions->value (settingKey).toStringList();
if (defs.isEmpty()) if (defs.isEmpty())
return QString(); return QString();
@ -339,8 +461,8 @@ QString CSMSettings::UserSettings::settingValue (const QString &settingKey)
CSMSettings::UserSettings& CSMSettings::UserSettings::instance() CSMSettings::UserSettings& CSMSettings::UserSettings::instance()
{ {
assert(mUserSettingsInstance); assert(sUserSettingsInstance);
return *mUserSettingsInstance; return *sUserSettingsInstance;
} }
void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey, void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
@ -348,6 +470,15 @@ void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
{ {
mSettingDefinitions->setValue (settingKey ,list); mSettingDefinitions->setValue (settingKey ,list);
if(settingKey == "3d-render-adv/num_lights" && !list.empty())
{
sh::Factory::getInstance ().setGlobalSetting ("num_lights", list.at(0).toStdString());
}
else if(settingKey == "3d-render/shaders" && !list.empty())
{
sh::Factory::getInstance ().setShadersEnabled (list.at(0).toStdString() == "true" ? true : false);
}
emit userSettingUpdated (settingKey, list); emit userSettingUpdated (settingKey, list);
} }
@ -387,30 +518,62 @@ void CSMSettings::UserSettings::removeSetting
} }
} }
CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const CSMSettings::SettingPageMap CSMSettings::UserSettings::settingPageMap() const
{ {
SettingPageMap pageMap; SettingPageMap pageMap;
foreach (Setting *setting, mSettings) foreach (Setting *setting, mSettings)
pageMap[setting->page()].append (setting); {
SettingPageMap::iterator iter = pageMap.find (setting->page());
if (iter==pageMap.end())
{
QPair<QString, QList <Setting *> > value;
std::map<QString, QString>::const_iterator iter2 =
mSectionLabels.find (setting->page());
value.first = iter2!=mSectionLabels.end() ? iter2->second : "";
iter = pageMap.insert (setting->page(), value);
}
iter->second.append (setting);
}
return pageMap; return pageMap;
} }
CSMSettings::Setting *CSMSettings::UserSettings::createSetting CSMSettings::Setting *CSMSettings::UserSettings::createSetting
(CSMSettings::SettingType typ, const QString &page, const QString &name) (CSMSettings::SettingType type, const QString &name, const QString& label)
{ {
//get list of all settings for the current setting name Setting *setting = new Setting (type, name, mSection, label);
if (findSetting (page, name))
{ // set useful defaults
qWarning() << "Duplicate declaration encountered: " int row = 1;
<< (name + '/' + page);
return 0; if (!mSettings.empty())
} row = mSettings.back()->viewRow()+1;
setting->setViewLocation (row, 1);
setting->setColumnSpan (3);
Setting *setting = new Setting (typ, name, page); int width = 10;
if (type==Type_CheckBox)
width = 40;
setting->setWidgetWidth (width);
if (type==Type_CheckBox)
setting->setStyleSheet ("QGroupBox { border: 0px; }");
if (type==Type_CheckBox)
setting->setDeclaredValues(QStringList() << "true" << "false");
if (type==Type_CheckBox)
setting->setSpecialValueText (setting->getLabel());
//add declaration to the model //add declaration to the model
mSettings.append (setting); mSettings.append (setting);
@ -418,6 +581,12 @@ CSMSettings::Setting *CSMSettings::UserSettings::createSetting
return setting; return setting;
} }
void CSMSettings::UserSettings::declareSection (const QString& page, const QString& label)
{
mSection = page;
mSectionLabels[page] = label;
}
QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const QStringList CSMSettings::UserSettings::definitions (const QString &viewKey) const
{ {
if (mSettingDefinitions->contains (viewKey)) if (mSettingDefinitions->contains (viewKey))

@ -1,10 +1,13 @@
#ifndef USERSETTINGS_HPP #ifndef USERSETTINGS_HPP
#define USERSETTINGS_HPP #define USERSETTINGS_HPP
#include <map>
#include <QList> #include <QList>
#include <QStringList> #include <QStringList>
#include <QString> #include <QString>
#include <QMap> #include <QMap>
#include <QPair>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include "support.hpp" #include "support.hpp"
@ -22,18 +25,20 @@ class QSettings;
namespace CSMSettings { namespace CSMSettings {
class Setting; class Setting;
typedef QMap <QString, QList <Setting *> > SettingPageMap; typedef QMap <QString, QPair<QString, QList <Setting *> > > SettingPageMap;
class UserSettings: public QObject class UserSettings: public QObject
{ {
Q_OBJECT Q_OBJECT
static UserSettings *mUserSettingsInstance; static UserSettings *sUserSettingsInstance;
const Files::ConfigurationManager& mCfgMgr; const Files::ConfigurationManager& mCfgMgr;
QSettings *mSettingDefinitions; QSettings *mSettingDefinitions;
QList <Setting *> mSettings; QList <Setting *> mSettings;
QString mSection;
std::map<QString, QString> mSectionLabels;
public: public:
@ -62,7 +67,7 @@ namespace CSMSettings {
void removeSetting void removeSetting
(const QString &pageName, const QString &settingName); (const QString &pageName, const QString &settingName);
///Retreive a map of the settings, keyed by page name ///Retrieve a map of the settings, keyed by page name
SettingPageMap settingPageMap() const; SettingPageMap settingPageMap() const;
///Returns a string list of defined vlaues for the specified setting ///Returns a string list of defined vlaues for the specified setting
@ -75,13 +80,20 @@ namespace CSMSettings {
///Save any unsaved changes in the QSettings object ///Save any unsaved changes in the QSettings object
void saveDefinitions() const; void saveDefinitions() const;
QString setting(const QString &viewKey, const QString &value = QString());
private: private:
void buildSettingModelDefaults(); void buildSettingModelDefaults();
///add a new setting to the model and return it ///add a new setting to the model and return it
Setting *createSetting (CSMSettings::SettingType typ, Setting *createSetting (CSMSettings::SettingType type, const QString &name,
const QString &page, const QString &name); const QString& label);
/// Set the section for createSetting calls.
///
/// Sections can be declared multiple times.
void declareSection (const QString& page, const QString& label);
signals: signals:

@ -0,0 +1,51 @@
#include "bodypartcheck.hpp"
CSMTools::BodyPartCheckStage::BodyPartCheckStage(
const CSMWorld::IdCollection<ESM::BodyPart> &bodyParts,
const CSMWorld::Resources &meshes,
const CSMWorld::IdCollection<ESM::Race> &races ) :
mBodyParts(bodyParts),
mMeshes(meshes),
mRaces(races)
{ }
int CSMTools::BodyPartCheckStage::setup()
{
return mBodyParts.getSize();
}
void CSMTools::BodyPartCheckStage::perform ( int stage, Messages &messages )
{
const CSMWorld::Record<ESM::BodyPart> &record = mBodyParts.getRecord(stage);
if ( record.isDeleted() )
return;
const ESM::BodyPart &bodyPart = record.get();
CSMWorld::UniversalId id( CSMWorld::UniversalId::Type_BodyPart, bodyPart.mId );
// Check BYDT
if (bodyPart.mData.mPart > 14 )
messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range part value." ));
if (bodyPart.mData.mFlags > 3 )
messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range flags value." ));
if (bodyPart.mData.mType > 2 )
messages.push_back(std::make_pair( id, bodyPart.mId + " has out of range type value." ));
// Check MODL
if ( bodyPart.mModel.empty() )
messages.push_back(std::make_pair( id, bodyPart.mId + " has no model." ));
else if ( mMeshes.searchId( bodyPart.mModel ) == -1 )
messages.push_back(std::make_pair( id, bodyPart.mId + " has invalid model." ));
// Check FNAM
if ( bodyPart.mRace.empty() )
messages.push_back(std::make_pair( id, bodyPart.mId + " has no race." ));
else if ( mRaces.searchId( bodyPart.mRace ) == -1 )
messages.push_back(std::make_pair( id, bodyPart.mId + " has invalid race." ));
}

@ -0,0 +1,35 @@
#ifndef CSM_TOOLS_BODYPARTCHECK_H
#define CSM_TOOLS_BODYPARTCHECK_H
#include <components/esm/loadbody.hpp>
#include <components/esm/loadrace.hpp>
#include "../world/resources.hpp"
#include "../world/idcollection.hpp"
#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that body part records are internally consistent
class BodyPartCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::BodyPart> &mBodyParts;
const CSMWorld::Resources &mMeshes;
const CSMWorld::IdCollection<ESM::Race> &mRaces;
public:
BodyPartCheckStage(
const CSMWorld::IdCollection<ESM::BodyPart> &bodyParts,
const CSMWorld::Resources &meshes,
const CSMWorld::IdCollection<ESM::Race> &races );
virtual int setup();
///< \return number of steps
virtual void perform( int stage, Messages &messages );
///< Messages resulting from this tage will be appended to \a messages.
};
}
#endif

@ -42,7 +42,7 @@ void CSMTools::FactionCheckStage::perform (int stage, Messages& messages)
// test for non-unique skill // test for non-unique skill
std::map<int, int> skills; // ID, number of occurrences std::map<int, int> skills; // ID, number of occurrences
for (int i=0; i<6; ++i) for (int i=0; i<7; ++i)
if (faction.mData.mSkills[i]!=-1) if (faction.mData.mSkills[i]!=-1)
++skills[faction.mData.mSkills[i]]; ++skills[faction.mData.mSkills[i]];
@ -54,4 +54,4 @@ void CSMTools::FactionCheckStage::perform (int stage, Messages& messages)
} }
/// \todo check data members that can't be edited in the table view /// \todo check data members that can't be edited in the table view
} }

@ -621,12 +621,6 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
} }
else else
{ {
if (npc.mNpdt52.mMana < 0)
messages.push_back (std::make_pair (id, npc.mId + " mana has negative value"));
if (npc.mNpdt52.mFatigue < 0)
messages.push_back (std::make_pair (id, npc.mId + " fatigue has negative value"));
if (npc.mNpdt52.mAgility == 0) if (npc.mNpdt52.mAgility == 0)
messages.push_back (std::make_pair (id, npc.mId + " agility has zero value")); messages.push_back (std::make_pair (id, npc.mId + " agility has zero value"));

@ -7,6 +7,8 @@
#include <components/compiler/exception.hpp> #include <components/compiler/exception.hpp>
#include <components/compiler/extensions0.hpp> #include <components/compiler/extensions0.hpp>
#include "../doc/document.hpp"
#include "../world/data.hpp" #include "../world/data.hpp"
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc, void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
@ -37,8 +39,8 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
(type==ErrorMessage ? "error: " : "warning: ") + message)); (type==ErrorMessage ? "error: " : "warning: ") + message));
} }
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMWorld::Data& data) CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document)
: mData (data), mContext (data), mMessages (0) : mDocument (document), mContext (document.getData()), mMessages (0)
{ {
/// \todo add an option to configure warning mode /// \todo add an option to configure warning mode
setWarningsMode (0); setWarningsMode (0);
@ -53,18 +55,25 @@ int CSMTools::ScriptCheckStage::setup()
mMessages = 0; mMessages = 0;
mId.clear(); mId.clear();
return mData.getScripts().getSize(); return mDocument.getData().getScripts().getSize();
} }
void CSMTools::ScriptCheckStage::perform (int stage, Messages& messages) void CSMTools::ScriptCheckStage::perform (int stage, Messages& messages)
{ {
mId = mDocument.getData().getScripts().getId (stage);
if (mDocument.isBlacklisted (
CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Script, mId)))
return;
mMessages = &messages; mMessages = &messages;
mId = mData.getScripts().getId (stage);
try try
{ {
mFile = mData.getScripts().getRecord (stage).get().mId; const CSMWorld::Data& data = mDocument.getData();
std::istringstream input (mData.getScripts().getRecord (stage).get().mScriptText);
mFile = data.getScripts().getRecord (stage).get().mId;
std::istringstream input (data.getScripts().getRecord (stage).get().mScriptText);
Compiler::Scanner scanner (*this, input, mContext.getExtensions()); Compiler::Scanner scanner (*this, input, mContext.getExtensions());

@ -8,12 +8,17 @@
#include "../world/scriptcontext.hpp" #include "../world/scriptcontext.hpp"
namespace CSMDoc
{
class Document;
}
namespace CSMTools namespace CSMTools
{ {
/// \brief VerifyStage: make sure that scripts compile /// \brief VerifyStage: make sure that scripts compile
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
{ {
const CSMWorld::Data& mData; const CSMDoc::Document& mDocument;
Compiler::Extensions mExtensions; Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext; CSMWorld::ScriptContext mContext;
std::string mId; std::string mId;
@ -28,7 +33,7 @@ namespace CSMTools
public: public:
ScriptCheckStage (const CSMWorld::Data& data); ScriptCheckStage (const CSMDoc::Document& document);
virtual int setup(); virtual int setup();
///< \return number of steps ///< \return number of steps

@ -5,6 +5,7 @@
#include "../doc/state.hpp" #include "../doc/state.hpp"
#include "../doc/operation.hpp" #include "../doc/operation.hpp"
#include "../doc/document.hpp"
#include "../world/data.hpp" #include "../world/data.hpp"
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
@ -21,6 +22,7 @@
#include "spellcheck.hpp" #include "spellcheck.hpp"
#include "referenceablecheck.hpp" #include "referenceablecheck.hpp"
#include "scriptcheck.hpp" #include "scriptcheck.hpp"
#include "bodypartcheck.hpp"
CSMDoc::Operation *CSMTools::Tools::get (int type) CSMDoc::Operation *CSMTools::Tools::get (int type)
{ {
@ -44,7 +46,7 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false); mVerifier = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (mVerifier, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (mVerifier, SIGNAL (done (int)), this, SIGNAL (done (int))); connect (mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (mVerifier, connect (mVerifier,
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)), SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int))); this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, int)));
@ -78,15 +80,23 @@ CSMDoc::Operation *CSMTools::Tools::getVerifier()
mVerifier->appendStage (new SpellCheckStage (mData.getSpells())); mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions())); mVerifier->appendStage (new ReferenceableCheckStage (mData.getReferenceables().getDataSet(), mData.getRaces(), mData.getClasses(), mData.getFactions()));
mVerifier->appendStage (new ScriptCheckStage (mData)); mVerifier->appendStage (new ScriptCheckStage (mDocument));
mVerifier->appendStage(
new BodyPartCheckStage(
mData.getBodyParts(),
mData.getResources(
CSMWorld::UniversalId( CSMWorld::UniversalId::Type_Meshes )),
mData.getRaces() ));
} }
return mVerifier; return mVerifier;
} }
CSMTools::Tools::Tools (CSMWorld::Data& data) : mData (data), mVerifier (0), mNextReportNumber (0) CSMTools::Tools::Tools (CSMDoc::Document& document)
: mDocument (document), mData (document.getData()), mVerifier (0), mNextReportNumber (0)
{ {
// index 0: load error log // index 0: load error log
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel));

@ -14,6 +14,7 @@ namespace CSMWorld
namespace CSMDoc namespace CSMDoc
{ {
class Operation; class Operation;
class Document;
} }
namespace CSMTools namespace CSMTools
@ -24,6 +25,7 @@ namespace CSMTools
{ {
Q_OBJECT Q_OBJECT
CSMDoc::Document& mDocument;
CSMWorld::Data& mData; CSMWorld::Data& mData;
CSMDoc::Operation *mVerifier; CSMDoc::Operation *mVerifier;
std::map<int, ReportModel *> mReports; std::map<int, ReportModel *> mReports;
@ -44,7 +46,7 @@ namespace CSMTools
public: public:
Tools (CSMWorld::Data& data); Tools (CSMDoc::Document& document);
virtual ~Tools(); virtual ~Tools();
@ -68,7 +70,7 @@ namespace CSMTools
void progress (int current, int max, int type); void progress (int current, int max, int type);
void done (int type); void done (int type, bool failed);
}; };
} }

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

@ -15,12 +15,9 @@ namespace CSMWorld
struct Cell : public ESM::Cell struct Cell : public ESM::Cell
{ {
std::string mId; std::string mId;
std::vector<std::pair<std::string, bool> > mRefs; // ID, modified
std::vector<std::string> mDeletedRefs;
void load (ESM::ESMReader &esm); void load (ESM::ESMReader &esm);
void addRef (const std::string& id);
}; };
} }

@ -68,6 +68,7 @@ namespace CSMWorld
Display_TopicInfo, Display_TopicInfo,
Display_JournalInfo, Display_JournalInfo,
Display_Scene, Display_Scene,
Display_GlobalVariable,
//CONCRETE TYPES ENDS HERE //CONCRETE TYPES ENDS HERE
Display_Integer, Display_Integer,
@ -89,7 +90,20 @@ namespace CSMWorld
Display_RefRecordType, Display_RefRecordType,
Display_DialogueType, Display_DialogueType,
Display_QuestStatusType, Display_QuestStatusType,
Display_Gender Display_EnchantmentType,
Display_BodyPartType,
Display_MeshType,
Display_Gender,
Display_Mesh,
Display_Icon,
Display_Music,
Display_SoundRes,
Display_Texture,
Display_Video,
Display_Colour,
Display_ScriptLines, // console context
Display_SoundGeneratorType,
Display_School
}; };
int mColumnId; int mColumnId;
@ -113,8 +127,6 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct Column : public ColumnBase struct Column : public ColumnBase
{ {
int mFlags;
Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue) Column (int columnId, Display displayType, int flags = Flag_Table | Flag_Dialogue)
: ColumnBase (columnId, displayType, flags) {} : ColumnBase (columnId, displayType, flags) {}

@ -1,7 +1,9 @@
#ifndef CSM_WOLRD_COLUMNIMP_H #ifndef CSM_WOLRD_COLUMNIMP_H
#define CSM_WOLRD_COLUMNIMP_H #define CSM_WOLRD_COLUMNIMP_H
#include <cassert>
#include <sstream> #include <sstream>
#include <stdexcept>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
@ -463,14 +465,21 @@ namespace CSMWorld
struct FlagColumn : public Column<ESXRecordT> struct FlagColumn : public Column<ESXRecordT>
{ {
int mMask; int mMask;
bool mInverted;
FlagColumn (int columnId, int mask) FlagColumn (int columnId, int mask, bool inverted = false)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Boolean), mMask (mask) : Column<ESXRecordT> (columnId, ColumnBase::Display_Boolean), mMask (mask),
mInverted (inverted)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
return (record.get().mData.mFlags & mMask)!=0; bool flag = (record.get().mData.mFlags & mMask)!=0;
if (mInverted)
flag = !flag;
return flag;
} }
virtual void set (Record<ESXRecordT>& record, const QVariant& data) virtual void set (Record<ESXRecordT>& record, const QVariant& data)
@ -479,7 +488,7 @@ namespace CSMWorld
int flags = record2.mData.mFlags & ~mMask; int flags = record2.mData.mFlags & ~mMask;
if (data.toInt()) if ((data.toInt()!=0)!=mInverted)
flags |= mMask; flags |= mMask;
record2.mData.mFlags = flags; record2.mData.mFlags = flags;
@ -493,6 +502,47 @@ namespace CSMWorld
} }
}; };
template<typename ESXRecordT>
struct FlagColumn2 : public Column<ESXRecordT>
{
int mMask;
bool mInverted;
FlagColumn2 (int columnId, int mask, bool inverted = false)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Boolean), mMask (mask),
mInverted (inverted)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
bool flag = (record.get().mFlags & mMask)!=0;
if (mInverted)
flag = !flag;
return flag;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
int flags = record2.mFlags & ~mMask;
if ((data.toInt()!=0)!=mInverted)
flags |= mMask;
record2.mFlags = flags;
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT> template<typename ESXRecordT>
struct WeightHeightColumn : public Column<ESXRecordT> struct WeightHeightColumn : public Column<ESXRecordT>
{ {
@ -597,7 +647,7 @@ namespace CSMWorld
struct SoundFileColumn : public Column<ESXRecordT> struct SoundFileColumn : public Column<ESXRecordT>
{ {
SoundFileColumn() SoundFileColumn()
: Column<ESXRecordT> (Columns::ColumnId_SoundFile, ColumnBase::Display_Sound) : Column<ESXRecordT> (Columns::ColumnId_SoundFile, ColumnBase::Display_SoundRes)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
@ -627,7 +677,7 @@ namespace CSMWorld
{ {
/// \todo Replace Display_Integer with something that displays the colour value more directly. /// \todo Replace Display_Integer with something that displays the colour value more directly.
MapColourColumn() MapColourColumn()
: Column<ESXRecordT> (Columns::ColumnId_MapColour, ColumnBase::Display_Integer) : Column<ESXRecordT> (Columns::ColumnId_MapColour, ColumnBase::Display_Colour)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
@ -759,8 +809,18 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct ScriptColumn : public Column<ESXRecordT> struct ScriptColumn : public Column<ESXRecordT>
{ {
ScriptColumn() enum Type
: Column<ESXRecordT> (Columns::ColumnId_ScriptText, ColumnBase::Display_Script, 0) {} {
Type_File, // regular script record
Type_Lines, // console context
Type_Info // dialogue context (not implemented yet)
};
ScriptColumn (Type type)
: Column<ESXRecordT> (Columns::ColumnId_ScriptText,
type==Type_File ? ColumnBase::Display_Script : ColumnBase::Display_ScriptLines,
type==Type_File ? 0 : ColumnBase::Flag_Dialogue)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -970,13 +1030,13 @@ namespace CSMWorld
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
return record.get().mFactIndex; return record.get().mFactionRank;
} }
virtual void set (Record<ESXRecordT>& record, const QVariant& data) virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
record2.mFactIndex = data.toInt(); record2.mFactionRank = data.toInt();
record.setModified (record2); record.setModified (record2);
} }
@ -1217,36 +1277,6 @@ namespace CSMWorld
} }
}; };
template<typename ESXRecordT>
struct ScopeColumn : public Column<ESXRecordT>
{
ScopeColumn()
: Column<ESXRecordT> (Columns::ColumnId_Scope, ColumnBase::Display_Integer, 0)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mScope);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mScope = static_cast<CSMFilter::Filter::Scope> (data.toInt());
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT> template<typename ESXRecordT>
struct PosColumn : public Column<ESXRecordT> struct PosColumn : public Column<ESXRecordT>
@ -1269,7 +1299,7 @@ namespace CSMWorld
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
ESM::Position& position = record.get().*mPosition; ESM::Position& position = record2.*mPosition;
position.pos[mIndex] = data.toFloat(); position.pos[mIndex] = data.toFloat();
@ -1303,7 +1333,7 @@ namespace CSMWorld
{ {
ESXRecordT record2 = record.get(); ESXRecordT record2 = record.get();
ESM::Position& position = record.get().*mPosition; ESM::Position& position = record2.*mPosition;
position.rot[mIndex] = data.toFloat(); position.rot[mIndex] = data.toFloat();
@ -1682,6 +1712,559 @@ namespace CSMWorld
return true; return true;
} }
}; };
template<typename ESXRecordT>
struct EnchantmentTypeColumn : public Column<ESXRecordT>
{
EnchantmentTypeColumn()
: Column<ESXRecordT> (Columns::ColumnId_EnchantmentType, ColumnBase::Display_EnchantmentType)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mData.mType);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mType = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct ChargesColumn2 : public Column<ESXRecordT>
{
ChargesColumn2() : Column<ESXRecordT> (Columns::ColumnId_Charges, ColumnBase::Display_Integer) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mCharge;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mCharge = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct AutoCalcColumn : public Column<ESXRecordT>
{
AutoCalcColumn() : Column<ESXRecordT> (Columns::ColumnId_AutoCalc, ColumnBase::Display_Boolean)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mAutocalc!=0;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mAutocalc = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct ModelColumn : public Column<ESXRecordT>
{
ModelColumn() : Column<ESXRecordT> (Columns::ColumnId_Model, ColumnBase::Display_String) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mModel.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mModel = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct VampireColumn : public Column<ESXRecordT>
{
VampireColumn() : Column<ESXRecordT> (Columns::ColumnId_Vampire, ColumnBase::Display_Boolean)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mVampire!=0;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mVampire = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct BodyPartTypeColumn : public Column<ESXRecordT>
{
BodyPartTypeColumn()
: Column<ESXRecordT> (Columns::ColumnId_BodyPartType, ColumnBase::Display_BodyPartType)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mData.mPart);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mPart = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct MeshTypeColumn : public Column<ESXRecordT>
{
MeshTypeColumn()
: Column<ESXRecordT> (Columns::ColumnId_MeshType, ColumnBase::Display_MeshType)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mData.mType);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mType = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct OwnerGlobalColumn : public Column<ESXRecordT>
{
OwnerGlobalColumn()
: Column<ESXRecordT> (Columns::ColumnId_OwnerGlobal, ColumnBase::Display_GlobalVariable)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mGlobalVariable.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mGlobalVariable = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct RefNumCounterColumn : public Column<ESXRecordT>
{
RefNumCounterColumn()
: Column<ESXRecordT> (Columns::ColumnId_RefNumCounter, ColumnBase::Display_Integer, 0)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mRefNumCounter);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mRefNumCounter = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct RefNumColumn : public Column<ESXRecordT>
{
RefNumColumn()
: Column<ESXRecordT> (Columns::ColumnId_RefNum, ColumnBase::Display_Integer, 0)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mRefNum.mIndex);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mRefNum.mIndex = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct SoundColumn : public Column<ESXRecordT>
{
SoundColumn()
: Column<ESXRecordT> (Columns::ColumnId_Sound, ColumnBase::Display_Sound)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mSound.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mSound = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct CreatureColumn : public Column<ESXRecordT>
{
CreatureColumn()
: Column<ESXRecordT> (Columns::ColumnId_Creature, ColumnBase::Display_Creature)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mCreature.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mCreature = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct SoundGeneratorTypeColumn : public Column<ESXRecordT>
{
SoundGeneratorTypeColumn()
: Column<ESXRecordT> (Columns::ColumnId_SoundGeneratorType, ColumnBase::Display_SoundGeneratorType)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mType);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mType = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct BaseCostColumn : public Column<ESXRecordT>
{
BaseCostColumn() : Column<ESXRecordT> (Columns::ColumnId_BaseCost, ColumnBase::Display_Float) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mBaseCost;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mBaseCost = data.toFloat();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct SchoolColumn : public Column<ESXRecordT>
{
SchoolColumn()
: Column<ESXRecordT> (Columns::ColumnId_School, ColumnBase::Display_School)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mSchool;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mSchool = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct EffectTextureColumn : public Column<ESXRecordT>
{
EffectTextureColumn (Columns::ColumnId columnId)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Texture)
{
assert (this->mColumnId==Columns::ColumnId_Icon ||
this->mColumnId==Columns::ColumnId_Particle);
}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (
(this->mColumnId==Columns::ColumnId_Icon ?
record.get().mIcon : record.get().mParticle).c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
(this->mColumnId==Columns::ColumnId_Icon ?
record2.mIcon : record2.mParticle)
= data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct EffectObjectColumn : public Column<ESXRecordT>
{
EffectObjectColumn (Columns::ColumnId columnId)
: Column<ESXRecordT> (columnId, columnId==Columns::ColumnId_BoltObject ? ColumnBase::Display_Weapon : ColumnBase::Display_Static)
{
assert (this->mColumnId==Columns::ColumnId_CastingObject ||
this->mColumnId==Columns::ColumnId_HitObject ||
this->mColumnId==Columns::ColumnId_AreaObject ||
this->mColumnId==Columns::ColumnId_BoltObject);
}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
const std::string *string = 0;
switch (this->mColumnId)
{
case Columns::ColumnId_CastingObject: string = &record.get().mCasting; break;
case Columns::ColumnId_HitObject: string = &record.get().mHit; break;
case Columns::ColumnId_AreaObject: string = &record.get().mArea; break;
case Columns::ColumnId_BoltObject: string = &record.get().mBolt; break;
}
if (!string)
throw std::logic_error ("Unsupported column ID");
return QString::fromUtf8 (string->c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
std::string *string = 0;
ESXRecordT record2 = record.get();
switch (this->mColumnId)
{
case Columns::ColumnId_CastingObject: string = &record2.mCasting; break;
case Columns::ColumnId_HitObject: string = &record2.mHit; break;
case Columns::ColumnId_AreaObject: string = &record2.mArea; break;
case Columns::ColumnId_BoltObject: string = &record2.mBolt; break;
}
if (!string)
throw std::logic_error ("Unsupported column ID");
*string = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct EffectSoundColumn : public Column<ESXRecordT>
{
EffectSoundColumn (Columns::ColumnId columnId)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Sound)
{
assert (this->mColumnId==Columns::ColumnId_CastingSound ||
this->mColumnId==Columns::ColumnId_HitSound ||
this->mColumnId==Columns::ColumnId_AreaSound ||
this->mColumnId==Columns::ColumnId_BoltSound);
}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
const std::string *string = 0;
switch (this->mColumnId)
{
case Columns::ColumnId_CastingSound: string = &record.get().mCastSound; break;
case Columns::ColumnId_HitSound: string = &record.get().mHitSound; break;
case Columns::ColumnId_AreaSound: string = &record.get().mAreaSound; break;
case Columns::ColumnId_BoltSound: string = &record.get().mBoltSound; break;
}
if (!string)
throw std::logic_error ("Unsupported column ID");
return QString::fromUtf8 (string->c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
std::string *string = 0;
ESXRecordT record2 = record.get();
switch (this->mColumnId)
{
case Columns::ColumnId_CastingSound: string = &record2.mCastSound; break;
case Columns::ColumnId_HitSound: string = &record2.mHitSound; break;
case Columns::ColumnId_AreaSound: string = &record2.mAreaSound; break;
case Columns::ColumnId_BoltSound: string = &record2.mBoltSound; break;
}
if (!string)
throw std::logic_error ("Unsupported column ID");
*string = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
} }
#endif #endif

@ -172,8 +172,35 @@ namespace CSMWorld
{ ColumnId_Rank, "Rank" }, { ColumnId_Rank, "Rank" },
{ ColumnId_Gender, "Gender" }, { ColumnId_Gender, "Gender" },
{ ColumnId_PcRank, "PC Rank" }, { ColumnId_PcRank, "PC Rank" },
{ ColumnId_Scope, "Scope" },
{ ColumnId_ReferenceableId, "Referenceable ID" }, { ColumnId_ReferenceableId, "Referenceable ID" },
{ ColumnId_CombatState, "Combat" },
{ ColumnId_MagicState, "Magic" },
{ ColumnId_StealthState, "Stealth" },
{ ColumnId_EnchantmentType, "Enchantment Type" },
{ ColumnId_Vampire, "Vampire" },
{ ColumnId_BodyPartType, "Bodypart Type" },
{ ColumnId_MeshType, "Mesh Type" },
{ ColumnId_OwnerGlobal, "Owner Global" },
{ ColumnId_DefaultProfile, "Default Profile" },
{ ColumnId_BypassNewGame, "Bypass New Game" },
{ ColumnId_GlobalProfile, "Global Profile" },
{ ColumnId_RefNumCounter, "RefNum Counter" },
{ ColumnId_RefNum, "RefNum" },
{ ColumnId_Creature, "Creature" },
{ ColumnId_SoundGeneratorType, "Sound Generator Type" },
{ ColumnId_AllowSpellmaking, "Allow Spellmaking" },
{ ColumnId_AllowEnchanting, "Allow Enchanting" },
{ ColumnId_BaseCost, "Base Cost" },
{ ColumnId_School, "School" },
{ ColumnId_Particle, "Particle" },
{ ColumnId_CastingObject, "Casting Object" },
{ ColumnId_HitObject, "Hit Object" },
{ ColumnId_AreaObject, "Area Object" },
{ ColumnId_BoltObject, "Bolt Object" },
{ ColumnId_CastingSound, "Casting Sound" },
{ ColumnId_HitSound, "Hit Sound" },
{ ColumnId_AreaSound, "Area Sound" },
{ ColumnId_BoltSound, "Bolt Sound" },
{ ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue2, "Use value 2" },
@ -299,6 +326,33 @@ namespace
"Male", "Female", 0 "Male", "Female", 0
}; };
static const char *sEnchantmentTypes[] =
{
"Cast Once", "When Strikes", "When Used", "Constant Effect", 0
};
static const char *sBodyPartTypes[] =
{
"Head", "Hair", "Neck", "Chest", "Groin", "Hand", "Wrist", "Forearm", "Upper Arm",
"Foot", "Ankle", "Knee", "Upper Leg", "Clavicle", "Tail", 0
};
static const char *sMeshTypes[] =
{
"Skin", "Clothing", "Armour", 0
};
static const char *sSoundGeneratorType[] =
{
"Left Foot", "Right Foot", "Swim Left", "Swim Right", "Moan", "Roar", "Scream",
"Land", 0
};
static const char *sSchools[] =
{
"Alteration", "Conjuration", "Destruction", "Illusion", "Mysticism", "Restoration", 0
};
const char **getEnumNames (CSMWorld::Columns::ColumnId column) const char **getEnumNames (CSMWorld::Columns::ColumnId column)
{ {
switch (column) switch (column)
@ -316,6 +370,11 @@ namespace
case CSMWorld::Columns::ColumnId_DialogueType: return sDialogueTypeEnums; case CSMWorld::Columns::ColumnId_DialogueType: return sDialogueTypeEnums;
case CSMWorld::Columns::ColumnId_QuestStatusType: return sQuestStatusTypes; case CSMWorld::Columns::ColumnId_QuestStatusType: return sQuestStatusTypes;
case CSMWorld::Columns::ColumnId_Gender: return sGenderEnums; case CSMWorld::Columns::ColumnId_Gender: return sGenderEnums;
case CSMWorld::Columns::ColumnId_EnchantmentType: return sEnchantmentTypes;
case CSMWorld::Columns::ColumnId_BodyPartType: return sBodyPartTypes;
case CSMWorld::Columns::ColumnId_MeshType: return sMeshTypes;
case CSMWorld::Columns::ColumnId_SoundGeneratorType: return sSoundGeneratorType;
case CSMWorld::Columns::ColumnId_School: return sSchools;
default: return 0; default: return 0;
} }

@ -165,9 +165,35 @@ namespace CSMWorld
ColumnId_Rank = 152, ColumnId_Rank = 152,
ColumnId_Gender = 153, ColumnId_Gender = 153,
ColumnId_PcRank = 154, ColumnId_PcRank = 154,
ColumnId_Scope = 155,
ColumnId_ReferenceableId = 156, ColumnId_ReferenceableId = 156,
ColumnId_CombatState = 157,
ColumnId_MagicState = 158,
ColumnId_StealthState = 159,
ColumnId_EnchantmentType = 160,
ColumnId_Vampire = 161,
ColumnId_BodyPartType = 162,
ColumnId_MeshType = 163,
ColumnId_OwnerGlobal = 164,
ColumnId_DefaultProfile = 165,
ColumnId_BypassNewGame = 166,
ColumnId_GlobalProfile = 167,
ColumnId_RefNumCounter = 168,
ColumnId_RefNum = 169,
ColumnId_Creature = 170,
ColumnId_SoundGeneratorType = 171,
ColumnId_AllowSpellmaking = 172,
ColumnId_AllowEnchanting = 173,
ColumnId_BaseCost = 174,
ColumnId_School = 175,
ColumnId_Particle = 176,
ColumnId_CastingObject = 177,
ColumnId_HitObject = 178,
ColumnId_AreaObject = 179,
ColumnId_BoltObject = 180,
ColumnId_CastingSound = 177,
ColumnId_HitSound = 178,
ColumnId_AreaSound = 179,
ColumnId_BoltSound = 180,
// Allocated to a separate value range, so we don't get a collision should we ever need // Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values. // to extend the number of use values.
ColumnId_UseValue1 = 0x10000, ColumnId_UseValue1 = 0x10000,
@ -212,7 +238,7 @@ namespace CSMWorld
bool hasEnums (ColumnId column); bool hasEnums (ColumnId column);
std::vector<std::string> getEnums (ColumnId column); std::vector<std::string> getEnums (ColumnId column);
///< Returns an empty vector, if \æ column isn't an enum type column. ///< Returns an empty vector, if \a column isn't an enum type column.
} }
} }

@ -0,0 +1,267 @@
#include "commanddispatcher.hpp"
#include <algorithm>
#include <components/misc/stringops.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;
std::for_each (mSelection.begin(), mSelection.end(), Misc::StringUtils::toLower);
std::sort (mSelection.begin(), mSelection.end());
}
void CSMWorld::CommandDispatcher::setExtendedTypes (const std::vector<UniversalId>& types)
{
mExtendedTypes = types;
}
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;
}
std::vector<CSMWorld::UniversalId> CSMWorld::CommandDispatcher::getExtendedTypes() const
{
std::vector<CSMWorld::UniversalId> tables;
if (mId==UniversalId::Type_Cells)
{
tables.push_back (mId);
tables.push_back (UniversalId::Type_References);
/// \todo add other cell-specific types
}
return tables;
}
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();
}
void CSMWorld::CommandDispatcher::executeExtendedDelete()
{
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Extended delete of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter)
{
if (*iter==mId)
executeDelete();
else if (*iter==UniversalId::Type_References)
{
IdTable& model = dynamic_cast<IdTable&> (
*mDocument.getData().getTableModel (*iter));
const RefCollection& collection = mDocument.getData().getReferences();
int size = collection.getSize();
for (int i=size-1; i>=0; --i)
{
const Record<CellRef>& record = collection.getRecord (i);
if (record.mState==RecordBase::State_Deleted)
continue;
if (!std::binary_search (mSelection.begin(), mSelection.end(),
Misc::StringUtils::lowerCase (record.get().mCell)))
continue;
mDocument.getUndoStack().push (
new CSMWorld::DeleteCommand (model, record.get().mId));
}
}
}
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
}
void CSMWorld::CommandDispatcher::executeExtendedRevert()
{
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().beginMacro (tr ("Extended revert of multiple records"));
for (std::vector<UniversalId>::const_iterator iter (mExtendedTypes.begin());
iter!=mExtendedTypes.end(); ++iter)
{
if (*iter==mId)
executeRevert();
else if (*iter==UniversalId::Type_References)
{
IdTable& model = dynamic_cast<IdTable&> (
*mDocument.getData().getTableModel (*iter));
const RefCollection& collection = mDocument.getData().getReferences();
int size = collection.getSize();
for (int i=size-1; i>=0; --i)
{
const Record<CellRef>& record = collection.getRecord (i);
if (!std::binary_search (mSelection.begin(), mSelection.end(),
Misc::StringUtils::lowerCase (record.get().mCell)))
continue;
mDocument.getUndoStack().push (
new CSMWorld::RevertCommand (model, record.get().mId));
}
}
}
if (mExtendedTypes.size()>1)
mDocument.getUndoStack().endMacro();
}

@ -0,0 +1,69 @@
#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<UniversalId> mExtendedTypes;
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);
void setExtendedTypes (const std::vector<UniversalId>& types);
///< Set record lists selected by the user for extended operations.
bool canDelete() const;
bool canRevert() const;
/// Return IDs of the record collection that can also be affected when
/// operating on the record collection this dispatcher is used for.
///
/// \note The returned collection contains the ID of the record collection this
/// dispatcher is used for. However if that record collection does not support
/// the extended mode, the returned vector will be empty instead.
std::vector<UniversalId> getExtendedTypes() const;
public slots:
void executeDelete();
void executeRevert();
void executeExtendedDelete();
void executeExtendedRevert();
};
}
#endif

@ -10,13 +10,12 @@ CSMWorld::ModifyCommand::ModifyCommand (QAbstractItemModel& model, const QModelI
const QVariant& new_, QUndoCommand* parent) const QVariant& new_, QUndoCommand* parent)
: QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_) : QUndoCommand (parent), mModel (model), mIndex (index), mNew (new_)
{ {
mOld = mModel.data (mIndex, Qt::EditRole);
setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString()); setText ("Modify " + mModel.headerData (mIndex.column(), Qt::Horizontal, Qt::DisplayRole).toString());
} }
void CSMWorld::ModifyCommand::redo() void CSMWorld::ModifyCommand::redo()
{ {
mOld = mModel.data (mIndex, Qt::EditRole);
mModel.setData (mIndex, mNew); mModel.setData (mIndex, mNew);
} }
@ -25,6 +24,13 @@ void CSMWorld::ModifyCommand::undo()
mModel.setData (mIndex, mOld); mModel.setData (mIndex, mOld);
} }
void CSMWorld::CreateCommand::applyModifications()
{
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter)
mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second);
}
CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent) CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
: QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None) : QUndoCommand (parent), mModel (model), mId (id), mType (UniversalId::Type_None)
{ {
@ -44,9 +50,7 @@ void CSMWorld::CreateCommand::setType (UniversalId::Type type)
void CSMWorld::CreateCommand::redo() void CSMWorld::CreateCommand::redo()
{ {
mModel.addRecord (mId, mType); mModel.addRecord (mId, mType);
applyModifications();
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter)
mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second);
} }
void CSMWorld::CreateCommand::undo() void CSMWorld::CreateCommand::undo()
@ -148,27 +152,22 @@ void CSMWorld::ReorderRowsCommand::undo()
CSMWorld::CloneCommand::CloneCommand (CSMWorld::IdTable& model, CSMWorld::CloneCommand::CloneCommand (CSMWorld::IdTable& model,
const std::string& idOrigin, const std::string& idOrigin,
const std::string& IdDestination, const std::string& idDestination,
const CSMWorld::UniversalId::Type type, const CSMWorld::UniversalId::Type type,
QUndoCommand* parent) : QUndoCommand* parent)
QUndoCommand (parent), : CreateCommand (model, idDestination, parent), mIdOrigin (idOrigin)
mModel (model),
mIdOrigin (idOrigin),
mIdDestination (Misc::StringUtils::lowerCase (IdDestination)),
mType (type)
{ {
setText ( ("Clone record " + idOrigin + " to the " + IdDestination).c_str()); setType (type);
setText ( ("Clone record " + idOrigin + " to the " + idDestination).c_str());
} }
void CSMWorld::CloneCommand::redo() void CSMWorld::CloneCommand::redo()
{ {
mModel.cloneRecord (mIdOrigin, mIdDestination, mType); mModel.cloneRecord (mIdOrigin, mId, mType);
applyModifications();
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter != mValues.end(); ++iter)
mModel.setData (mModel.getModelIndex (mIdDestination, iter->first), iter->second);
} }
void CSMWorld::CloneCommand::undo() void CSMWorld::CloneCommand::undo()
{ {
mModel.removeRow (mModel.getModelIndex (mIdDestination, 0).row()); mModel.removeRow (mModel.getModelIndex (mId, 0).row());
} }

@ -39,40 +39,44 @@ namespace CSMWorld
virtual void undo(); virtual void undo();
}; };
class CloneCommand : public QUndoCommand class CreateCommand : public QUndoCommand
{ {
std::map<int, QVariant> mValues;
protected:
IdTable& mModel; IdTable& mModel;
std::string mIdOrigin; std::string mId;
std::string mIdDestination;
UniversalId::Type mType; UniversalId::Type mType;
std::map<int, QVariant> mValues;
protected:
/// Apply modifications set via addValue.
void applyModifications();
public: public:
CloneCommand (IdTable& model, const std::string& idOrigin, CreateCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0);
const std::string& IdDestination,
const UniversalId::Type type, void setType (UniversalId::Type type);
QUndoCommand* parent = 0);
void addValue (int column, const QVariant& value);
virtual void redo(); virtual void redo();
virtual void undo(); virtual void undo();
}; };
class CreateCommand : public QUndoCommand class CloneCommand : public CreateCommand
{ {
IdTable& mModel; std::string mIdOrigin;
std::string mId;
UniversalId::Type mType;
std::map<int, QVariant> mValues;
public: public:
CreateCommand (IdTable& model, const std::string& id, QUndoCommand *parent = 0); CloneCommand (IdTable& model, const std::string& idOrigin,
const std::string& IdDestination,
void setType (UniversalId::Type type); const UniversalId::Type type,
QUndoCommand* parent = 0);
void addValue (int column, const QVariant& value);
virtual void redo(); virtual void redo();

@ -15,12 +15,15 @@
#include "columnimp.hpp" #include "columnimp.hpp"
#include "regionmap.hpp" #include "regionmap.hpp"
#include "columns.hpp" #include "columns.hpp"
#include "resourcesmanager.hpp"
#include "resourcetable.hpp"
void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type1, void CSMWorld::Data::addModel (QAbstractItemModel *model, UniversalId::Type type, bool update)
UniversalId::Type type2, bool update)
{ {
mModels.push_back (model); mModels.push_back (model);
mModelIndex.insert (std::make_pair (type1, model)); mModelIndex.insert (std::make_pair (type, model));
UniversalId::Type type2 = UniversalId::getParentType (type);
if (type2!=UniversalId::Type_None) if (type2!=UniversalId::Type_None)
mModelIndex.insert (std::make_pair (type2, model)); mModelIndex.insert (std::make_pair (type2, model));
@ -55,8 +58,9 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
return number; return number;
} }
CSMWorld::Data::Data (ToUTF8::FromType encoding) CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager)
: mEncoder (encoding), mRefs (mCells), mReader (0), mDialogue (0) : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0)
{ {
mGlobals.addColumn (new StringIdColumn<ESM::Global>); mGlobals.addColumn (new StringIdColumn<ESM::Global>);
mGlobals.addColumn (new RecordStateColumn<ESM::Global>); mGlobals.addColumn (new RecordStateColumn<ESM::Global>);
@ -67,7 +71,6 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>); mGmsts.addColumn (new StringIdColumn<ESM::GameSetting>);
mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>); mGmsts.addColumn (new RecordStateColumn<ESM::GameSetting>);
mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst)); mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst));
mGmsts.addColumn (new FixedRecordTypeColumn<ESM::GameSetting> (UniversalId::Type_Gmst));
mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting> (ColumnBase::Display_GmstVarType)); mGmsts.addColumn (new VarTypeColumn<ESM::GameSetting> (ColumnBase::Display_GmstVarType));
mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>); mGmsts.addColumn (new VarValueColumn<ESM::GameSetting>);
@ -101,7 +104,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mFactions.addColumn (new AttributesColumn<ESM::Faction> (0)); mFactions.addColumn (new AttributesColumn<ESM::Faction> (0));
mFactions.addColumn (new AttributesColumn<ESM::Faction> (1)); mFactions.addColumn (new AttributesColumn<ESM::Faction> (1));
mFactions.addColumn (new HiddenColumn<ESM::Faction>); mFactions.addColumn (new HiddenColumn<ESM::Faction>);
for (int i=0; i<6; ++i) for (int i=0; i<7; ++i)
mFactions.addColumn (new SkillsColumn<ESM::Faction> (i)); mFactions.addColumn (new SkillsColumn<ESM::Faction> (i));
mRaces.addColumn (new StringIdColumn<ESM::Race>); mRaces.addColumn (new StringIdColumn<ESM::Race>);
@ -127,7 +130,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mScripts.addColumn (new StringIdColumn<ESM::Script>); mScripts.addColumn (new StringIdColumn<ESM::Script>);
mScripts.addColumn (new RecordStateColumn<ESM::Script>); mScripts.addColumn (new RecordStateColumn<ESM::Script>);
mScripts.addColumn (new FixedRecordTypeColumn<ESM::Script> (UniversalId::Type_Script)); mScripts.addColumn (new FixedRecordTypeColumn<ESM::Script> (UniversalId::Type_Script));
mScripts.addColumn (new ScriptColumn<ESM::Script>); mScripts.addColumn (new ScriptColumn<ESM::Script> (ScriptColumn<ESM::Script>::Type_File));
mRegions.addColumn (new StringIdColumn<ESM::Region>); mRegions.addColumn (new StringIdColumn<ESM::Region>);
mRegions.addColumn (new RecordStateColumn<ESM::Region>); mRegions.addColumn (new RecordStateColumn<ESM::Region>);
@ -182,7 +185,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mJournalInfos.addColumn (new StringIdColumn<Info> (true)); mJournalInfos.addColumn (new StringIdColumn<Info> (true));
mJournalInfos.addColumn (new RecordStateColumn<Info>); mJournalInfos.addColumn (new RecordStateColumn<Info>);
mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_Journal)); mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_JournalInfo));
mJournalInfos.addColumn (new TopicColumn<Info> (true)); mJournalInfos.addColumn (new TopicColumn<Info> (true));
mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>); mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>);
mJournalInfos.addColumn (new QuestIndexColumn<Info>); mJournalInfos.addColumn (new QuestIndexColumn<Info>);
@ -196,6 +199,60 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater)); mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater));
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx)); mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx));
mCells.addColumn (new RegionColumn<Cell>); mCells.addColumn (new RegionColumn<Cell>);
mCells.addColumn (new RefNumCounterColumn<Cell>);
mEnchantments.addColumn (new StringIdColumn<ESM::Enchantment>);
mEnchantments.addColumn (new RecordStateColumn<ESM::Enchantment>);
mEnchantments.addColumn (new FixedRecordTypeColumn<ESM::Enchantment> (UniversalId::Type_Enchantment));
mEnchantments.addColumn (new EnchantmentTypeColumn<ESM::Enchantment>);
mEnchantments.addColumn (new CostColumn<ESM::Enchantment>);
mEnchantments.addColumn (new ChargesColumn2<ESM::Enchantment>);
mEnchantments.addColumn (new AutoCalcColumn<ESM::Enchantment>);
mBodyParts.addColumn (new StringIdColumn<ESM::BodyPart>);
mBodyParts.addColumn (new RecordStateColumn<ESM::BodyPart>);
mBodyParts.addColumn (new FixedRecordTypeColumn<ESM::BodyPart> (UniversalId::Type_BodyPart));
mBodyParts.addColumn (new BodyPartTypeColumn<ESM::BodyPart>);
mBodyParts.addColumn (new VampireColumn<ESM::BodyPart>);
mBodyParts.addColumn (new FlagColumn<ESM::BodyPart> (Columns::ColumnId_Female, ESM::BodyPart::BPF_Female));
mBodyParts.addColumn (new FlagColumn<ESM::BodyPart> (Columns::ColumnId_Playable, ESM::BodyPart::BPF_NotPlayable, true));
mBodyParts.addColumn (new MeshTypeColumn<ESM::BodyPart>);
mBodyParts.addColumn (new ModelColumn<ESM::BodyPart>);
mBodyParts.addColumn (new RaceColumn<ESM::BodyPart>);
mSoundGens.addColumn (new StringIdColumn<ESM::SoundGenerator>);
mSoundGens.addColumn (new RecordStateColumn<ESM::SoundGenerator>);
mSoundGens.addColumn (new FixedRecordTypeColumn<ESM::SoundGenerator> (UniversalId::Type_SoundGen));
mSoundGens.addColumn (new CreatureColumn<ESM::SoundGenerator>);
mSoundGens.addColumn (new SoundColumn<ESM::SoundGenerator>);
mSoundGens.addColumn (new SoundGeneratorTypeColumn<ESM::SoundGenerator>);
mMagicEffects.addColumn (new StringIdColumn<ESM::MagicEffect>);
mMagicEffects.addColumn (new RecordStateColumn<ESM::MagicEffect>);
mMagicEffects.addColumn (new FixedRecordTypeColumn<ESM::MagicEffect> (UniversalId::Type_MagicEffect));
mMagicEffects.addColumn (new SchoolColumn<ESM::MagicEffect>);
mMagicEffects.addColumn (new BaseCostColumn<ESM::MagicEffect>);
mMagicEffects.addColumn (new EffectTextureColumn<ESM::MagicEffect> (Columns::ColumnId_Icon));
mMagicEffects.addColumn (new EffectTextureColumn<ESM::MagicEffect> (Columns::ColumnId_Particle));
mMagicEffects.addColumn (new EffectObjectColumn<ESM::MagicEffect> (Columns::ColumnId_CastingObject));
mMagicEffects.addColumn (new EffectObjectColumn<ESM::MagicEffect> (Columns::ColumnId_HitObject));
mMagicEffects.addColumn (new EffectObjectColumn<ESM::MagicEffect> (Columns::ColumnId_AreaObject));
mMagicEffects.addColumn (new EffectObjectColumn<ESM::MagicEffect> (Columns::ColumnId_BoltObject));
mMagicEffects.addColumn (new EffectSoundColumn<ESM::MagicEffect> (Columns::ColumnId_CastingSound));
mMagicEffects.addColumn (new EffectSoundColumn<ESM::MagicEffect> (Columns::ColumnId_HitSound));
mMagicEffects.addColumn (new EffectSoundColumn<ESM::MagicEffect> (Columns::ColumnId_AreaSound));
mMagicEffects.addColumn (new EffectSoundColumn<ESM::MagicEffect> (Columns::ColumnId_BoltSound));
mMagicEffects.addColumn (new FlagColumn<ESM::MagicEffect> (
Columns::ColumnId_AllowSpellmaking, ESM::MagicEffect::AllowSpellmaking));
mMagicEffects.addColumn (new FlagColumn<ESM::MagicEffect> (
Columns::ColumnId_AllowEnchanting, ESM::MagicEffect::AllowEnchanting));
mMagicEffects.addColumn (new FlagColumn<ESM::MagicEffect> (
Columns::ColumnId_NegativeLight, ESM::MagicEffect::NegativeLight));
mMagicEffects.addColumn (new DescriptionColumn<ESM::MagicEffect>);
mPathgrids.addColumn (new StringIdColumn<Pathgrid>);
mPathgrids.addColumn (new RecordStateColumn<Pathgrid>);
mPathgrids.addColumn (new FixedRecordTypeColumn<Pathgrid> (UniversalId::Type_Pathgrid));
mRefs.addColumn (new StringIdColumn<CellRef> (true)); mRefs.addColumn (new StringIdColumn<CellRef> (true));
mRefs.addColumn (new RecordStateColumn<CellRef>); mRefs.addColumn (new RecordStateColumn<CellRef>);
@ -227,34 +284,66 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding)
mRefs.addColumn (new LockLevelColumn<CellRef>); mRefs.addColumn (new LockLevelColumn<CellRef>);
mRefs.addColumn (new KeyColumn<CellRef>); mRefs.addColumn (new KeyColumn<CellRef>);
mRefs.addColumn (new TrapColumn<CellRef>); mRefs.addColumn (new TrapColumn<CellRef>);
mRefs.addColumn (new OwnerGlobalColumn<CellRef>);
mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>); mRefs.addColumn (new RefNumColumn<CellRef>);
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>);
mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter)); mFilters.addColumn (new StringIdColumn<ESM::Filter>);
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>); mFilters.addColumn (new RecordStateColumn<ESM::Filter>);
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>); mFilters.addColumn (new FixedRecordTypeColumn<ESM::Filter> (UniversalId::Type_Filter));
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>); mFilters.addColumn (new FilterColumn<ESM::Filter>);
mFilters.addColumn (new DescriptionColumn<ESM::Filter>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst); mDebugProfiles.addColumn (new StringIdColumn<ESM::DebugProfile>);
addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill, false); mDebugProfiles.addColumn (new RecordStateColumn<ESM::DebugProfile>);
addModel (new IdTable (&mClasses), UniversalId::Type_Classes, UniversalId::Type_Class); mDebugProfiles.addColumn (new FixedRecordTypeColumn<ESM::DebugProfile> (UniversalId::Type_DebugProfile));
addModel (new IdTable (&mFactions), UniversalId::Type_Factions, UniversalId::Type_Faction); mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
addModel (new IdTable (&mRaces), UniversalId::Type_Races, UniversalId::Type_Race); Columns::ColumnId_DefaultProfile, ESM::DebugProfile::Flag_Default));
addModel (new IdTable (&mSounds), UniversalId::Type_Sounds, UniversalId::Type_Sound); mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script); Columns::ColumnId_BypassNewGame, ESM::DebugProfile::Flag_BypassNewGame));
addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region); mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign); Columns::ColumnId_GlobalProfile, ESM::DebugProfile::Flag_Global));
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell); mDebugProfiles.addColumn (new DescriptionColumn<ESM::DebugProfile>);
addModel (new IdTable (&mTopics), UniversalId::Type_Topics, UniversalId::Type_Topic); mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
addModel (new IdTable (&mJournals), UniversalId::Type_Journals, UniversalId::Type_Journal); ScriptColumn<ESM::DebugProfile>::Type_Lines));
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 (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mCells, IdTable::Reordering_None, IdTable::Viewing_Id), UniversalId::Type_Cells, UniversalId::Type_Cell); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mReferenceables, IdTable::Reordering_None, IdTable::Viewing_None, true), addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
UniversalId::Type_Referenceables, UniversalId::Type_Referenceable); addModel (new IdTable (&mClasses), UniversalId::Type_Class);
addModel (new IdTable (&mRefs, IdTable::Reordering_None, IdTable::Viewing_Cell, true), UniversalId::Type_References, UniversalId::Type_Reference, false); addModel (new IdTable (&mFactions), UniversalId::Type_Faction);
addModel (new IdTable (&mFilters), UniversalId::Type_Filters, UniversalId::Type_Filter, false); 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 (&mEnchantments), UniversalId::Type_Enchantment);
addModel (new IdTable (&mBodyParts), UniversalId::Type_BodyPart);
addModel (new IdTable (&mSoundGens), UniversalId::Type_SoundGen);
addModel (new IdTable (&mMagicEffects), UniversalId::Type_MagicEffect);
addModel (new IdTable (&mPathgrids), UniversalId::Type_Pathgrid);
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);
addModel (new IdTable (&mDebugProfiles), UniversalId::Type_DebugProfile);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Meshes)),
UniversalId::Type_Mesh);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Icons)),
UniversalId::Type_Icon);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Musics)),
UniversalId::Type_Music);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_SoundsRes)),
UniversalId::Type_SoundRes);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Textures)),
UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video);
} }
CSMWorld::Data::~Data() CSMWorld::Data::~Data()
@ -446,16 +535,91 @@ CSMWorld::RefCollection& CSMWorld::Data::getReferences()
return mRefs; return mRefs;
} }
const CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() const const CSMWorld::IdCollection<ESM::Filter>& CSMWorld::Data::getFilters() const
{ {
return mFilters; return mFilters;
} }
CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() CSMWorld::IdCollection<ESM::Filter>& CSMWorld::Data::getFilters()
{ {
return mFilters; return mFilters;
} }
const CSMWorld::IdCollection<ESM::Enchantment>& CSMWorld::Data::getEnchantments() const
{
return mEnchantments;
}
CSMWorld::IdCollection<ESM::Enchantment>& CSMWorld::Data::getEnchantments()
{
return mEnchantments;
}
const CSMWorld::IdCollection<ESM::BodyPart>& CSMWorld::Data::getBodyParts() const
{
return mBodyParts;
}
CSMWorld::IdCollection<ESM::BodyPart>& CSMWorld::Data::getBodyParts()
{
return mBodyParts;
}
const CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles() const
{
return mDebugProfiles;
}
CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles()
{
return mDebugProfiles;
}
const CSMWorld::IdCollection<CSMWorld::Land>& CSMWorld::Data::getLand() const
{
return mLand;
}
const CSMWorld::IdCollection<CSMWorld::LandTexture>& CSMWorld::Data::getLandTextures() const
{
return mLandTextures;
}
const CSMWorld::IdCollection<ESM::SoundGenerator>& CSMWorld::Data::getSoundGens() const
{
return mSoundGens;
}
CSMWorld::IdCollection<ESM::SoundGenerator>& CSMWorld::Data::getSoundGens()
{
return mSoundGens;
}
const CSMWorld::IdCollection<ESM::MagicEffect>& CSMWorld::Data::getMagicEffects() const
{
return mMagicEffects;
}
CSMWorld::IdCollection<ESM::MagicEffect>& CSMWorld::Data::getMagicEffects()
{
return mMagicEffects;
}
const CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& CSMWorld::Data::getPathgrids() const
{
return mPathgrids;
}
CSMWorld::SubCellCollection<CSMWorld::Pathgrid>& CSMWorld::Data::getPathgrids()
{
return mPathgrids;
}
const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const
{
return mResourcesManager.get (id.getType());
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id) QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
{ {
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType()); std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -469,8 +633,7 @@ QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId&
if (id.getType()==UniversalId::Type_RegionMap) if (id.getType()==UniversalId::Type_RegionMap)
{ {
RegionMap *table = 0; RegionMap *table = 0;
addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, addModel (table = new RegionMap (*this), UniversalId::Type_RegionMap, false);
UniversalId::Type_None, false);
return table; return table;
} }
throw std::logic_error ("No table model available for " + id.toString()); throw std::logic_error ("No table model available for " + id.toString());
@ -486,12 +649,17 @@ void CSMWorld::Data::merge()
int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base, bool project) int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base, bool project)
{ {
delete mReader; // Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading
boost::shared_ptr<ESM::ESMReader> ptr(mReader);
mReaders.push_back(ptr);
mReader = 0; mReader = 0;
mDialogue = 0; mDialogue = 0;
mRefLoadCache.clear();
mReader = new ESM::ESMReader; mReader = new ESM::ESMReader;
mReader->setEncoder (&mEncoder); mReader->setEncoder (&mEncoder);
mReader->setIndex(mReaderIndex++);
mReader->open (path.string()); mReader->open (path.string());
mBase = base; mBase = base;
@ -510,15 +678,21 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
if (!mReader->hasMoreRecs()) if (!mReader->hasMoreRecs())
{ {
delete mReader; // Don't delete the Reader yet. Some record types store a reference to the Reader to handle on-demand loading
boost::shared_ptr<ESM::ESMReader> ptr(mReader);
mReaders.push_back(ptr);
mReader = 0; mReader = 0;
mDialogue = 0; mDialogue = 0;
mRefLoadCache.clear();
return true; return true;
} }
ESM::NAME n = mReader->getRecName(); ESM::NAME n = mReader->getRecName();
mReader->getRecHeader(); mReader->getRecHeader();
bool unhandledRecord = false;
switch (n.val) switch (n.val)
{ {
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break; case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
@ -532,11 +706,22 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
case ESM::REC_REGN: mRegions.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_BSGN: mBirthsigns.load (*mReader, mBase); break;
case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break; case ESM::REC_SPEL: mSpells.load (*mReader, mBase); break;
case ESM::REC_ENCH: mEnchantments.load (*mReader, mBase); break;
case ESM::REC_BODY: mBodyParts.load (*mReader, mBase); break;
case ESM::REC_SNDG: mSoundGens.load (*mReader, mBase); break;
case ESM::REC_MGEF: mMagicEffects.load (*mReader, mBase); break;
case ESM::REC_PGRD: mPathgrids.load (*mReader, mBase); break;
case ESM::REC_LTEX: mLandTextures.load (*mReader, mBase); break;
case ESM::REC_LAND: mLand.load(*mReader, mBase); break;
case ESM::REC_CELL: case ESM::REC_CELL:
{
mCells.load (*mReader, mBase); mCells.load (*mReader, mBase);
mRefs.load (*mReader, mCells.getSize()-1, mBase); std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (mCells.getSize()-1));
mRefs.load (*mReader, mCells.getSize()-1, mBase, mRefLoadCache[cellId], messages);
break; break;
}
case ESM::REC_ACTI: mReferenceables.load (*mReader, mBase, UniversalId::Type_Activator); 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_ALCH: mReferenceables.load (*mReader, mBase, UniversalId::Type_Potion); break;
@ -624,23 +809,37 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
case ESM::REC_FILT: case ESM::REC_FILT:
if (mProject) if (!mProject)
{
unhandledRecord = true;
break;
}
mFilters.load (*mReader, mBase);
break;
case ESM::REC_DBGP:
if (!mProject)
{ {
mFilters.load (*mReader, mBase); unhandledRecord = true;
mFilters.setData (mFilters.getSize()-1,
mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
static_cast<int> (CSMFilter::Filter::Scope_Project));
break; break;
} }
// fall through (filter record in a content file is an error with format 0) mDebugProfiles.load (*mReader, mBase);
break;
default: default:
messages.push_back (std::make_pair (UniversalId::Type_None, unhandledRecord = true;
"Unsupported record type: " + n.toString())); }
if (unhandledRecord)
{
messages.push_back (std::make_pair (UniversalId::Type_None,
"Unsupported record type: " + n.toString()));
mReader->skipRecord(); mReader->skipRecord();
} }
return false; return false;
@ -663,6 +862,10 @@ bool CSMWorld::Data::hasId (const std::string& id) const
getTopics().searchId (id)!=-1 || getTopics().searchId (id)!=-1 ||
getJournals().searchId (id)!=-1 || getJournals().searchId (id)!=-1 ||
getCells().searchId (id)!=-1 || getCells().searchId (id)!=-1 ||
getEnchantments().searchId (id)!=-1 ||
getBodyParts().searchId (id)!=-1 ||
getSoundGens().searchId (id)!=-1 ||
getMagicEffects().searchId (id)!=-1 ||
getReferenceables().searchId (id)!=-1; getReferenceables().searchId (id)!=-1;
} }
@ -681,7 +884,14 @@ int CSMWorld::Data::count (RecordBase::State state) const
count (state, mBirthsigns) + count (state, mBirthsigns) +
count (state, mSpells) + count (state, mSpells) +
count (state, mCells) + count (state, mCells) +
count (state, mReferenceables); count (state, mEnchantments) +
count (state, mBodyParts) +
count (state, mLand) +
count (state, mLandTextures) +
count (state, mSoundGens) +
count (state, mMagicEffects) +
count (state, mReferenceables) +
count (state, mPathgrids);
} }
void CSMWorld::Data::setDescription (const std::string& description) void CSMWorld::Data::setDescription (const std::string& description)
@ -721,6 +931,10 @@ std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
appendIds (ids, mTopics, listDeleted); appendIds (ids, mTopics, listDeleted);
appendIds (ids, mJournals, listDeleted); appendIds (ids, mJournals, listDeleted);
appendIds (ids, mCells, listDeleted); appendIds (ids, mCells, listDeleted);
appendIds (ids, mEnchantments, listDeleted);
appendIds (ids, mBodyParts, listDeleted);
appendIds (ids, mSoundGens, listDeleted);
appendIds (ids, mMagicEffects, listDeleted);
appendIds (ids, mReferenceables, listDeleted); appendIds (ids, mReferenceables, listDeleted);
std::sort (ids.begin(), ids.end()); std::sort (ids.begin(), ids.end());
@ -737,4 +951,4 @@ void CSMWorld::Data::dataChanged (const QModelIndex& topLeft, const QModelIndex&
void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end) void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end)
{ {
emit idListChanged(); emit idListChanged();
} }

@ -21,19 +21,27 @@
#include <components/esm/loadbsgn.hpp> #include <components/esm/loadbsgn.hpp>
#include <components/esm/loadspel.hpp> #include <components/esm/loadspel.hpp>
#include <components/esm/loaddial.hpp> #include <components/esm/loaddial.hpp>
#include <components/esm/loadench.hpp>
#include <components/esm/loadbody.hpp>
#include <components/esm/loadsndg.hpp>
#include <components/esm/loadmgef.hpp>
#include <components/esm/debugprofile.hpp>
#include <components/esm/filter.hpp>
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
#include "../filter/filter.hpp"
#include "../doc/stage.hpp" #include "../doc/stage.hpp"
#include "idcollection.hpp" #include "idcollection.hpp"
#include "universalid.hpp" #include "universalid.hpp"
#include "cell.hpp" #include "cell.hpp"
#include "land.hpp"
#include "landtexture.hpp"
#include "refidcollection.hpp" #include "refidcollection.hpp"
#include "refcollection.hpp" #include "refcollection.hpp"
#include "infocollection.hpp" #include "infocollection.hpp"
#include "pathgrid.hpp"
#include "subcellcollection.hpp"
class QAbstractItemModel; class QAbstractItemModel;
@ -45,6 +53,9 @@ namespace ESM
namespace CSMWorld namespace CSMWorld
{ {
class ResourcesManager;
class Resources;
class Data : public QObject class Data : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -63,12 +74,21 @@ namespace CSMWorld
IdCollection<ESM::Spell> mSpells; IdCollection<ESM::Spell> mSpells;
IdCollection<ESM::Dialogue> mTopics; IdCollection<ESM::Dialogue> mTopics;
IdCollection<ESM::Dialogue> mJournals; IdCollection<ESM::Dialogue> mJournals;
IdCollection<ESM::Enchantment> mEnchantments;
IdCollection<ESM::BodyPart> mBodyParts;
IdCollection<ESM::MagicEffect> mMagicEffects;
SubCellCollection<Pathgrid> mPathgrids;
IdCollection<ESM::DebugProfile> mDebugProfiles;
IdCollection<ESM::SoundGenerator> mSoundGens;
InfoCollection mTopicInfos; InfoCollection mTopicInfos;
InfoCollection mJournalInfos; InfoCollection mJournalInfos;
IdCollection<Cell> mCells; IdCollection<Cell> mCells;
IdCollection<LandTexture> mLandTextures;
IdCollection<Land> mLand;
RefIdCollection mReferenceables; RefIdCollection mReferenceables;
RefCollection mRefs; RefCollection mRefs;
IdCollection<CSMFilter::Filter> mFilters; IdCollection<ESM::Filter> mFilters;
const ResourcesManager& mResourcesManager;
std::vector<QAbstractItemModel *> mModels; std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex; std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
std::string mAuthor; std::string mAuthor;
@ -77,13 +97,17 @@ namespace CSMWorld
const ESM::Dialogue *mDialogue; // last loaded dialogue const ESM::Dialogue *mDialogue; // last loaded dialogue
bool mBase; bool mBase;
bool mProject; bool mProject;
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
int mReaderIndex;
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
// not implemented // not implemented
Data (const Data&); Data (const Data&);
Data& operator= (const Data&); Data& operator= (const Data&);
void addModel (QAbstractItemModel *model, UniversalId::Type type1, void addModel (QAbstractItemModel *model, UniversalId::Type type,
UniversalId::Type type2 = UniversalId::Type_None, bool update = true); bool update = true);
static void appendIds (std::vector<std::string>& ids, const CollectionBase& collection, static void appendIds (std::vector<std::string>& ids, const CollectionBase& collection,
bool listDeleted); bool listDeleted);
@ -93,7 +117,7 @@ namespace CSMWorld
public: public:
Data (ToUTF8::FromType encoding); Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager);
virtual ~Data(); virtual ~Data();
@ -169,9 +193,40 @@ namespace CSMWorld
RefCollection& getReferences(); RefCollection& getReferences();
const IdCollection<CSMFilter::Filter>& getFilters() const; const IdCollection<ESM::Filter>& getFilters() const;
IdCollection<ESM::Filter>& getFilters();
const IdCollection<ESM::Enchantment>& getEnchantments() const;
IdCollection<ESM::Enchantment>& getEnchantments();
const IdCollection<ESM::BodyPart>& getBodyParts() const;
IdCollection<ESM::BodyPart>& getBodyParts();
const IdCollection<ESM::DebugProfile>& getDebugProfiles() const;
IdCollection<ESM::DebugProfile>& getDebugProfiles();
const IdCollection<CSMWorld::Land>& getLand() const;
const IdCollection<CSMWorld::LandTexture>& getLandTextures() const;
const IdCollection<ESM::SoundGenerator>& getSoundGens() const;
IdCollection<ESM::SoundGenerator>& getSoundGens();
const IdCollection<ESM::MagicEffect>& getMagicEffects() const;
IdCollection<ESM::MagicEffect>& getMagicEffects();
const SubCellCollection<Pathgrid>& getPathgrids() const;
SubCellCollection<Pathgrid>& getPathgrids();
IdCollection<CSMFilter::Filter>& getFilters(); /// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const;
QAbstractItemModel *getTableModel (const UniversalId& id); QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown. ///< If no table model is available for \a id, an exception is thrown.
@ -222,4 +277,4 @@ namespace CSMWorld
}; };
} }
#endif #endif

@ -11,11 +11,16 @@ namespace CSMWorld
template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> > template<typename ESXRecordT, typename IdAccessorT = IdAccessor<ESXRecordT> >
class IdCollection : public Collection<ESXRecordT, IdAccessorT> class IdCollection : public Collection<ESXRecordT, IdAccessorT>
{ {
virtual void loadRecord (ESXRecordT& record, ESM::ESMReader& reader);
public: public:
void load (ESM::ESMReader& reader, bool base); void load (ESM::ESMReader& reader, bool base);
void load (const ESXRecordT& record, bool base); /// \param index Index at which the record can be found.
/// Special values: -2 index unknown, -1 record does not exist yet and therefore
/// does not have an index
void load (const ESXRecordT& record, bool base, int index = -2);
bool tryDelete (const std::string& id); bool tryDelete (const std::string& id);
///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored. ///< Try deleting \a id. If the id does not exist or can't be deleted the call is ignored.
@ -23,6 +28,13 @@ namespace CSMWorld
/// \return Has the ID been deleted? /// \return Has the ID been deleted?
}; };
template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::loadRecord (ESXRecordT& record,
ESM::ESMReader& reader)
{
record.load (reader);
}
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base) void IdCollection<ESXRecordT, IdAccessorT>::load (ESM::ESMReader& reader, bool base)
{ {
@ -56,17 +68,36 @@ namespace CSMWorld
else else
{ {
ESXRecordT record; ESXRecordT record;
IdAccessorT().getId (record) = id;
record.load (reader);
load (record, base); int index = this->searchId (id);
if (index==-1)
IdAccessorT().getId (record) = id;
else
{
record = this->getRecord (index).get();
}
loadRecord (record, reader);
if (index==-1)
{
std::string newId = IdAccessorT().getId(record);
int newIndex = this->searchId(newId);
if (newIndex != -1 && id != newId)
index = newIndex;
}
load (record, base, index);
} }
} }
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>
void IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base) void IdCollection<ESXRecordT, IdAccessorT>::load (const ESXRecordT& record, bool base,
int index)
{ {
int index = this->searchId (IdAccessorT().getId (record)); if (index==-2)
index = this->searchId (IdAccessorT().getId (record));
if (index==-1) if (index==-1)
{ {

@ -4,9 +4,8 @@
#include "collectionbase.hpp" #include "collectionbase.hpp"
#include "columnbase.hpp" #include "columnbase.hpp"
CSMWorld::IdTable::IdTable (CollectionBase *idCollection, Reordering reordering, CSMWorld::IdTable::IdTable (CollectionBase *idCollection, unsigned int features)
Viewing viewing, bool preview) : IdTableBase (features), mIdCollection (idCollection)
: mIdCollection (idCollection), mReordering (reordering), mViewing (viewing), mPreview (preview)
{} {}
CSMWorld::IdTable::~IdTable() CSMWorld::IdTable::~IdTable()
@ -30,7 +29,7 @@ int CSMWorld::IdTable::columnCount (const QModelIndex & parent) const
QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
{ {
if (role!=Qt::DisplayRole && role!=Qt::EditRole) if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0)
return QVariant(); return QVariant();
if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable()) if (role==Qt::EditRole && !mIdCollection->getColumn (index.column()).isEditable())
@ -186,27 +185,12 @@ void CSMWorld::IdTable::reorderRows (int baseIndex, const std::vector<int>& newO
index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1)); index (baseIndex+newOrder.size()-1, mIdCollection->getColumns()-1));
} }
CSMWorld::IdTable::Reordering CSMWorld::IdTable::getReordering() const
{
return mReordering;
}
CSMWorld::IdTable::Viewing CSMWorld::IdTable::getViewing() const
{
return mViewing;
}
bool CSMWorld::IdTable::hasPreview() const
{
return mPreview;
}
std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row) const
{ {
std::string id; std::string id;
std::string hint; std::string hint;
if (mViewing==Viewing_Cell) if (getFeatures() & Feature_ViewCell)
{ {
int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell); int cellColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Cell);
int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id); int idColumn = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
@ -217,7 +201,7 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData()); hint = "r:" + std::string (mIdCollection->getData (row, idColumn).toString().toUtf8().constData());
} }
} }
else if (mViewing==Viewing_Id) else if (getFeatures() & Feature_ViewId)
{ {
int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id); int column = mIdCollection->searchColumnIndex (Columns::ColumnId_Id);
@ -237,7 +221,12 @@ std::pair<CSMWorld::UniversalId, std::string> CSMWorld::IdTable::view (int row)
return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint); return std::make_pair (UniversalId (UniversalId::Type_Scene, id), hint);
} }
bool CSMWorld::IdTable::isDeleted (const std::string& id) const
{
return getRecord (id).isDeleted();
}
int CSMWorld::IdTable::getColumnId(int column) const int CSMWorld::IdTable::getColumnId(int column) const
{ {
return mIdCollection->getColumn(column).getId(); return mIdCollection->getColumn(column).getId();
} }

@ -3,8 +3,7 @@
#include <vector> #include <vector>
#include <QAbstractItemModel> #include "idtablebase.hpp"
#include "universalid.hpp" #include "universalid.hpp"
#include "columns.hpp" #include "columns.hpp"
@ -13,33 +12,13 @@ namespace CSMWorld
class CollectionBase; class CollectionBase;
class RecordBase; class RecordBase;
class IdTable : public QAbstractItemModel class IdTable : public IdTableBase
{ {
Q_OBJECT Q_OBJECT
public:
enum Reordering
{
Reordering_None,
Reordering_WithinTopic
};
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)
};
private: private:
CollectionBase *mIdCollection; CollectionBase *mIdCollection;
Reordering mReordering;
Viewing mViewing;
bool mPreview;
// not implemented // not implemented
IdTable (const IdTable&); IdTable (const IdTable&);
@ -47,8 +26,7 @@ namespace CSMWorld
public: public:
IdTable (CollectionBase *idCollection, Reordering reordering = Reordering_None, IdTable (CollectionBase *idCollection, unsigned int features = 0);
Viewing viewing = Viewing_None, bool preview = false);
///< The ownership of \a idCollection is not transferred. ///< The ownership of \a idCollection is not transferred.
virtual ~IdTable(); virtual ~IdTable();
@ -79,17 +57,17 @@ namespace CSMWorld
const std::string& destination, const std::string& destination,
UniversalId::Type type = UniversalId::Type_None); UniversalId::Type type = UniversalId::Type_None);
QModelIndex getModelIndex (const std::string& id, int column) const; virtual QModelIndex getModelIndex (const std::string& id, int column) const;
void setRecord (const std::string& id, const RecordBase& record); void setRecord (const std::string& id, const RecordBase& record);
///< Add record or overwrite existing recrod. ///< Add record or overwrite existing recrod.
const RecordBase& getRecord (const std::string& id) const; const RecordBase& getRecord (const std::string& id) const;
int searchColumnIndex (Columns::ColumnId id) const; virtual int searchColumnIndex (Columns::ColumnId id) const;
///< Return index of column with the given \a id. If no such column exists, -1 is returned. ///< Return index of column with the given \a id. If no such column exists, -1 is returned.
int findColumnIndex (Columns::ColumnId id) const; virtual int findColumnIndex (Columns::ColumnId id) const;
///< Return index of column with the given \a id. If no such column exists, an exception is ///< Return index of column with the given \a id. If no such column exists, an exception is
/// thrown. /// thrown.
@ -97,16 +75,13 @@ namespace CSMWorld
///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices ///< Reorder the rows [baseIndex, baseIndex+newOrder.size()) according to the indices
/// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex). /// given in \a newOrder (baseIndex+newOrder[0] specifies the new index of row baseIndex).
Reordering getReordering() const; virtual std::pair<UniversalId, std::string> view (int row) const;
Viewing getViewing() const;
bool hasPreview() const;
std::pair<UniversalId, std::string> view (int row) const;
///< Return the UniversalId and the hint for viewing \a row. If viewing is not ///< Return the UniversalId and the hint for viewing \a row. If viewing is not
/// supported by this table, return (UniversalId::Type_None, ""). /// supported by this table, return (UniversalId::Type_None, "").
/// Is \a id flagged as deleted?
virtual bool isDeleted (const std::string& id) const;
int getColumnId(int column) const; int getColumnId(int column) const;
}; };
} }

@ -0,0 +1,9 @@
#include "idtablebase.hpp"
CSMWorld::IdTableBase::IdTableBase (unsigned int features) : mFeatures (features) {}
unsigned int CSMWorld::IdTableBase::getFeatures() const
{
return mFeatures;
}

@ -0,0 +1,67 @@
#ifndef CSM_WOLRD_IDTABLEBASE_H
#define CSM_WOLRD_IDTABLEBASE_H
#include <QAbstractItemModel>
#include "columns.hpp"
namespace CSMWorld
{
class UniversalId;
class IdTableBase : public QAbstractItemModel
{
Q_OBJECT
public:
enum Features
{
Feature_ReorderWithinTopic = 1,
/// 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,
/// Table can not be modified through ordinary means.
Feature_Constant = 16
};
private:
unsigned int mFeatures;
public:
IdTableBase (unsigned int features);
virtual QModelIndex getModelIndex (const std::string& id, int column) const = 0;
/// Return index of column with the given \a id. If no such column exists, -1 is
/// returned.
virtual int searchColumnIndex (Columns::ColumnId id) const = 0;
/// Return index of column with the given \a id. If no such column exists, an
/// exception is thrown.
virtual int findColumnIndex (Columns::ColumnId id) const = 0;
/// Return the UniversalId and the hint for viewing \a row. If viewing is not
/// supported by this table, return (UniversalId::Type_None, "").
virtual std::pair<UniversalId, std::string> view (int row) const = 0;
/// Is \a id flagged as deleted?
virtual bool isDeleted (const std::string& id) const = 0;
unsigned int getFeatures() const;
};
}
#endif

@ -3,7 +3,7 @@
#include <vector> #include <vector>
#include "idtable.hpp" #include "idtablebase.hpp"
void CSMWorld::IdTableProxyModel::updateColumnMap() void CSMWorld::IdTableProxyModel::updateColumnMap()
{ {
@ -13,7 +13,7 @@ void CSMWorld::IdTableProxyModel::updateColumnMap()
{ {
std::vector<int> columns = mFilter->getReferencedColumns(); std::vector<int> columns = mFilter->getReferencedColumns();
const IdTable& table = dynamic_cast<const IdTable&> (*sourceModel()); const IdTableBase& table = dynamic_cast<const IdTableBase&> (*sourceModel());
for (std::vector<int>::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter) for (std::vector<int>::const_iterator iter (columns.begin()); iter!=columns.end(); ++iter)
mColumnMap.insert (std::make_pair (*iter, mColumnMap.insert (std::make_pair (*iter,
@ -28,7 +28,7 @@ bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelI
return true; return true;
return mFilter->test ( return mFilter->test (
dynamic_cast<IdTable&> (*sourceModel()), sourceRow, mColumnMap); dynamic_cast<IdTableBase&> (*sourceModel()), sourceRow, mColumnMap);
} }
CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent) CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
@ -39,7 +39,7 @@ CSMWorld::IdTableProxyModel::IdTableProxyModel (QObject *parent)
QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, int column) const
{ {
return mapFromSource (dynamic_cast<IdTable&> (*sourceModel()).getModelIndex (id, column)); return mapFromSource (dynamic_cast<IdTableBase&> (*sourceModel()).getModelIndex (id, column));
} }
void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter) void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter)
@ -47,4 +47,9 @@ void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::
mFilter = filter; mFilter = filter;
updateColumnMap(); updateColumnMap();
invalidateFilter(); invalidateFilter();
} }
bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
return QSortFilterProxyModel::lessThan(left, right);
}

@ -33,7 +33,11 @@ namespace CSMWorld
virtual QModelIndex getModelIndex (const std::string& id, int column) const; virtual QModelIndex getModelIndex (const std::string& id, int column) const;
void setFilter (const boost::shared_ptr<CSMFilter::Node>& filter); void setFilter (const boost::shared_ptr<CSMFilter::Node>& filter);
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
}; };
} }
#endif #endif

@ -0,0 +1,28 @@
#include "land.hpp"
#include <sstream>
namespace CSMWorld
{
Land::Land()
{
mLand.reset(new ESM::Land());
}
void Land::load(ESM::ESMReader &esm)
{
mLand->load(esm);
std::ostringstream stream;
stream << "#" << mLand->mX << " " << mLand->mY;
mId = stream.str();
}
void Land::blank()
{
/// \todo
}
}

@ -0,0 +1,29 @@
#ifndef CSM_WORLD_LAND_H
#define CSM_WORLD_LAND_H
#include <string>
#include <boost/shared_ptr.hpp>
#include <components/esm/loadland.hpp>
namespace CSMWorld
{
/// \brief Wrapper for Land record. Encodes X and Y cell index in the ID.
///
/// \todo Add worldspace support to the Land record.
/// \todo Add a proper copy constructor (currently worked around using shared_ptr)
struct Land
{
Land();
boost::shared_ptr<ESM::Land> mLand;
std::string mId;
/// Loads the metadata and ID
void load (ESM::ESMReader &esm);
void blank();
};
}
#endif

@ -0,0 +1,21 @@
#include "landtexture.hpp"
#include <components/esm/esmreader.hpp>
namespace CSMWorld
{
void LandTexture::load(ESM::ESMReader &esm)
{
ESM::LandTexture::load(esm);
int plugin = esm.getIndex();
std::ostringstream stream;
stream << mIndex << "_" << plugin;
mId = stream.str();
}
}

@ -0,0 +1,22 @@
#ifndef CSM_WORLD_LANDTEXTURE_H
#define CSM_WORLD_LANDTEXTURE_H
#include <string>
#include <components/esm/loadltex.hpp>
namespace CSMWorld
{
/// \brief Wrapper for LandTexture record. Encodes mIndex and the plugin index (obtained from ESMReader)
/// in the ID.
///
/// \attention The mId field of the ESM::LandTexture struct is not used.
struct LandTexture : public ESM::LandTexture
{
std::string mId;
void load (ESM::ESMReader &esm);
};
}
#endif

@ -0,0 +1,35 @@
#include "pathgrid.hpp"
#include <sstream>
void CSMWorld::Pathgrid::load (ESM::ESMReader &esm, const IdCollection<Cell>& cells)
{
load (esm);
// correct ID
if (!mId.empty() && mId[0]!='#' && cells.searchId (mId)==-1)
{
std::ostringstream stream;
stream << "#" << mData.mX << " " << mData.mY;
mId = stream.str();
}
}
void CSMWorld::Pathgrid::load (ESM::ESMReader &esm)
{
ESM::Pathgrid::load (esm);
if (mCell.empty())
{
std::ostringstream stream;
stream << "#" << mData.mX << " " << mData.mY;
mId = stream.str();
}
else
mId = mCell;
}

@ -0,0 +1,28 @@
#ifndef CSM_WOLRD_PATHGRID_H
#define CSM_WOLRD_PATHGRID_H
#include <vector>
#include <string>
#include <components/esm/loadpgrd.hpp>
#include "idcollection.hpp"
#include "cell.hpp"
namespace CSMWorld
{
/// \brief Wrapper for Pathgrid record
///
/// \attention The mData.mX and mData.mY fields of the ESM::Pathgrid struct are not used.
/// Exterior cell coordinates are encoded in the pathgrid ID.
struct Pathgrid : public ESM::Pathgrid
{
std::string mId;
void load (ESM::ESMReader &esm, const IdCollection<Cell>& cells);
void load (ESM::ESMReader &esm);
};
}
#endif

@ -1,12 +1,8 @@
#include "ref.hpp" #include "ref.hpp"
#include "cell.hpp" CSMWorld::CellRef::CellRef()
void CSMWorld::CellRef::load (ESM::ESMReader &esm, Cell& cell, const std::string& id)
{ {
mId = id; mRefNum.mIndex = 0;
mCell = cell.mId; mRefNum.mContentFile = 0;
cell.addRef (mId);
} }

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

@ -3,12 +3,15 @@
#include <sstream> #include <sstream>
#include <components/misc/stringops.hpp>
#include "ref.hpp" #include "ref.hpp"
#include "cell.hpp" #include "cell.hpp"
#include "universalid.hpp" #include "universalid.hpp"
#include "record.hpp" #include "record.hpp"
void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base) void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool base,
std::map<ESM::RefNum, std::string>& cache, CSMDoc::Stage::Messages& messages)
{ {
Record<Cell> cell = mCells.getRecord (cellIndex); Record<Cell> cell = mCells.getRecord (cellIndex);
@ -17,19 +20,73 @@ void CSMWorld::RefCollection::load (ESM::ESMReader& reader, int cellIndex, bool
CellRef ref; CellRef ref;
bool deleted = false; bool deleted = false;
while (cell2.getNextRef (reader, ref, deleted))
while (ESM::Cell::getNextRef (reader, ref, deleted))
{ {
/// \todo handle deleted and moved references ref.mCell = cell2.mId;
ref.load (reader, cell2, getNewId());
Record<CellRef> record2; /// \todo handle moved references
record2.mState = base ? RecordBase::State_BaseOnly : RecordBase::State_ModifiedOnly;
(base ? record2.mBase : record2.mModified) = ref;
appendRecord (record2); std::map<ESM::RefNum, std::string>::iterator iter = cache.find (ref.mRefNum);
}
if (deleted)
{
if (iter==cache.end())
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Cell,
mCells.getId (cellIndex));
messages.push_back (std::make_pair (id,
"Attempt to delete a non-existing reference"));
continue;
}
int index = getIndex (iter->second);
Record<CellRef> record = getRecord (index);
if (record.mState==RecordBase::State_BaseOnly)
{
removeRows (index, 1);
cache.erase (iter);
}
else
{
record.mState = RecordBase::State_Deleted;
setRecord (index, record);
}
mCells.setRecord (cellIndex, cell); 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);
}
}
} }
std::string CSMWorld::RefCollection::getNewId() std::string CSMWorld::RefCollection::getNewId()

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

@ -248,6 +248,15 @@ QVariant CSMWorld::CreatureRefIdAdapter::getData (const RefIdColumn *column, con
if (column==mColumns.mOriginal) if (column==mColumns.mOriginal)
return QString::fromUtf8 (record.get().mOriginal.c_str()); return QString::fromUtf8 (record.get().mOriginal.c_str());
if (column==mColumns.mCombat)
return static_cast<int> (record.get().mData.mCombat);
if (column==mColumns.mMagic)
return static_cast<int> (record.get().mData.mMagic);
if (column==mColumns.mStealth)
return static_cast<int> (record.get().mData.mStealth);
std::map<const RefIdColumn *, unsigned int>::const_iterator iter = std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
mColumns.mFlags.find (column); mColumns.mFlags.find (column);
@ -271,6 +280,12 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
record.get().mScale = value.toFloat(); record.get().mScale = value.toFloat();
else if (column==mColumns.mOriginal) else if (column==mColumns.mOriginal)
record.get().mOriginal = value.toString().toUtf8().constData(); record.get().mOriginal = value.toString().toUtf8().constData();
else if (column==mColumns.mCombat)
record.get().mData.mCombat = value.toInt();
else if (column==mColumns.mMagic)
record.get().mData.mMagic = value.toInt();
else if (column==mColumns.mStealth)
record.get().mData.mStealth = value.toInt();
else else
{ {
std::map<const RefIdColumn *, unsigned int>::const_iterator iter = std::map<const RefIdColumn *, unsigned int>::const_iterator iter =

@ -34,7 +34,7 @@ namespace CSMWorld
BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base); BaseRefIdAdapter (UniversalId::Type type, const BaseColumns& base);
virtual std::string getId (const RecordBase& record) const; virtual std::string getId (const RecordBase& record) const;
virtual void setId (RecordBase& record, const std::string& id); virtual void setId (RecordBase& record, const std::string& id);
virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index) virtual QVariant getData (const RefIdColumn *column, const RefIdData& data, int index)
@ -57,7 +57,7 @@ namespace CSMWorld
{ {
(dynamic_cast<Record<RecordT>&> (record).get().mId) = id; (dynamic_cast<Record<RecordT>&> (record).get().mId) = id;
} }
template<typename RecordT> template<typename RecordT>
std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const std::string BaseRefIdAdapter<RecordT>::getId (const RecordBase& record) const
{ {
@ -631,6 +631,9 @@ namespace CSMWorld
const RefIdColumn *mSoul; const RefIdColumn *mSoul;
const RefIdColumn *mScale; const RefIdColumn *mScale;
const RefIdColumn *mOriginal; const RefIdColumn *mOriginal;
const RefIdColumn *mCombat;
const RefIdColumn *mMagic;
const RefIdColumn *mStealth;
CreatureColumns (const ActorColumns& actorColumns); CreatureColumns (const ActorColumns& actorColumns);
}; };

@ -44,7 +44,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
baseColumns.mId = &mColumns.back(); baseColumns.mId = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState, mColumns.push_back (RefIdColumn (Columns::ColumnId_Modification, ColumnBase::Display_RecordState,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, true, false));
baseColumns.mModified = &mColumns.back(); baseColumns.mModified = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType, mColumns.push_back (RefIdColumn (Columns::ColumnId_RecordType, ColumnBase::Display_RefRecordType,
ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false)); ColumnBase::Flag_Table | ColumnBase::Flag_Dialogue, false, false));
@ -52,7 +52,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
ModelColumns modelColumns (baseColumns); ModelColumns modelColumns (baseColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Model, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Model, ColumnBase::Display_Mesh));
modelColumns.mModel = &mColumns.back(); modelColumns.mModel = &mColumns.back();
NameColumns nameColumns (modelColumns); NameColumns nameColumns (modelColumns);
@ -64,7 +64,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
InventoryColumns inventoryColumns (nameColumns); InventoryColumns inventoryColumns (nameColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Icon, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Icon, ColumnBase::Display_Icon));
inventoryColumns.mIcon = &mColumns.back(); inventoryColumns.mIcon = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Weight, ColumnBase::Display_Float)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Weight, ColumnBase::Display_Float));
inventoryColumns.mWeight = &mColumns.back(); inventoryColumns.mWeight = &mColumns.back();
@ -175,6 +175,15 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mScale = &mColumns.back(); creatureColumns.mScale = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_OriginalCreature, ColumnBase::Display_String));
creatureColumns.mOriginal = &mColumns.back(); creatureColumns.mOriginal = &mColumns.back();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer));
creatureColumns.mCombat = &mColumns.back();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_MagicState, ColumnBase::Display_Integer));
creatureColumns.mMagic = &mColumns.back();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_StealthState, ColumnBase::Display_Integer));
creatureColumns.mStealth = &mColumns.back();
static const struct static const struct
{ {
@ -304,10 +313,17 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponReach, ColumnBase::Display_Float)); mColumns.push_back (RefIdColumn (Columns::ColumnId_WeaponReach, ColumnBase::Display_Float));
weaponColumns.mReach = &mColumns.back(); weaponColumns.mReach = &mColumns.back();
for (int i=0; i<6; ++i) for (int i=0; i<3; ++i)
{ {
mColumns.push_back (RefIdColumn (Columns::ColumnId_MinChop + i, ColumnBase::Display_Integer)); const RefIdColumn **column =
weaponColumns.mChop[i] = &mColumns.back(); i==0 ? weaponColumns.mChop : (i==1 ? weaponColumns.mSlash : weaponColumns.mThrust);
for (int j=0; j<2; ++j)
{
mColumns.push_back (
RefIdColumn (Columns::ColumnId_MinChop+i*2+j, ColumnBase::Display_Integer));
column[j] = &mColumns.back();
}
} }
static const struct static const struct

@ -0,0 +1,103 @@
#include "resources.hpp"
#include <sstream>
#include <stdexcept>
#include <OgreResourceGroupManager.h>
#include <components/misc/stringops.hpp>
CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::Type type,
const char * const *extensions)
: mBaseDirectory (baseDirectory), mType (type)
{
int baseSize = mBaseDirectory.size();
Ogre::StringVector resourcesGroups =
Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
for (Ogre::StringVector::iterator iter (resourcesGroups.begin());
iter!=resourcesGroups.end(); ++iter)
{
if (*iter=="General" || *iter=="Internal" || *iter=="Autodetect")
continue;
Ogre::StringVectorPtr resources =
Ogre::ResourceGroupManager::getSingleton().listResourceNames (*iter);
for (Ogre::StringVector::const_iterator iter (resources->begin());
iter!=resources->end(); ++iter)
{
if (static_cast<int> (iter->size())<baseSize+1 ||
iter->substr (0, baseSize)!=mBaseDirectory ||
((*iter)[baseSize]!='/' && (*iter)[baseSize]!='\\'))
continue;
if (extensions)
{
std::string::size_type index = iter->find_last_of ('.');
if (index==std::string::npos)
continue;
std::string extension = iter->substr (index+1);
int i = 0;
for (; extensions[i]; ++i)
if (extensions[i]==extension)
break;
if (!extensions[i])
continue;
}
std::string file = iter->substr (baseSize+1);
mFiles.push_back (file);
mIndex.insert (std::make_pair (file, static_cast<int> (mFiles.size())-1));
}
}
}
int CSMWorld::Resources::getSize() const
{
return mFiles.size();
}
std::string CSMWorld::Resources::getId (int index) const
{
return mFiles.at (index);
}
int CSMWorld::Resources::getIndex (const std::string& id) const
{
int index = searchId (id);
if (index==-1)
{
std::ostringstream stream;
stream << "Invalid resource: " << mBaseDirectory << '/' << id;
throw std::runtime_error (stream.str().c_str());
}
return index;
}
int CSMWorld::Resources::searchId (const std::string& id) const
{
std::string id2 = Misc::StringUtils::lowerCase (id);
std::map<std::string, int>::const_iterator iter = mIndex.find (id2);
if (iter==mIndex.end())
return -1;
return iter->second;
}
CSMWorld::UniversalId::Type CSMWorld::Resources::getType() const
{
return mType;
}

@ -0,0 +1,37 @@
#ifndef CSM_WOLRD_RESOURCES_H
#define CSM_WOLRD_RESOURCES_H
#include <string>
#include <map>
#include <vector>
#include "universalid.hpp"
namespace CSMWorld
{
class Resources
{
std::map<std::string, int> mIndex;
std::vector<std::string> mFiles;
std::string mBaseDirectory;
UniversalId::Type mType;
public:
/// \param type Type of resources in this table.
Resources (const std::string& baseDirectory, UniversalId::Type type,
const char * const *extensions = 0);
int getSize() const;
std::string getId (int index) const;
int getIndex (const std::string& id) const;
int searchId (const std::string& id) const;
UniversalId::Type getType() const;
};
}
#endif

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

Loading…
Cancel
Save