Merge branch 'master' of git://github.com/OpenMW/openmw into appveyor

coverity_scan
Alexander "Ace" Olofsson 10 years ago
commit 4319255d7b

@ -1,6 +1,6 @@
os: os:
- linux - linux
- osx # - osx
language: cpp language: cpp
branches: branches:
only: only:
@ -38,7 +38,7 @@ before_script:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi - if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
script: script:
- cd ./build - cd ./build
- if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j4; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi
- if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi
after_script: after_script:
- if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi

@ -12,9 +12,10 @@ echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_
echo "yes" | sudo apt-add-repository ppa:openmw/openmw echo "yes" | sudo apt-add-repository ppa:openmw/openmw
sudo apt-get update -qq sudo apt-get update -qq
sudo apt-get install -qq libgtest-dev google-mock 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 libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev
sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-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 apt-get install -qq libbullet-dev libopenscenegraph-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
sudo apt-get install -qq cmake-data #workaround for broken osgqt cmake script in ubuntu 12.04
if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi if [ "${ANALYZE}" ]; then sudo apt-get install -qq clang-3.6; fi
sudo mkdir /usr/src/gtest/build sudo mkdir /usr/src/gtest/build
cd /usr/src/gtest/build cd /usr/src/gtest/build

@ -54,15 +54,13 @@ endif (ANDROID)
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_BINARY_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(BOOST_STATIC "Link static build of Boost into the binaries" FALSE) option(BOOST_STATIC "Link static build of Boost into the binaries" FALSE)
option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE) option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
set(CUSTOM_OGRE_PLUGIN_DIR "" CACHE PATH "Specify a custom directory for Ogre plugins (autodetected by default)")
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_OPENMW "build OpenMW" ON)
option(BUILD_BSATOOL "build BSA extractor" ON) 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)
@ -72,12 +70,16 @@ 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" OFF) option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest" OFF)
option(BUILD_NIFTEST "build nif file tester" OFF)
option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON) option(BUILD_MYGUI_PLUGIN "build MyGUI plugin for OpenMW resources, to use with MyGUI tools" ON)
# OS X deployment # OS X deployment
option(OPENMW_OSX_DEPLOYMENT OFF) option(OPENMW_OSX_DEPLOYMENT OFF)
if (MSVC)
option(OPENMW_MP_BUILD "Build OpenMW with /MP flag" OFF)
option(OPENMW_LTO_BUILD "Build OpenMW with Link-Time Optimization (Needs ~2GB of RAM)" OFF)
endif()
# 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")
@ -98,24 +100,30 @@ endif()
cmake_minimum_required(VERSION 2.6) cmake_minimum_required(VERSION 2.6)
# Sound setup # Sound setup
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
unset(FFMPEG_LIBRARIES CACHE) unset(FFMPEG_LIBRARIES CACHE)
find_package(FFmpeg)
find_package(FFmpeg REQUIRED)
set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARY})
if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND ) if ( NOT AVCODEC_FOUND OR NOT AVFORMAT_FOUND OR NOT AVUTIL_FOUND OR NOT SWSCALE_FOUND )
message(FATAL_ERROR "FFmpeg component required, but not found!") message(FATAL_ERROR "FFmpeg component required, but not found!")
endif() endif()
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS}) set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
if( SWRESAMPLE_FOUND ) if( SWRESAMPLE_FOUND )
add_definitions(-DHAVE_LIBSWRESAMPLE) add_definitions(-DHAVE_LIBSWRESAMPLE)
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES}) set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
else() else()
if( AVRESAMPLE_FOUND ) if( AVRESAMPLE_FOUND )
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES}) set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
else() else()
message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).") message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
endif() endif()
endif() endif()
# Required for building the FFmpeg headers
add_definitions(-D__STDC_CONSTANT_MACROS)
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES})
# 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)
@ -136,21 +144,32 @@ endif()
if (WIN32) if (WIN32)
if(NOT MINGW) if(NOT MINGW)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
set(PLATFORM_INCLUDE_DIR "platform")
add_definitions(-DBOOST_ALL_NO_LIB) add_definitions(-DBOOST_ALL_NO_LIB)
endif(NOT MINGW) endif(NOT MINGW)
# Suppress WinMain(), provided by SDL # Suppress WinMain(), provided by SDL
add_definitions(-DSDL_MAIN_HANDLED) add_definitions(-DSDL_MAIN_HANDLED)
else (WIN32)
set(PLATFORM_INCLUDE_DIR "") # Get rid of useless crud from windows.h
endif (WIN32) add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
if (MSVC10)
set(PLATFORM_INCLUDE_DIR "")
endif() endif()
# Dependencies # Dependencies
set(DESIRED_QT_VERSION 4 CACHE STRING "The QT version OpenMW should use (4 or 5)")
message(STATUS "Using Qt${DESIRED_QT_VERSION}")
if (DESIRED_QT_VERSION MATCHES 4)
find_package(Qt4 REQUIRED COMPONENTS QtCore QtGui QtNetwork QtOpenGL)
else()
find_package(Qt5Widgets REQUIRED)
find_package(Qt5Core REQUIRED)
find_package(Qt5Network REQUIRED)
find_package(Qt5OpenGL REQUIRED)
# Instruct CMake to run moc automatically when needed.
#set(CMAKE_AUTOMOC ON)
endif()
# Fix for not visible pthreads functions for linker with glibc 2.15 # Fix for not visible pthreads functions for linker with glibc 2.15
if (UNIX AND NOT APPLE) if (UNIX AND NOT APPLE)
find_package (Threads) find_package (Threads)
@ -171,7 +190,7 @@ if (HAVE_UNORDERED_MAP)
endif () endif ()
set(BOOST_COMPONENTS system filesystem program_options) set(BOOST_COMPONENTS system filesystem program_options thread)
if(WIN32) if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32) endif(WIN32)
@ -180,10 +199,8 @@ IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_STATIC_LIBS ON)
endif() endif()
find_package(OGRE REQUIRED) find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX)
if (${OGRE_VERSION} VERSION_LESS "1.9") include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
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") if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
@ -195,87 +212,22 @@ find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED) find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED) find_package(Bullet REQUIRED)
set(OGRE_PLUGIN_INCLUDE_DIRS "") include_directories("."
set(OGRE_STATIC_PLUGINS "")
macro(add_static_ogre_plugin PLUGIN)
if(OGRE_${PLUGIN}_FOUND)
# strip RenderSystem_ or Plugin_ prefix from plugin name
string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN})
string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP})
add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME})
list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS})
list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES})
endif(OGRE_${PLUGIN}_FOUND)
endmacro(add_static_ogre_plugin)
if(OGRE_STATIC)
# set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS
add_static_ogre_plugin(Plugin_OctreeSceneManager)
add_static_ogre_plugin(Plugin_ParticleFX)
find_package(Cg)
if(Cg_FOUND)
add_static_ogre_plugin(Plugin_CgProgramManager)
list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES})
endif(Cg_FOUND)
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("." ${LIBS_DIR}
SYSTEM SYSTEM
${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}
${MYGUI_INCLUDE_DIRS} ${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR} ${OPENAL_INCLUDE_DIR}
${BULLET_INCLUDE_DIRS} ${BULLET_INCLUDE_DIRS}
) )
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR}) link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${MYGUI_LIB_DIR})
if(MYGUI_STATIC) if(MYGUI_STATIC)
add_definitions(-DMYGUI_STATIC) add_definitions(-DMYGUI_STATIC)
endif (MYGUI_STATIC) endif (MYGUI_STATIC)
if (APPLE) if (APPLE)
# List used Ogre plugins
SET(USED_OGRE_PLUGINS ${OGRE_RenderSystem_GL_LIBRARY_REL}
${OGRE_Plugin_ParticleFX_LIBRARY_REL})
# Actually we must use OGRE_Plugin_CgProgramManager_FOUND but it's
# not reliable and equals TRUE even if there's no Ogre Cg plugin
if (Cg_FOUND)
set(USED_OGRE_PLUGINS ${USED_OGRE_PLUGINS}
${OGRE_Plugin_CgProgramManager_LIBRARY_REL})
endif ()
if (${OGRE_PLUGIN_DIR_REL}})
set(OGRE_PLUGINS_REL_FOUND TRUE)
endif ()
if (${OGRE_PLUGIN_DIR_DBG})
set(OGRE_PLUGINS_DBG_FOUND TRUE)
endif ()
if (${OGRE_PLUGINS_REL_FOUND})
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
else ()
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_DBG})
endif ()
configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist configure_file(${OpenMW_SOURCE_DIR}/files/mac/Info.plist
"${APP_BUNDLE_DIR}/Contents/Info.plist") "${APP_BUNDLE_DIR}/Contents/Info.plist")
@ -286,30 +238,7 @@ endif (APPLE)
# Set up DEBUG define # Set up DEBUG define
set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1) set_directory_properties(PROPERTIES COMPILE_DEFINITIONS_DEBUG DEBUG=1)
# Set up Ogre plugin folder & debug suffix
if (APPLE)
# Ogre on OS X doesn't use "_d" suffix (see Ogre's CMakeLists.txt)
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="")
else ()
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d")
endif()
if (APPLE AND OPENMW_OSX_DEPLOYMENT)
# make it empty so plugin loading code can check this and try to find plugins inside app bundle
add_definitions(-DOGRE_PLUGIN_DIR="")
else()
if (CUSTOM_OGRE_PLUGIN_DIR STREQUAL "")
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
else()
set(OGRE_PLUGIN_DIR ${CUSTOM_OGRE_PLUGIN_DIR})
endif()
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
endif()
add_subdirectory(files/) add_subdirectory(files/)
add_subdirectory(files/mygui)
# Specify build paths # Specify build paths
@ -326,9 +255,6 @@ endif (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg configure_file(${OpenMW_SOURCE_DIR}/files/settings-default.cfg
"${OpenMW_BINARY_DIR}/settings-default.cfg") "${OpenMW_BINARY_DIR}/settings-default.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/transparency-overrides.cfg
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg")
configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local configure_file(${OpenMW_SOURCE_DIR}/files/openmw.cfg.local
"${OpenMW_BINARY_DIR}/openmw.cfg") "${OpenMW_BINARY_DIR}/openmw.cfg")
@ -370,10 +296,14 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6) endif(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND "${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
elseif (MSVC) elseif (MSVC)
# Enable link-time code generation globally for all linking # Enable link-time code generation globally for all linking
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL") if (OPENMW_LTO_BUILD)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE")
endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) endif (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang)
IF(NOT WIN32 AND NOT APPLE) IF(NOT WIN32 AND NOT APPLE)
@ -394,7 +324,9 @@ IF(NOT WIN32 AND NOT APPLE)
SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir") SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir")
# Install binaries # Install binaries
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" ) IF(BUILD_OPENMW)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENMW)
IF(BUILD_LAUNCHER) IF(BUILD_LAUNCHER)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_LAUNCHER) ENDIF(BUILD_LAUNCHER)
@ -413,19 +345,15 @@ IF(NOT WIN32 AND NOT APPLE)
IF(BUILD_OPENCS) IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENCS) ENDIF(BUILD_OPENCS)
IF(BUILD_NIFTEST)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
ENDIF(BUILD_NIFTEST)
IF(BUILD_WIZARD) IF(BUILD_WIZARD)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" ) INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" )
ENDIF(BUILD_WIZARD) ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN) #if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" ) # INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
ENDIF(BUILD_MYGUI_PLUGIN) #ENDIF(BUILD_MYGUI_PLUGIN)
# Install licenses # Install licenses
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" ) 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" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.desktop" DESTINATION "${DATAROOTDIR}/applications" COMPONENT "openmw")
@ -437,7 +365,6 @@ IF(NOT WIN32 AND NOT APPLE)
# Install global configuration files # Install global configuration files
INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" DESTINATION "${SYSCONFDIR}" RENAME "openmw.cfg" COMPONENT "openmw")
INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw") INSTALL(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
@ -460,7 +387,6 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt" "${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
"${OpenMW_SOURCE_DIR}/Docs/license/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}/gamecontrollerdb.txt" "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe" "${OpenMW_BINARY_DIR}/Release/openmw.exe"
DESTINATION ".") DESTINATION ".")
@ -486,6 +412,8 @@ if(WIN32)
ENDIF(BUILD_MYGUI_PLUGIN) ENDIF(BUILD_MYGUI_PLUGIN)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".") INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
FILE(GLOB plugin_dir "${OpenMW_BINARY_DIR}/Release/osgPlugins-*")
INSTALL(DIRECTORY ${plugin_dir} DESTINATION ".")
SET(CPACK_GENERATOR "NSIS") SET(CPACK_GENERATOR "NSIS")
SET(CPACK_PACKAGE_NAME "OpenMW") SET(CPACK_PACKAGE_NAME "OpenMW")
@ -546,31 +474,22 @@ if(WIN32)
include(CPack) include(CPack)
endif(WIN32) endif(WIN32)
# Libs
include_directories(libs)
add_subdirectory(libs/openengine)
# Extern # Extern
add_subdirectory (extern/shiny) add_subdirectory (extern/osg-ffmpeg-videoplayer)
add_subdirectory (extern/ogre-ffmpeg-videoplayer)
add_subdirectory (extern/oics) add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre)
# Components # Components
add_subdirectory (components) add_subdirectory (components)
# Plugins # Plugins
if (BUILD_MYGUI_PLUGIN) #if (BUILD_MYGUI_PLUGIN)
add_subdirectory(plugins/mygui_resource_plugin) # add_subdirectory(plugins/mygui_resource_plugin)
endif() #endif()
#Testing
if (BUILD_NIFTEST)
add_subdirectory(components/nif/tests/)
endif(BUILD_NIFTEST)
# Apps and tools # Apps and tools
add_subdirectory( apps/openmw ) if (BUILD_OPENMW)
add_subdirectory( apps/openmw )
endif()
if (BUILD_BSATOOL) if (BUILD_BSATOOL)
add_subdirectory( apps/bsatool ) add_subdirectory( apps/bsatool )
@ -607,9 +526,9 @@ endif()
if (WIN32) if (WIN32)
if (MSVC) if (MSVC)
if (MULTITHREADED_BUILD) if (OPENMW_MP_BUILD)
set( MT_BUILD "/MP") set( MT_BUILD "/MP")
endif (MULTITHREADED_BUILD) endif()
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
@ -617,20 +536,22 @@ if (WIN32)
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" )
endforeach( OUTPUTCONFIG ) endforeach( OUTPUTCONFIG )
if (USE_DEBUG_CONSOLE) if (USE_DEBUG_CONSOLE AND BUILD_OPENMW)
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")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE")
else() elseif (BUILD_OPENMW)
# Turn off debug console, debug output will be written to visual studio output instead # Turn off debug console, debug output will be written to visual studio output instead
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS")
endif() endif()
# Release builds use the debug console if (BUILD_OPENMW)
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") # Release builds use the debug console
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE") set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
endif()
# Play a bit with the warning levels # Play a bit with the warning levels
@ -639,8 +560,8 @@ if (WIN32)
set(WARNINGS_DISABLE set(WARNINGS_DISABLE
# Warnings that aren't enabled normally and don't need to be enabled # Warnings that aren't enabled normally and don't need to be enabled
# They're unneeded and sometimes completely retarded warnings that /Wall enables # They're unneeded and sometimes completely retarded warnings that /Wall enables
# Not going to bother commenting them as they tend to warn on every standard library files # Not going to bother commenting them as they tend to warn on every standard library file
4061 4263 4264 4266 4350 4371 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946 4061 4263 4264 4266 4350 4371 4435 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946
# Warnings that are thrown on standard libraries and not OpenMW # Warnings that are thrown on standard libraries and not OpenMW
4347 # Non-template function with same name and parameter count as template function 4347 # Non-template function with same name and parameter count as template function
@ -652,12 +573,6 @@ if (WIN32)
4987 # nonstandard extension used (triggered by setjmp.h) 4987 # nonstandard extension used (triggered by setjmp.h)
4996 # Function was declared deprecated 4996 # Function was declared deprecated
# cause by ogre extensivly
4193 # #pragma warning(pop) : no matching '#pragma warning(push)'
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'
4315 # undocumented, 'this' pointer for member might not be aligned (OgreMemoryStlAllocator.h)
# caused by boost # caused by boost
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off) 4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
@ -668,6 +583,7 @@ if (WIN32)
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)
4245 # Signed/unsigned mismatch
4267 # Conversion from 'size_t' to 'int', possible loss of data 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
@ -683,21 +599,42 @@ if (WIN32)
set(WARNINGS "${WARNINGS} /wd${d}") set(WARNINGS "${WARNINGS} /wd${d}")
endforeach(d) endforeach(d)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNINGS} ${MT_BUILD}") set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
# oics uses tinyxml, which has an initialized but unused variable
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${WARNINGS} /wd4189 ${MT_BUILD}")
set_target_properties(osg-ffmpeg-videoplayer PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
# boost::wave has a few issues with signed / unsigned conversions, so we suppress those here if (BUILD_BSATOOL)
set(SHINY_WARNINGS "${WARNINGS} /wd4245") set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}") endif()
# oics uses tinyxml, which has an initialized but unused variable if (BUILD_ESMTOOL)
set(OICS_WARNINGS "${WARNINGS} /wd4189") set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}") endif()
if (BUILD_ESSIMPORTER)
set_target_properties(openmw-essimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
if (BUILD_LAUNCHER)
set_target_properties(openmw-launcher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
if (BUILD_MWINIIMPORTER)
set_target_properties(openmw-iniimporter PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
if (BUILD_OPENCS) if (BUILD_OPENCS)
# QT triggers an informational warning that the object layout may differ when compiled with /vd2 set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435") endif()
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS})
endif (BUILD_OPENCS) if (BUILD_OPENMW)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
if (BUILD_WIZARD)
set_target_properties(openmw-wizard PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
endif(MSVC) endif(MSVC)
# TODO: At some point release builds should not use the console but rather write to a log file # TODO: At some point release builds should not use the console but rather write to a log file
@ -714,7 +651,6 @@ if (APPLE)
install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/openmw.cfg.install" RENAME "openmw.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/settings-default.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/gamecontrollerdb.txt" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime) install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop") set(CPACK_GENERATOR "DragNDrop")
@ -728,90 +664,14 @@ if (APPLE)
set(OPENCS_BUNDLE_NAME "OpenMW-CS.app") set(OPENCS_BUNDLE_NAME "OpenMW-CS.app")
set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}") set(OPENCS_APP "\${CMAKE_INSTALL_PREFIX}/${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}")
set(ABSOLUTE_PLUGINS "")
foreach (PLUGIN ${USED_OGRE_PLUGINS})
get_filename_component(PLUGIN_ABS ${PLUGIN} REALPATH)
set(ABSOLUTE_PLUGINS ${PLUGIN_ABS} ${ABSOLUTE_PLUGINS})
endforeach ()
install(CODE " install(CODE "
set(BU_CHMOD_BUNDLE_ITEMS ON) set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities) include(BundleUtilities)
" COMPONENT Runtime) " COMPONENT Runtime)
# installs used plugins in bundle at given path (bundle_path must be relative to ${CMAKE_INSTALL_PREFIX})
# and returns list of install paths for all installed plugins
function (install_plugins_for_bundle bundle_path plugins_var)
set(RELATIVE_PLUGIN_INSTALL_BASE "${bundle_path}/Contents/Frameworks")
set(PLUGINS "")
set(PLUGIN_INSTALL_BASE "\${CMAKE_INSTALL_PREFIX}/${RELATIVE_PLUGIN_INSTALL_BASE}")
foreach (PLUGIN ${ABSOLUTE_PLUGINS})
get_filename_component(PLUGIN_RELATIVE ${PLUGIN} NAME)
get_filename_component(PLUGIN_RELATIVE_WE ${PLUGIN} NAME_WE)
set(PLUGIN_DYLIB_IN_BUNDLE "${PLUGIN_INSTALL_BASE}/${PLUGIN_RELATIVE}/${PLUGIN_RELATIVE_WE}")
set(PLUGINS ${PLUGINS} "${PLUGIN_DYLIB_IN_BUNDLE}")
install(CODE "
copy_resolved_framework_into_bundle(\"${PLUGIN}/${PLUGIN_RELATIVE_WE}\" \"${PLUGIN_DYLIB_IN_BUNDLE}\")
" COMPONENT Runtime)
endforeach ()
set(${plugins_var} ${PLUGINS} PARENT_SCOPE)
endfunction (install_plugins_for_bundle)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${APP_BUNDLE_NAME}" PLUGINS)
install_plugins_for_bundle("${INSTALL_SUBDIR}/${OPENCS_BUNDLE_NAME}" OPENCS_PLUGINS)
#For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail #For now, search unresolved dependencies only in default system paths, so if you put unresolveable (i.e. with @executable_path in id name) lib or framework somewhere else, it would fail
set(DIRS "") set(DIRS "")
# Overriding item resolving during installation, it needed if
# some library already has been "fixed up", i.e. its id name contains @executable_path,
# but library is not embedded in bundle. For example, it's Ogre.framework from Ogre SDK.
# Current implementation of GetPrerequsities/BundleUtilities doesn't handle that case.
#
# Current limitations:
# 1. Handles only frameworks, not simple libs
INSTALL(CODE "
cmake_policy(SET CMP0009 OLD)
set(CMAKE_FIND_LIBRARY_PREFIXES ${CMAKE_FIND_LIBRARY_PREFIXES})
set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
set(CMAKE_SYSTEM_FRAMEWORK_PATH ${CMAKE_SYSTEM_FRAMEWORK_PATH})
set(OPENMW_RESOLVED_ITEMS \"\")
function(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var)
if(item MATCHES \"@executable_path\" AND NOT \${\${resolved_var}})
if (item MATCHES \"Frameworks\") # if it is a framework
# get last segment of path
get_filename_component(fname \"\${item}\" NAME_WE)
find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} \${CMAKE_SYSTEM_FRAMEWORK_PATH})
if (ri)
string(REGEX REPLACE \"^.*/Frameworks/.*\\\\.framework\" \"\" item_part \${item})
set(ri \"\${ri}\${item_part}\")
set(\${resolved_item_var} \${ri} PARENT_SCOPE)
set(\${resolved_var} 1 PARENT_SCOPE)
endif()
else()
# code path for standard (non-framework) libs (ogre & qt pugins)
get_filename_component(fname \"\${item}\" NAME_WE)
string(REGEX REPLACE \"^lib\" \"\" fname \${fname})
find_library(ri NAMES \${fname} PATHS \${exepath} \${dirs} /usr/lib /usr/local/lib)
if (ri)
set(\${resolved_item_var} \${ri} PARENT_SCOPE)
set(\${resolved_var} 1 PARENT_SCOPE)
endif ()
endif()
endif()
endfunction(gp_resolve_item_override)
fixup_bundle(\"${OPENMW_APP}\" \"${PLUGINS}\" \"${DIRS}\")
fixup_bundle(\"${OPENCS_APP}\" \"${OPENCS_PLUGINS}\" \"${DIRS}\")
" COMPONENT Runtime)
include(CPack) include(CPack)
endif (APPLE) endif (APPLE)

@ -9,7 +9,8 @@ add_executable(bsatool
) )
target_link_libraries(bsatool target_link_libraries(bsatool
${Boost_LIBRARIES} ${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
components components
) )

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <vector> #include <vector>
#include <exception> #include <exception>
@ -237,12 +238,14 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
} }
// Get a stream for the file to extract // Get a stream for the file to extract
Ogre::DataStreamPtr data = bsa.getFile(archivePath.c_str()); Files::IStreamPtr stream = bsa.getFile(archivePath.c_str());
bfs::ofstream out(target, std::ios::binary); bfs::ofstream out(target, std::ios::binary);
// Write the file to disk // Write the file to disk
std::cout << "Extracting " << info.extractfile << " to " << target << std::endl; std::cout << "Extracting " << info.extractfile << " to " << target << std::endl;
out.write(data->getAsString().c_str(), data->size());
out << stream->rdbuf();
out.close(); out.close();
return 0; return 0;
@ -276,12 +279,12 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info)
// Get a stream for the file to extract // Get a stream for the file to extract
// (inefficient because getFile iter on the list again) // (inefficient because getFile iter on the list again)
Ogre::DataStreamPtr data = bsa.getFile(archivePath); Files::IStreamPtr data = bsa.getFile(archivePath);
bfs::ofstream out(target, std::ios::binary); bfs::ofstream out(target, std::ios::binary);
// Write the file to disk // Write the file to disk
std::cout << "Extracting " << target << std::endl; std::cout << "Extracting " << target << std::endl;
out.write(data->getAsString().c_str(), data->size()); out << data->rdbuf();
out.close(); out.close();
} }

@ -13,7 +13,7 @@ add_executable(esmtool
) )
target_link_libraries(esmtool target_link_libraries(esmtool
${Boost_LIBRARIES} ${Boost_PROGRAM_OPTIONS_LIBRARY}
components components
) )

@ -4,6 +4,7 @@
#include <list> #include <list>
#include <map> #include <map>
#include <set> #include <set>
#include <fstream>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
@ -284,7 +285,7 @@ void printRaw(ESM::ESMReader &esm)
esm.getRecHeader(); esm.getRecHeader();
while(esm.hasMoreSubs()) while(esm.hasMoreSubs())
{ {
uint64_t offs = esm.getOffset(); size_t offs = esm.getFileOffset();
esm.getSubName(); esm.getSubName();
esm.skipHSub(); esm.skipHSub();
n = esm.retSubName(); n = esm.retSubName();

@ -119,7 +119,7 @@ std::string clothingTypeLabel(int idx)
} }
std::string armorTypeLabel(int idx) std::string armorTypeLabel(int idx)
{ {
if (idx >= 0 && idx <= 10) if (idx >= 0 && idx <= 10)
{ {
static const char *armorTypeLabels[] = { static const char *armorTypeLabels[] = {
@ -645,7 +645,7 @@ std::string ruleFunction(int idx)
else else
return "Invalid"; return "Invalid";
} }
// The "unused flag bits" should probably be defined alongside the // The "unused flag bits" should probably be defined alongside the
// defined bits in the ESM component. The names of the flag bits are // defined bits in the ESM component. The names of the flag bits are
// very inconsistent. // very inconsistent.
@ -653,7 +653,7 @@ std::string ruleFunction(int idx)
std::string bodyPartFlags(int flags) std::string bodyPartFlags(int flags)
{ {
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
if (flags & ESM::BodyPart::BPF_Female) properties += "Female "; if (flags & ESM::BodyPart::BPF_Female) properties += "Female ";
if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable "; if (flags & ESM::BodyPart::BPF_NotPlayable) properties += "NotPlayable ";
int unused = (0xFFFFFFFF ^ int unused = (0xFFFFFFFF ^
@ -667,7 +667,7 @@ std::string bodyPartFlags(int flags)
std::string cellFlags(int flags) std::string cellFlags(int flags)
{ {
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
if (flags & ESM::Cell::HasWater) properties += "HasWater "; if (flags & ESM::Cell::HasWater) properties += "HasWater ";
if (flags & ESM::Cell::Interior) properties += "Interior "; if (flags & ESM::Cell::Interior) properties += "Interior ";
if (flags & ESM::Cell::NoSleep) properties += "NoSleep "; if (flags & ESM::Cell::NoSleep) properties += "NoSleep ";
@ -830,12 +830,12 @@ std::string npcFlags(int flags)
std::string properties = ""; std::string properties = "";
if (flags == 0) properties += "[None] "; if (flags == 0) properties += "[None] ";
// Mythicmods and the ESM component differ. Mythicmods says // Mythicmods and the ESM component differ. Mythicmods says
// 0x8=None and 0x10=AutoCalc, while our code defines 0x8 as // 0x8=None and 0x10=AutoCalc, while our code previously defined
// AutoCalc. The former seems to be correct. All Bethesda // 0x8 as AutoCalc. The former seems to be correct. All Bethesda
// records have bit 0x8 set. A suspiciously large portion of // records have bit 0x8 set. Previously, suspiciously large portion
// females have autocalc turned off. // of females had autocalc turned off.
if (flags & ESM::NPC::Autocalc) properties += "Unknown "; if (flags & 0x00000008) properties += "Unknown ";
if (flags & 0x00000010) properties += "Autocalc "; if (flags & ESM::NPC::Autocalc) properties += "Autocalc ";
if (flags & ESM::NPC::Female) properties += "Female "; if (flags & ESM::NPC::Female) properties += "Female ";
if (flags & ESM::NPC::Respawn) properties += "Respawn "; if (flags & ESM::NPC::Respawn) properties += "Respawn ";
if (flags & ESM::NPC::Essential) properties += "Essential "; if (flags & ESM::NPC::Essential) properties += "Essential ";
@ -847,8 +847,8 @@ std::string npcFlags(int flags)
// however the only unknown bit occurs on ALL records, and // however the only unknown bit occurs on ALL records, and
// relatively few NPCs have this bit set. // relatively few NPCs have this bit set.
int unused = (0xFFFFFFFF ^ int unused = (0xFFFFFFFF ^
(ESM::NPC::Autocalc| (0x00000008|
0x00000010| ESM::NPC::Autocalc|
ESM::NPC::Female| ESM::NPC::Female|
ESM::NPC::Respawn| ESM::NPC::Respawn|
ESM::NPC::Essential| ESM::NPC::Essential|

@ -33,7 +33,8 @@ add_executable(openmw-essimporter
) )
target_link_libraries(openmw-essimporter target_link_libraries(openmw-essimporter
${Boost_LIBRARIES} ${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
components components
) )

@ -41,9 +41,9 @@ namespace ESSImport
{ {
for (int i=0; i<ESM::Skill::Length; ++i) for (int i=0; i<ESM::Skill::Length; ++i)
{ {
npcStats.mSkills[i].mRegular.mMod = actorData.mSkills[i][1]; npcStats.mSkills[i].mMod = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mCurrent = actorData.mSkills[i][1]; npcStats.mSkills[i].mCurrent = actorData.mSkills[i][1];
npcStats.mSkills[i].mRegular.mBase = actorData.mSkills[i][0]; npcStats.mSkills[i].mBase = actorData.mSkills[i][0];
} }
npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter; npcStats.mTimeToStartDrowning = actorData.mACDT.mBreathMeter;

@ -2,8 +2,7 @@
#include <stdexcept> #include <stdexcept>
#include <OgreImage.h> #include <osgDB/WriteFile>
#include <OgreColourValue.h>
#include <components/esm/creaturestate.hpp> #include <components/esm/creaturestate.hpp>
#include <components/esm/containerstate.hpp> #include <components/esm/containerstate.hpp>
@ -15,12 +14,14 @@
namespace namespace
{ {
void convertImage(char* data, int size, int width, int height, Ogre::PixelFormat pf, const std::string& out) void convertImage(char* data, int size, int width, int height, GLenum pf, const std::string& out)
{ {
Ogre::Image screenshot; osg::ref_ptr<osg::Image> image (new osg::Image);
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size)); image->allocateImage(width, height, 1, pf, GL_UNSIGNED_BYTE);
screenshot.loadRawData(stream, width, height, 1, pf); memcpy(image->data(), data, size);
screenshot.save(out); image->flipVertical();
osgDB::writeImageFile(*image, out);
} }
@ -71,17 +72,20 @@ namespace ESSImport
data.resize(esm.getSubSize()); data.resize(esm.getSubSize());
esm.getExact(&data[0], data.size()); esm.getExact(&data[0], data.size());
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(&data[0], data.size())); mGlobalMapImage = new osg::Image;
mGlobalMapImage.loadRawData(stream, maph.size, maph.size, 1, Ogre::PF_BYTE_RGB); mGlobalMapImage->allocateImage(maph.size, maph.size, 1, GL_RGB, GL_UNSIGNED_BYTE);
memcpy(mGlobalMapImage->data(), &data[0], data.size());
// to match openmw size // to match openmw size
mGlobalMapImage.resize(maph.size*2, maph.size*2, Ogre::Image::FILTER_BILINEAR); // FIXME: filtering?
mGlobalMapImage->scaleImage(maph.size*2, maph.size*2, 1, GL_UNSIGNED_BYTE);
} }
void ConvertFMAP::write(ESM::ESMWriter &esm) void ConvertFMAP::write(ESM::ESMWriter &esm)
{ {
int numcells = mGlobalMapImage.getWidth() / 18; // NB truncating, doesn't divide perfectly int numcells = mGlobalMapImage->s() / 18; // NB truncating, doesn't divide perfectly
// with the 512x512 map the game has by default // with the 512x512 map the game has by default
int cellSize = mGlobalMapImage.getWidth()/numcells; int cellSize = mGlobalMapImage->s()/numcells;
// Note the upper left corner of the (0,0) cell should be at (width/2, height/2) // Note the upper left corner of the (0,0) cell should be at (width/2, height/2)
@ -90,12 +94,14 @@ namespace ESSImport
mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2; mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2;
mContext->mGlobalMapState.mBounds.mMaxY = numcells/2; mContext->mGlobalMapState.mBounds.mMaxY = numcells/2;
Ogre::Image image2; osg::ref_ptr<osg::Image> image2 (new osg::Image);
std::vector<Ogre::uint8> data;
int width = cellSize*numcells; int width = cellSize*numcells;
int height = cellSize*numcells; int height = cellSize*numcells;
std::vector<unsigned char> data;
data.resize(width*height*4, 0); data.resize(width*height*4, 0);
image2.loadDynamicImage(&data[0], width, height, Ogre::PF_BYTE_RGBA);
image2->allocateImage(width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE);
memcpy(image2->data(), &data[0], data.size());
for (std::set<std::pair<int, int> >::const_iterator it = mContext->mExploredCells.begin(); it != mContext->mExploredCells.end(); ++it) for (std::set<std::pair<int, int> >::const_iterator it = mContext->mExploredCells.begin(); it != mContext->mExploredCells.end(); ++it)
{ {
@ -108,8 +114,8 @@ namespace ESSImport
continue; continue;
} }
int imageLeftSrc = mGlobalMapImage.getWidth()/2; int imageLeftSrc = mGlobalMapImage->s()/2;
int imageTopSrc = mGlobalMapImage.getHeight()/2; int imageTopSrc = mGlobalMapImage->t()/2;
imageLeftSrc += it->first * cellSize; imageLeftSrc += it->first * cellSize;
imageTopSrc -= it->second * cellSize; imageTopSrc -= it->second * cellSize;
int imageLeftDst = width/2; int imageLeftDst = width/2;
@ -118,13 +124,31 @@ namespace ESSImport
imageTopDst -= it->second * cellSize; imageTopDst -= it->second * cellSize;
for (int x=0; x<cellSize; ++x) for (int x=0; x<cellSize; ++x)
for (int y=0; y<cellSize; ++y) for (int y=0; y<cellSize; ++y)
image2.setColourAt(mGlobalMapImage.getColourAt(imageLeftSrc+x, imageTopSrc+y, 0) {
, imageLeftDst+x, imageTopDst+y, 0); unsigned int col = *(unsigned int*)mGlobalMapImage->data(imageLeftSrc+x, imageTopSrc+y, 0);
*(unsigned int*)image2->data(imageLeftDst+x, imageTopDst+y, 0) = col;
}
}
std::stringstream ostream;
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("png");
if (!readerwriter)
{
std::cerr << "can't write global map image, no png readerwriter found" << std::endl;
return;
}
image2->flipVertical();
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image2, ostream);
if (!result.success())
{
std::cerr << "can't write global map image: " << result.message() << std::endl;
return;
} }
Ogre::DataStreamPtr encoded = image2.encode("png"); std::string outData = ostream.str();
mContext->mGlobalMapState.mImageData.resize(encoded->size()); mContext->mGlobalMapState.mImageData = std::vector<char>(outData.begin(), outData.end());
encoded->read(&mContext->mGlobalMapState.mImageData[0], encoded->size());
esm.startRecord(ESM::REC_GMAP); esm.startRecord(ESM::REC_GMAP);
mContext->mGlobalMapState.save(esm); mContext->mGlobalMapState.save(esm);
@ -194,7 +218,7 @@ namespace ESSImport
std::ostringstream filename; std::ostringstream filename;
filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga"; filename << "fog_" << cell.mData.mX << "_" << cell.mData.mY << ".tga";
convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, Ogre::PF_BYTE_RGBA, filename.str()); convertImage((char*)&newcell.mFogOfWar[0], newcell.mFogOfWar.size()*4, 16, 16, GL_RGBA, filename.str());
} }
} }

@ -1,7 +1,10 @@
#ifndef OPENMW_ESSIMPORT_CONVERTER_H #ifndef OPENMW_ESSIMPORT_CONVERTER_H
#define OPENMW_ESSIMPORT_CONVERTER_H #define OPENMW_ESSIMPORT_CONVERTER_H
#include <OgreImage.h> #include <limits>
#include <osg/Image>
#include <osg/ref_ptr>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
@ -311,7 +314,7 @@ public:
virtual void write(ESM::ESMWriter &esm); virtual void write(ESM::ESMWriter &esm);
private: private:
Ogre::Image mGlobalMapImage; osg::ref_ptr<osg::Image> mGlobalMapImage;
}; };
class ConvertCell : public Converter class ConvertCell : public Converter

@ -18,7 +18,7 @@ namespace ESSImport
for (int i=0; i<8; ++i) for (int i=0; i<8; ++i)
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i]; out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[i];
for (int i=0; i<27; ++i) for (int i=0; i<27; ++i)
out.mObject.mNpcStats.mSkills[i].mRegular.mProgress = pcdt.mPNAM.mSkillProgress[i]; out.mObject.mNpcStats.mSkills[i].mProgress = pcdt.mPNAM.mSkillProgress[i];
out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress; out.mObject.mNpcStats.mLevelProgress = pcdt.mPNAM.mLevelProgress;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon) if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)

@ -1,7 +1,11 @@
#include "importer.hpp" #include "importer.hpp"
#include <iomanip>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <OgreRoot.h> #include <osgDB/ReadFile>
#include <osg/ImageUtils>
#include <components/esm/esmreader.hpp> #include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp> #include <components/esm/esmwriter.hpp>
@ -32,13 +36,48 @@ namespace
void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out) void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out)
{ {
Ogre::Image screenshot; if (fileHeader.mSCRS.size() != 128*128*4)
std::vector<unsigned char> screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :( {
Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size())); std::cerr << "unexpected screenshot size " << std::endl;
screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA); return;
Ogre::DataStreamPtr encoded = screenshot.encode("jpg"); }
out.mScreenshot.resize(encoded->size());
encoded->read(&out.mScreenshot[0], encoded->size()); osg::ref_ptr<osg::Image> image (new osg::Image);
image->allocateImage(128, 128, 1, GL_RGB, GL_UNSIGNED_BYTE);
// need to convert pixel format from BGRA to RGB as the jpg readerwriter doesn't support it otherwise
std::vector<unsigned char>::const_iterator it = fileHeader.mSCRS.begin();
for (int y=0; y<128; ++y)
{
for (int x=0; x<128; ++x)
{
*(image->data(x,y)+2) = *it++;
*(image->data(x,y)+1) = *it++;
*image->data(x,y) = *it++;
it++; // skip alpha
}
}
image->flipVertical();
std::stringstream ostream;
osgDB::ReaderWriter* readerwriter = osgDB::Registry::instance()->getReaderWriterForExtension("jpg");
if (!readerwriter)
{
std::cerr << "can't write screenshot: no jpg readerwriter found" << std::endl;
return;
}
osgDB::ReaderWriter::WriteResult result = readerwriter->writeImage(*image, ostream);
if (!result.success())
{
std::cerr << "can't write screenshot: " << result.message() << " code " << result.status() << std::endl;
return;
}
std::string data = ostream.str();
out.mScreenshot = std::vector<char>(data.begin(), data.end());
} }
} }
@ -203,10 +242,6 @@ namespace ESSImport
void Importer::run() void Importer::run()
{ {
// construct Ogre::Root to gain access to image codecs
Ogre::LogManager logman;
Ogre::Root root;
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding)); ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding));
ESM::ESMReader esm; ESM::ESMReader esm;
esm.open(mEssFile); esm.open(mEssFile);
@ -292,7 +327,7 @@ namespace ESSImport
ESM::ESMWriter writer; ESM::ESMWriter writer;
writer.setFormat (ESM::Header::CurrentFormat); writer.setFormat (ESM::SavedGame::sCurrentFormat);
std::ofstream stream(mOutFile.c_str(), std::ios::binary); std::ofstream stream(mOutFile.c_str(), std::ios::binary);
// all unused // all unused

@ -57,7 +57,6 @@ set(LAUNCHER_UI
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER}) source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
find_package(Qt4 REQUIRED)
set(QT_USE_QTGUI 1) set(QT_USE_QTGUI 1)
# Set some platform specific settings # Set some platform specific settings
@ -66,12 +65,17 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc) if (DESIRED_QT_VERSION MATCHES 4)
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC}) include(${QT_USE_FILE})
QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI}) QT4_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
QT4_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
QT4_WRAP_UI(UI_HDRS ${LAUNCHER_UI})
else()
QT5_ADD_RESOURCES(RCC_SRCS ${CMAKE_SOURCE_DIR}/files/launcher/launcher.qrc)
QT5_WRAP_CPP(MOC_SRCS ${LAUNCHER_HEADER_MOC})
QT5_WRAP_UI(UI_HDRS ${LAUNCHER_UI})
endif()
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_DIR}) include_directories(${LIBUNSHIELD_INCLUDE_DIR})
@ -88,17 +92,25 @@ add_executable(openmw-launcher
) )
target_link_libraries(openmw-launcher target_link_libraries(openmw-launcher
${Boost_LIBRARIES}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SDL2_LIBRARY_ONLY} ${SDL2_LIBRARY_ONLY}
${QT_LIBRARIES}
components components
) )
if (DESIRED_QT_VERSION MATCHES 4)
target_link_libraries(openmw-launcher ${QT_QTGUI_LIBRARY} ${QT_QTCORE_LIBRARY})
if(WIN32)
target_link_libraries(openmw-launcher ${QT_QTMAIN_LIBRARY})
endif(WIN32)
else()
qt5_use_modules(openmw-launcher Widgets Core)
if (WIN32)
target_link_libraries(Qt5::WinMain)
endif()
endif()
if (BUILD_WITH_CODE_COVERAGE) if (BUILD_WITH_CODE_COVERAGE)
add_definitions (--coverage) add_definitions (--coverage)
target_link_libraries(openmw-launcher gcov) target_link_libraries(openmw-launcher gcov)
endif() endif()

@ -12,9 +12,6 @@
#include <SDL_video.h> #include <SDL_video.h>
#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <boost/math/common_factor.hpp> #include <boost/math/common_factor.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
@ -37,10 +34,6 @@ 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)
: QWidget(parent) : QWidget(parent)
, mOgre(NULL)
, mSelectedRenderSystem(NULL)
, mOpenGLRenderSystem(NULL)
, mDirect3DRenderSystem(NULL)
, mCfgMgr(cfg) , mCfgMgr(cfg)
, mGraphicsSettings(graphicsSetting) , mGraphicsSettings(graphicsSetting)
{ {
@ -52,79 +45,12 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsS
customWidthSpinBox->setMaximum(res.width()); customWidthSpinBox->setMaximum(res.width());
customHeightSpinBox->setMaximum(res.height()); customHeightSpinBox->setMaximum(res.height());
connect(rendererComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(rendererChanged(const QString&)));
connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int))); connect(fullScreenCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotFullScreenChanged(int)));
connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool))); connect(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int))); connect(screenComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(screenChanged(int)));
} }
bool Launcher::GraphicsPage::setupOgre()
{
try
{
mOgre = mOgreInit.init(mCfgMgr.getLogPath().string() + "/launcherOgre.log");
}
catch(Ogre::Exception &ex)
{
QString ogreError = QString::fromUtf8(ex.getFullDescription().c_str());
QMessageBox msgBox;
msgBox.setWindowTitle("Error creating Ogre::Root");
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Failed to create the Ogre::Root object</b><br><br> \
Press \"Show Details...\" for more information.<br>"));
msgBox.setDetailedText(ogreError);
msgBox.exec();
qCritical("Error creating Ogre::Root, the error reported was:\n %s", qPrintable(ogreError));
return false;
}
// Get the available renderers and put them in the combobox
const Ogre::RenderSystemList &renderers = mOgre->getAvailableRenderers();
for (Ogre::RenderSystemList::const_iterator r = renderers.begin(); r != renderers.end(); ++r) {
mSelectedRenderSystem = *r;
rendererComboBox->addItem((*r)->getName().c_str());
}
QString openGLName = QString("OpenGL Rendering Subsystem");
QString direct3DName = QString("Direct3D9 Rendering Subsystem");
// Create separate rendersystems
mOpenGLRenderSystem = mOgre->getRenderSystemByName(openGLName.toStdString());
mDirect3DRenderSystem = mOgre->getRenderSystemByName(direct3DName.toStdString());
if (!mOpenGLRenderSystem && !mDirect3DRenderSystem) {
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error creating renderer"));
msgBox.setIcon(QMessageBox::Critical);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setText(tr("<br><b>Could not select a valid render system</b><br><br> \
Please make sure Ogre plugins were installed correctly.<br>"));
msgBox.exec();
return false;
}
// Now fill the GUI elements
int index = rendererComboBox->findText(mGraphicsSettings.value(QString("Video/render system")));
if ( index != -1) {
rendererComboBox->setCurrentIndex(index);
} else {
#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
rendererComboBox->setCurrentIndex(rendererComboBox->findText(direct3DName));
#else
rendererComboBox->setCurrentIndex(rendererComboBox->findText(openGLName));
#endif
}
antiAliasingComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
return true;
}
bool Launcher::GraphicsPage::setupSDL() bool Launcher::GraphicsPage::setupSDL()
{ {
int displays = SDL_GetNumVideoDisplays(); int displays = SDL_GetNumVideoDisplays();
@ -153,8 +79,6 @@ bool Launcher::GraphicsPage::loadSettings()
{ {
if (!setupSDL()) if (!setupSDL())
return false; return false;
if (!mOgre && !setupOgre())
return false;
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true")) if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
vSyncCheckBox->setCheckState(Qt::Checked); vSyncCheckBox->setCheckState(Qt::Checked);
@ -203,7 +127,6 @@ void Launcher::GraphicsPage::saveSettings()
: mGraphicsSettings.setValue(QString("Video/window border"), QString("false")); : mGraphicsSettings.setValue(QString("Video/window border"), QString("false"));
mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText()); mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
if (standardRadioButton->isChecked()) { if (standardRadioButton->isChecked()) {
@ -221,39 +144,6 @@ void Launcher::GraphicsPage::saveSettings()
mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex())); mGraphicsSettings.setValue(QString("Video/screen"), QString::number(screenComboBox->currentIndex()));
} }
QStringList Launcher::GraphicsPage::getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer)
{
QStringList result;
uint row = 0;
Ogre::ConfigOptionMap options = renderer->getConfigOptions();
for (Ogre::ConfigOptionMap::iterator i = options.begin (); i != options.end (); ++i, ++row)
{
Ogre::StringVector::iterator opt_it;
uint idx = 0;
for (opt_it = i->second.possibleValues.begin();
opt_it != i->second.possibleValues.end(); ++opt_it, ++idx)
{
if (strcmp (key.toStdString().c_str(), i->first.c_str()) == 0) {
result << ((key == "FSAA") ? QString("MSAA ") : QString("")) + QString::fromUtf8((*opt_it).c_str()).simplified();
}
}
}
// Sort ascending
qSort(result.begin(), result.end(), naturalSortLessThanCI);
// Replace the zero option with Off
int index = result.indexOf("MSAA 0");
if (index != -1)
result.replace(index, tr("Off"));
return result;
}
QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen) QStringList Launcher::GraphicsPage::getAvailableResolutions(int screen)
{ {
QStringList result; QStringList result;
@ -316,15 +206,6 @@ QRect Launcher::GraphicsPage::getMaximumResolution()
return max; return max;
} }
void Launcher::GraphicsPage::rendererChanged(const QString &renderer)
{
mSelectedRenderSystem = mOgre->getRenderSystemByName(renderer.toStdString());
antiAliasingComboBox->clear();
antiAliasingComboBox->addItems(getAvailableOptions(QString("FSAA"), mSelectedRenderSystem));
}
void Launcher::GraphicsPage::screenChanged(int screen) void Launcher::GraphicsPage::screenChanged(int screen)
{ {
if (screen >= 0) { if (screen >= 0) {

@ -3,12 +3,8 @@
#include <QWidget> #include <QWidget>
#include <components/ogreinit/ogreinit.hpp>
#include "ui_graphicspage.h" #include "ui_graphicspage.h"
namespace Ogre { class Root; class RenderSystem; }
namespace Files { struct ConfigurationManager; } namespace Files { struct ConfigurationManager; }
namespace Launcher namespace Launcher
@ -26,7 +22,6 @@ namespace Launcher
bool loadSettings(); bool loadSettings();
public slots: public slots:
void rendererChanged(const QString &renderer);
void screenChanged(int screen); void screenChanged(int screen);
private slots: private slots:
@ -34,20 +29,12 @@ namespace Launcher
void slotStandardToggled(bool checked); void slotStandardToggled(bool checked);
private: private:
OgreInit::OgreInit mOgreInit;
Ogre::Root *mOgre;
Ogre::RenderSystem *mSelectedRenderSystem;
Ogre::RenderSystem *mOpenGLRenderSystem;
Ogre::RenderSystem *mDirect3DRenderSystem;
Files::ConfigurationManager &mCfgMgr; Files::ConfigurationManager &mCfgMgr;
GraphicsSettings &mGraphicsSettings; GraphicsSettings &mGraphicsSettings;
QStringList getAvailableOptions(const QString &key, Ogre::RenderSystem *renderer);
QStringList getAvailableResolutions(int screen); QStringList getAvailableResolutions(int screen);
QRect getMaximumResolution(); QRect getMaximumResolution();
bool setupOgre();
bool setupSDL(); bool setupSDL();
}; };
} }

@ -54,9 +54,6 @@ int main(int argc, char *argv[])
QDir::setCurrent(dir.absolutePath()); QDir::setCurrent(dir.absolutePath());
// Support non-latin characters
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
Launcher::MainDialog mainWin; Launcher::MainDialog mainWin;
Launcher::FirstRunDialogResult result = mainWin.showFirstRunDialog(); Launcher::FirstRunDialogResult result = mainWin.showFirstRunDialog();

@ -199,7 +199,7 @@ bool Launcher::MainDialog::setup()
// Now create the pages as they need the settings // Now create the pages as they need the settings
createPages(); createPages();
// Call this so we can exit on Ogre/SDL errors before mainwindow is shown // Call this so we can exit on SDL errors before mainwindow is shown
if (!mGraphicsPage->loadSettings()) if (!mGraphicsPage->loadSettings())
return false; return false;
@ -490,7 +490,7 @@ bool Launcher::MainDialog::writeSettings()
// Game settings // Game settings
QFile file(userPath + QString("openmw.cfg")); QFile file(userPath + QString("openmw.cfg"));
if (!file.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) { if (!file.open(QIODevice::ReadWrite | QIODevice::Text)) {
// File cannot be opened or created // File cannot be opened or created
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file")); msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
@ -503,10 +503,8 @@ bool Launcher::MainDialog::writeSettings()
return false; return false;
} }
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.writeFile(stream); mGameSettings.writeFileWithComments(file);
file.close(); file.close();
// Graphics settings // Graphics settings
@ -525,6 +523,7 @@ bool Launcher::MainDialog::writeSettings()
return false; return false;
} }
QTextStream stream(&file);
stream.setDevice(&file); stream.setDevice(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8")); stream.setCodec(QTextCodec::codecForName("UTF-8"));

@ -14,10 +14,16 @@ add_executable(openmw-iniimporter
) )
target_link_libraries(openmw-iniimporter target_link_libraries(openmw-iniimporter
${Boost_LIBRARIES} ${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
components components
) )
if (WIN32)
target_link_libraries(openmw-iniimporter
${Boost_LOCALE_LIBRARY})
endif()
if (MINGW) if (MINGW)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -municode")
endif() endif()

@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc
opencs_units (model/world opencs_units (model/world
idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree idtable idtableproxymodel regionmap data commanddispatcher idtablebase resourcetable nestedtableproxymodel idtree infotableproxymodel
) )
@ -26,6 +26,7 @@ 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 resources resourcesmanager scope refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
idcompletionmanager metadata
) )
opencs_hdrs_noqt (model/world opencs_hdrs_noqt (model/world
@ -40,7 +41,7 @@ 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 referencecheck referenceablecheck scriptcheck bodypartcheck birthsigncheck spellcheck referencecheck referenceablecheck scriptcheck bodypartcheck
startscriptcheck search searchoperation searchstage pathgridcheck startscriptcheck search searchoperation searchstage pathgridcheck soundgencheck
) )
@ -63,17 +64,18 @@ opencs_units (view/world
table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator table tablesubview scriptsubview util regionmapsubview tablebottombox creator genericcreator
cellcreator referenceablecreator referencecreator scenesubview cellcreator referenceablecreator referencecreator scenesubview
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
dialoguespinbox dialoguespinbox recordbuttonbar tableeditidaction
) )
opencs_units_noqt (view/world opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator physicssystem scripthighlighter idvalidator dialoguecreator idcompletiondelegate
colordelegate dragdroputils
) )
opencs_units (view/widget opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2 scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit
) )
opencs_units (view/render opencs_units (view/render
@ -82,8 +84,8 @@ opencs_units (view/render
) )
opencs_units_noqt (view/render opencs_units_noqt (view/render
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight lighting lightingday lightingnight
lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate lightingbright object cell terrainstorage
) )
opencs_hdrs_noqt (view/render opencs_hdrs_noqt (view/render
@ -152,19 +154,16 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE) set(QT_USE_QTMAIN TRUE)
endif(WIN32) endif(WIN32)
set(BOOST_COMPONENTS system filesystem program_options thread wave) if (DESIRED_QT_VERSION MATCHES 4)
if(WIN32) include(${QT_USE_FILE})
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale) qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
endif(WIN32) qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS}) else()
qt5_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED) qt5_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
include(${QT_USE_FILE}) qt5_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
endif()
qt4_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt4_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt4_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
# for compiled .ui files # for compiled .ui files
include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_BINARY_DIR})
@ -200,17 +199,35 @@ if(APPLE)
endif(APPLE) endif(APPLE)
target_link_libraries(openmw-cs target_link_libraries(openmw-cs
${OENGINE_LIBRARY} ${OPENSCENEGRAPH_LIBRARIES}
${OGRE_LIBRARIES} ${Boost_SYSTEM_LIBRARY}
${OGRE_Overlay_LIBRARIES} ${Boost_FILESYSTEM_LIBRARY}
${OGRE_STATIC_PLUGINS} ${Boost_PROGRAM_OPTIONS_LIBRARY}
${SHINY_LIBRARIES}
${Boost_LIBRARIES}
${BULLET_LIBRARIES}
${QT_LIBRARIES}
components components
) )
if (DESIRED_QT_VERSION MATCHES 4)
target_link_libraries(openmw-cs
${QT_QTGUI_LIBRARY}
${QT_QTCORE_LIBRARY}
${QT_QTNETWORK_LIBRARY}
${QT_QTOPENGL_LIBRARY})
if (WIN32)
target_link_libraries(openmw-cs ${QT_QTMAIN_LIBRARY})
endif()
else()
qt5_use_modules(openmw-cs Widgets Core Network OpenGL)
if (WIN32)
target_link_libraries(Qt5::WinMain)
endif()
endif()
if (WIN32)
target_link_libraries(openmw-cs ${Boost_LOCALE_LIBRARY})
endif()
if(APPLE) if(APPLE)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE) INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
endif() endif()

@ -1,28 +1,25 @@
#include "editor.hpp" #include "editor.hpp"
#include <openengine/bullet/BulletShapeLoader.h>
#include <QApplication> #include <QApplication>
#include <QLocalServer> #include <QLocalServer>
#include <QLocalSocket> #include <QLocalSocket>
#include <QMessageBox> #include <QMessageBox>
#include <OgreRoot.h> #include <components/vfs/manager.hpp>
#include <OgreRenderWindow.h> #include <components/vfs/registerarchives.hpp>
#include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
#include <components/ogreinit/ogreinit.hpp> #include <components/nifosg/nifloader.hpp>
#include <components/nifogre/ogrenifloader.hpp>
#include <components/bsa/resources.hpp>
#include "model/doc/document.hpp" #include "model/doc/document.hpp"
#include "model/world/data.hpp" #include "model/world/data.hpp"
CS::Editor::Editor (OgreInit::OgreInit& ogreInit) #ifdef _WIN32
: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr), #include <Windows.h>
#endif
CS::Editor::Editor ()
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr),
mViewManager (mDocumentManager), mPid(""), mViewManager (mDocumentManager), mPid(""),
mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL) mLock(), mIpcServerName ("org.openmw.OpenCS"), mServer(NULL), mClientSocket(NULL)
{ {
@ -33,16 +30,13 @@ CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
CSMSettings::UserSettings::instance().loadSettings ("opencs.ini"); CSMSettings::UserSettings::instance().loadSettings ("opencs.ini");
mSettings.setModel (CSMSettings::UserSettings::instance()); mSettings.setModel (CSMSettings::UserSettings::instance());
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string()); NifOsg::Loader::setShowMarkers(true);
NifOgre::Loader::setShowMarkers(true);
mOverlaySystem.reset (new CSVRender::OverlaySystem); mVFS.reset(new VFS::Manager(mFsStrict));
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true, VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true);
mFsStrict);
mDocumentManager.listResources(); mDocumentManager.setVFS(mVFS.get());
mNewGame.setLocalData (mLocal); mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal); mFileDialog.setLocalData (mLocal);
@ -81,9 +75,6 @@ CS::Editor::~Editor ()
if(mServer && boost::filesystem::exists(mPid)) if(mServer && boost::filesystem::exists(mPid))
static_cast<void> ( // silence coverity warning static_cast<void> ( // silence coverity warning
remove(mPid.string().c_str())); // ignore any error remove(mPid.string().c_str())); // ignore any error
// cleanup global resources used by OEngine
delete OEngine::Physic::BulletShapeManager::getSingletonPtr();
} }
void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs) void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
@ -95,7 +86,7 @@ void CS::Editor::setupDataFiles (const Files::PathContainer& dataDirs)
} }
} }
std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig() std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfig(bool quiet)
{ {
boost::program_options::variables_map variables; boost::program_options::variables_map variables;
boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options"); boost::program_options::options_description desc("Syntax: openmw-cs <options>\nAllowed options");
@ -115,7 +106,7 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
boost::program_options::notify(variables); boost::program_options::notify(variables);
mCfgMgr.readConfiguration(variables, desc); mCfgMgr.readConfiguration(variables, desc, quiet);
mDocumentManager.setEncoding ( mDocumentManager.setEncoding (
ToUTF8::calculateEncoding (variables["encoding"].as<std::string>())); ToUTF8::calculateEncoding (variables["encoding"].as<std::string>()));
@ -195,6 +186,11 @@ void CS::Editor::cancelCreateGame()
void CS::Editor::createAddon() void CS::Editor::createAddon()
{ {
mStartup.hide(); mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
mFileDialog.showDialog (CSVDoc::ContentAction_New); mFileDialog.showDialog (CSVDoc::ContentAction_New);
} }
@ -215,6 +211,11 @@ void CS::Editor::cancelFileDialog()
void CS::Editor::loadDocument() void CS::Editor::loadDocument()
{ {
mStartup.hide(); mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
mFileDialog.showDialog (CSVDoc::ContentAction_Edit); mFileDialog.showDialog (CSVDoc::ContentAction_Edit);
} }
@ -307,12 +308,12 @@ bool CS::Editor::makeIPCServer()
mServer->close(); mServer->close();
fullPath.remove(QRegExp("dummy$")); fullPath.remove(QRegExp("dummy$"));
fullPath += mIpcServerName; fullPath += mIpcServerName;
if(boost::filesystem::exists(fullPath.toStdString().c_str())) if(boost::filesystem::exists(fullPath.toUtf8().constData()))
{ {
// TODO: compare pid of the current process with that in the file // TODO: compare pid of the current process with that in the file
std::cout << "Detected unclean shutdown." << std::endl; std::cout << "Detected unclean shutdown." << std::endl;
// delete the stale file // delete the stale file
if(remove(fullPath.toStdString().c_str())) if(remove(fullPath.toUtf8().constData()))
std::cerr << "ERROR removing stale connection file" << std::endl; std::cerr << "ERROR removing stale connection file" << std::endl;
} }
} }
@ -354,114 +355,6 @@ int CS::Editor::run()
return QApplication::exec(); return QApplication::exec();
} }
std::auto_ptr<sh::Factory> CS::Editor::setupGraphics()
{
std::string renderer =
#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);
// Create a hidden background window to keep resources
Ogre::NameValuePairList params;
params.insert(std::make_pair("title", ""));
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("hidden", "true"));
#if OGRE_PLATFORM == OGRE_PLATFORM_APPLE
params.insert(std::make_pair("macAPI", "cocoa"));
#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);
hiddenWindow->setActive(false);
sh::OgrePlatform* platform =
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()))
boost::filesystem::create_directories (mCfgMgr.getCachePath());
platform->setCacheFolder (mCfgMgr.getCachePath().string());
std::auto_ptr<sh::Factory> factory (new sh::Factory (platform));
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->setReadSourceCache (true);
factory->setReadMicrocodeCache (true);
factory->setWriteMicrocodeCache (true);
factory->loadAllFiles();
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);
std::string shadows_pssm = mUserSettings.setting("Shader/shadows_pssm", QString("false")).toStdString();
sh::Factory::getInstance().setGlobalSetting ("shadows_pssm", shadows_pssm);
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");
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
return factory;
}
void CS::Editor::documentAdded (CSMDoc::Document *document) void CS::Editor::documentAdded (CSMDoc::Document *document)
{ {
mViewManager.addView (document); mViewManager.addView (document);

@ -11,16 +11,12 @@
#include <QLocalServer> #include <QLocalServer>
#include <QLocalSocket> #include <QLocalSocket>
#include <extern/shiny/Main/Factory.hpp>
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#endif #endif
#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"
@ -30,11 +26,10 @@
#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"
namespace OgreInit namespace VFS
{ {
class OgreInit; class Manager;
} }
namespace CS namespace CS
@ -43,10 +38,11 @@ namespace CS
{ {
Q_OBJECT Q_OBJECT
Nif::Cache mNifCache; // FIXME: should be moved to document, so we can have different resources for each opened project
std::auto_ptr<VFS::Manager> mVFS;
Files::ConfigurationManager mCfgMgr; Files::ConfigurationManager mCfgMgr;
CSMSettings::UserSettings mUserSettings; CSMSettings::UserSettings mUserSettings;
std::auto_ptr<CSVRender::OverlaySystem> mOverlaySystem;
CSMDoc::DocumentManager mDocumentManager; CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager; CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup; CSVDoc::StartupDialogue mStartup;
@ -62,7 +58,7 @@ namespace CS
void setupDataFiles (const Files::PathContainer& dataDirs); void setupDataFiles (const Files::PathContainer& dataDirs);
std::pair<Files::PathContainer, std::vector<std::string> > readConfig(); std::pair<Files::PathContainer, std::vector<std::string> > readConfig(bool quiet=false);
///< \return data paths ///< \return data paths
// not implemented // not implemented
@ -71,7 +67,7 @@ namespace CS
public: public:
Editor (OgreInit::OgreInit& ogreInit); Editor ();
~Editor (); ~Editor ();
bool makeIPCServer(); bool makeIPCServer();
@ -80,9 +76,6 @@ namespace CS
int run(); int run();
///< \return error status ///< \return error status
std::auto_ptr<sh::Factory> setupGraphics();
///< The returned factory must persist at least as long as *this.
private slots: private slots:
void createGame(); void createGame();

@ -9,9 +9,7 @@
#include <QIcon> #include <QIcon>
#include <QMetaType> #include <QMetaType>
#include <extern/shiny/Main/Factory.hpp> #include "model/doc/messages.hpp"
#include <components/ogreinit/ogreinit.hpp>
#include "model/world/universalid.hpp" #include "model/world/universalid.hpp"
@ -48,14 +46,14 @@ int main(int argc, char *argv[])
{ {
try try
{ {
// To allow background thread drawing in OSG
QApplication::setAttribute(Qt::AA_X11InitThreads, true);
Q_INIT_RESOURCE (resources); Q_INIT_RESOURCE (resources);
qRegisterMetaType<std::string> ("std::string"); qRegisterMetaType<std::string> ("std::string");
qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId"); qRegisterMetaType<CSMWorld::UniversalId> ("CSMWorld::UniversalId");
qRegisterMetaType<CSMDoc::Message> ("CSMDoc::Message");
OgreInit::OgreInit ogreInit;
std::auto_ptr<sh::Factory> shinyFactory;
Application application (argc, argv); Application application (argc, argv);
@ -80,15 +78,13 @@ int main(int argc, char *argv[])
application.setWindowIcon (QIcon (":./openmw-cs.png")); application.setWindowIcon (QIcon (":./openmw-cs.png"));
CS::Editor editor (ogreInit); CS::Editor editor;
if(!editor.makeIPCServer()) if(!editor.makeIPCServer())
{ {
editor.connectToIPCServer(); editor.connectToIPCServer();
return 0; return 0;
} }
shinyFactory = editor.setupGraphics();
return editor.run(); return editor.run();
} }
catch (std::exception& e) catch (std::exception& e)

@ -2,6 +2,7 @@
#include <cassert> #include <cassert>
#include <fstream> #include <fstream>
#include <iostream>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
@ -9,8 +10,6 @@
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#endif #endif
#include "../../view/world/physicssystem.hpp"
void CSMDoc::Document::addGmsts() void CSMDoc::Document::addGmsts()
{ {
static const char *gmstFloats[] = static const char *gmstFloats[] =
@ -2245,19 +2244,19 @@ void CSMDoc::Document::createBase()
} }
} }
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration, CSMDoc::Document::Document (const VFS::Manager* vfs, 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, const CSMWorld::ResourcesManager& resourcesManager, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts) const std::vector<std::string>& blacklistedScripts)
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager), : mVFS(vfs), mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
mTools (*this), mTools (*this),
mProjectPath ((configuration.getUserDataPath() / "projects") / mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")), (savePath.filename().string() + ".project")),
mSavingOperation (*this, mProjectPath, encoding), mSavingOperation (*this, mProjectPath, encoding),
mSaving (&mSavingOperation), mSaving (&mSavingOperation),
mResDir(resDir), mResDir(resDir),
mRunner (mProjectPath), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>()) mRunner (mProjectPath), mIdCompletionManager(mData)
{ {
if (mContentFiles.empty()) if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence"); throw std::runtime_error ("Empty content file sequence");
@ -2271,7 +2270,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (boost::filesystem::exists (customFiltersPath)) if (boost::filesystem::exists (customFiltersPath))
{ {
destination << std::ifstream(customFiltersPath.c_str(), std::ios::binary).rdbuf(); destination << std::ifstream(customFiltersPath.string().c_str(), std::ios::binary).rdbuf();
} }
else else
{ {
@ -2281,9 +2280,6 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (mNew) if (mNew)
{ {
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1) if (mContentFiles.size()==1)
createBase(); createBase();
} }
@ -2303,8 +2299,8 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool))); connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect ( connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), &mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); this, SLOT (reportMessage (const CSMDoc::Message&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged())); connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
} }
@ -2313,6 +2309,11 @@ CSMDoc::Document::~Document()
{ {
} }
const VFS::Manager *CSMDoc::Document::getVFS() const
{
return mVFS;
}
QUndoStack& CSMDoc::Document::getUndoStack() QUndoStack& CSMDoc::Document::getUndoStack()
{ {
return mUndoStack; return mUndoStack;
@ -2368,9 +2369,9 @@ void CSMDoc::Document::save()
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
CSMWorld::UniversalId CSMDoc::Document::verify() CSMWorld::UniversalId CSMDoc::Document::verify (const CSMWorld::UniversalId& reportId)
{ {
CSMWorld::UniversalId id = mTools.runVerifier(); CSMWorld::UniversalId id = mTools.runVerifier (reportId);
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
return id; return id;
} }
@ -2400,11 +2401,10 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
emit stateChanged (getState(), this); emit stateChanged (getState(), this);
} }
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
const std::string& hint, int type)
{ {
/// \todo find a better way to get these messages to the user. /// \todo find a better way to get these messages to the user.
std::cout << message << std::endl; std::cout << message.mMessage << std::endl;
} }
void CSMDoc::Document::operationDone (int type, bool failed) void CSMDoc::Document::operationDone (int type, bool failed)
@ -2481,10 +2481,7 @@ void CSMDoc::Document::progress (int current, int max, int type)
emit progress (current, max, type, 1, this); emit progress (current, max, type, 1, this);
} }
boost::shared_ptr<CSVWorld::PhysicsSystem> CSMDoc::Document::getPhysics () CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager()
{ {
if(!mPhysics) return mIdCompletionManager;
mPhysics = boost::shared_ptr<CSVWorld::PhysicsSystem> (new CSVWorld::PhysicsSystem());
return mPhysics;
} }

@ -13,6 +13,7 @@
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
#include "../world/data.hpp" #include "../world/data.hpp"
#include "../world/idcompletionmanager.hpp"
#include "../tools/tools.hpp" #include "../tools/tools.hpp"
@ -24,6 +25,12 @@
class QAbstractItemModel; class QAbstractItemModel;
namespace VFS
{
class Manager;
}
namespace ESM namespace ESM
{ {
struct GameSetting; struct GameSetting;
@ -41,11 +48,6 @@ namespace CSMWorld
class ResourcesManager; class ResourcesManager;
} }
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSMDoc namespace CSMDoc
{ {
class Document : public QObject class Document : public QObject
@ -54,6 +56,7 @@ namespace CSMDoc
private: private:
const VFS::Manager* mVFS;
boost::filesystem::path mSavePath; boost::filesystem::path mSavePath;
std::vector<boost::filesystem::path> mContentFiles; std::vector<boost::filesystem::path> mContentFiles;
bool mNew; bool mNew;
@ -65,7 +68,8 @@ namespace CSMDoc
boost::filesystem::path mResDir; boost::filesystem::path mResDir;
Blacklist mBlacklist; Blacklist mBlacklist;
Runner mRunner; Runner mRunner;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
CSMWorld::IdCompletionManager mIdCompletionManager;
// 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.
@ -93,7 +97,7 @@ namespace CSMDoc
public: public:
Document (const Files::ConfigurationManager& configuration, Document (const VFS::Manager* vfs, 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, const CSMWorld::ResourcesManager& resourcesManager, ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
@ -101,6 +105,8 @@ namespace CSMDoc
~Document(); ~Document();
const VFS::Manager* getVFS() const;
QUndoStack& getUndoStack(); QUndoStack& getUndoStack();
int getState() const; int getState() const;
@ -118,7 +124,7 @@ namespace CSMDoc
void save(); void save();
CSMWorld::UniversalId verify(); CSMWorld::UniversalId verify (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
CSMWorld::UniversalId newSearch(); CSMWorld::UniversalId newSearch();
@ -142,7 +148,7 @@ namespace CSMDoc
QTextDocument *getRunLog(); QTextDocument *getRunLog();
boost::shared_ptr<CSVWorld::PhysicsSystem> getPhysics(); CSMWorld::IdCompletionManager &getIdCompletionManager();
signals: signals:
@ -154,8 +160,7 @@ namespace CSMDoc
void modificationStateChanged (bool clean); void modificationStateChanged (bool clean);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMDoc::Message& message, int type);
const std::string& hint, int type);
void operationDone (int type, bool failed); void operationDone (int type, bool failed);

@ -13,7 +13,7 @@
#include "document.hpp" #include "document.hpp"
CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration) CSMDoc::DocumentManager::DocumentManager (const Files::ConfigurationManager& configuration)
: mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252) : mConfiguration (configuration), mEncoding (ToUTF8::WINDOWS_1252), mVFS(NULL)
{ {
boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects"; boost::filesystem::path projectPath = configuration.getUserDataPath() / "projects";
@ -57,7 +57,7 @@ bool CSMDoc::DocumentManager::isEmpty()
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, mResourcesManager, mBlacklistedScripts); Document *document = new Document (mVFS, mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
mDocuments.push_back (document); mDocuments.push_back (document);
@ -95,11 +95,6 @@ void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector<std::stri
mBlacklistedScripts = 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);
@ -113,3 +108,9 @@ void CSMDoc::DocumentManager::documentNotLoaded (Document *document, const std::
if (error.empty()) // do not remove the document yet, if we have an error if (error.empty()) // do not remove the document yet, if we have an error
removeDocument (document); removeDocument (document);
} }
void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs)
{
mResourcesManager.setVFS(vfs);
mVFS = vfs;
}

@ -15,6 +15,11 @@
#include "loader.hpp" #include "loader.hpp"
namespace VFS
{
class Manager;
}
namespace Files namespace Files
{ {
struct ConfigurationManager; struct ConfigurationManager;
@ -35,6 +40,7 @@ namespace CSMDoc
ToUTF8::FromType mEncoding; ToUTF8::FromType mEncoding;
CSMWorld::ResourcesManager mResourcesManager; CSMWorld::ResourcesManager mResourcesManager;
std::vector<std::string> mBlacklistedScripts; std::vector<std::string> mBlacklistedScripts;
const VFS::Manager* mVFS;
DocumentManager (const DocumentManager&); DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&); DocumentManager& operator= (const DocumentManager&);
@ -56,8 +62,7 @@ namespace CSMDoc
void setBlacklistedScripts (const std::vector<std::string>& scriptIds); void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
/// Ask OGRE for a list of available resources. void setVFS(const VFS::Manager* vfs);
void listResources();
bool isEmpty(); bool isEmpty();

@ -52,7 +52,7 @@ void CSMDoc::Loader::load()
{ {
if (iter->second.mRecordsLeft) if (iter->second.mRecordsLeft)
{ {
CSMDoc::Messages messages; Messages messages (Message::Severity_Error);
for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals for (int i=0; i<batchingSize; ++i) // do not flood the system with update signals
if (document->getData().continueLoading (messages)) if (document->getData().continueLoading (messages))
{ {
@ -68,7 +68,7 @@ void CSMDoc::Loader::load()
for (CSMDoc::Messages::Iterator iter (messages.begin()); for (CSMDoc::Messages::Iterator iter (messages.begin());
iter!=messages.end(); ++iter) iter!=messages.end(); ++iter)
{ {
document->getReport (log)->add (iter->mId, iter->mMessage); document->getReport (log)->add (*iter);
emit loadMessage (document, iter->mMessage); emit loadMessage (document, iter->mMessage);
} }
} }

@ -1,15 +1,25 @@
#include "messages.hpp" #include "messages.hpp"
CSMDoc::Message::Message() {}
CSMDoc::Message::Message (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, Severity severity)
: mId (id), mMessage (message), mHint (hint), mSeverity (severity)
{}
CSMDoc::Messages::Messages (Message::Severity default_)
: mDefault (default_)
{}
void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message, void CSMDoc::Messages::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint) const std::string& hint, Message::Severity severity)
{ {
Message data; if (severity==Message::Severity_Default)
data.mId = id; severity = mDefault;
data.mMessage = message;
data.mHint = hint; mMessages.push_back (Message (id, message, hint, severity));
mMessages.push_back (data);
} }
void CSMDoc::Messages::push_back (const std::pair<CSMWorld::UniversalId, std::string>& data) void CSMDoc::Messages::push_back (const std::pair<CSMWorld::UniversalId, std::string>& data)

@ -4,20 +4,41 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <QMetaType>
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
namespace CSMDoc namespace CSMDoc
{ {
struct Message
{
enum Severity
{
Severity_Info = 0, // no problem
Severity_Warning = 1, // a potential problem, but we are probably fine
Severity_Error = 2, // an error; we are not fine
Severity_SeriousError = 3, // an error so bad we can't even be sure if we are
// reporting it correctly
Severity_Default = 4
};
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
Severity mSeverity;
Message();
Message (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, Severity severity);
};
class Messages class Messages
{ {
public: public:
struct Message // \deprecated Use CSMDoc::Message directly instead.
{ typedef CSMDoc::Message Message;
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
typedef std::vector<Message> Collection; typedef std::vector<Message> Collection;
@ -26,11 +47,15 @@ namespace CSMDoc
private: private:
Collection mMessages; Collection mMessages;
Message::Severity mDefault;
public: public:
Messages (Message::Severity default_);
void add (const CSMWorld::UniversalId& id, const std::string& message, void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = ""); const std::string& hint = "",
Message::Severity severity = Message::Severity_Default);
/// \deprecated Use add instead. /// \deprecated Use add instead.
void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data); void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data);
@ -41,4 +66,6 @@ namespace CSMDoc
}; };
} }
Q_DECLARE_METATYPE (CSMDoc::Message)
#endif #endif

@ -7,6 +7,7 @@
#include <QTimer> #include <QTimer>
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
#include "../settings/usersettings.hpp"
#include "state.hpp" #include "state.hpp"
#include "stage.hpp" #include "stage.hpp"
@ -23,13 +24,17 @@ void CSMDoc::Operation::prepareStages()
{ {
iter->second = iter->first->setup(); iter->second = iter->first->setup();
mTotalSteps += iter->second; mTotalSteps += iter->second;
for (std::map<QString, QStringList>::const_iterator iter2 (mSettings.begin()); iter2!=mSettings.end(); ++iter2)
iter->first->updateUserSetting (iter2->first, iter2->second);
} }
} }
CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways) CSMDoc::Operation::Operation (int type, bool ordered, bool finalAlways)
: mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()), : mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()),
mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered), mCurrentStep(0), mCurrentStepTotal(0), mTotalSteps(0), mOrdered (ordered),
mFinalAlways (finalAlways), mError(false), mConnected (false) mFinalAlways (finalAlways), mError(false), mConnected (false), mPrepared (false),
mDefaultSeverity (Message::Severity_Error)
{ {
mTimer = new QTimer (this); mTimer = new QTimer (this);
} }
@ -49,8 +54,8 @@ void CSMDoc::Operation::run()
connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage())); connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage()));
mConnected = true; mConnected = true;
} }
prepareStages(); mPrepared = false;
mTimer->start (0); mTimer->start (0);
} }
@ -60,6 +65,19 @@ void CSMDoc::Operation::appendStage (Stage *stage)
mStages.push_back (std::make_pair (stage, 0)); mStages.push_back (std::make_pair (stage, 0));
} }
void CSMDoc::Operation::configureSettings (const std::vector<QString>& settings)
{
for (std::vector<QString>::const_iterator iter (settings.begin()); iter!=settings.end(); ++iter)
{
mSettings.insert (std::make_pair (*iter, CSMSettings::UserSettings::instance().definitions (*iter)));
}
}
void CSMDoc::Operation::setDefaultSeverity (Message::Severity severity)
{
mDefaultSeverity = severity;
}
bool CSMDoc::Operation::hasError() const bool CSMDoc::Operation::hasError() const
{ {
return mError; return mError;
@ -84,9 +102,23 @@ void CSMDoc::Operation::abort()
mCurrentStage = mStages.end(); mCurrentStage = mStages.end();
} }
void CSMDoc::Operation::updateUserSetting (const QString& name, const QStringList& value)
{
std::map<QString, QStringList>::iterator iter = mSettings.find (name);
if (iter!=mSettings.end())
iter->second = value;
}
void CSMDoc::Operation::executeStage() void CSMDoc::Operation::executeStage()
{ {
Messages messages; if (!mPrepared)
{
prepareStages();
mPrepared = true;
}
Messages messages (mDefaultSeverity);
while (mCurrentStage!=mStages.end()) while (mCurrentStage!=mStages.end())
{ {
@ -103,7 +135,7 @@ void CSMDoc::Operation::executeStage()
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
emit reportMessage (CSMWorld::UniversalId(), e.what(), "", mType); emit reportMessage (Message (CSMWorld::UniversalId(), e.what(), "", Message::Severity_SeriousError), mType);
abort(); abort();
} }
@ -115,7 +147,7 @@ void CSMDoc::Operation::executeStage()
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType); emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter) for (Messages::Iterator iter (messages.begin()); iter!=messages.end(); ++iter)
emit reportMessage (iter->mId, iter->mMessage, iter->mHint, mType); emit reportMessage (*iter, mType);
if (mCurrentStage==mStages.end()) if (mCurrentStage==mStages.end())
operationDone(); operationDone();

@ -2,9 +2,13 @@
#define CSM_DOC_OPERATION_H #define CSM_DOC_OPERATION_H
#include <vector> #include <vector>
#include <map>
#include <QObject> #include <QObject>
#include <QTimer> #include <QTimer>
#include <QStringList>
#include "messages.hpp"
namespace CSMWorld namespace CSMWorld
{ {
@ -30,6 +34,9 @@ namespace CSMDoc
bool mError; bool mError;
bool mConnected; bool mConnected;
QTimer *mTimer; QTimer *mTimer;
std::map<QString, QStringList> mSettings;
bool mPrepared;
Message::Severity mDefaultSeverity;
void prepareStages(); void prepareStages();
@ -46,14 +53,21 @@ namespace CSMDoc
/// ///
/// \attention Do no call this function while this Operation is running. /// \attention Do no call this function while this Operation is running.
/// Specify settings to be passed on to stages.
///
/// \attention Do no call this function while this Operation is running.
void configureSettings (const std::vector<QString>& settings);
/// \attention Do no call this function while this Operation is running.
void setDefaultSeverity (Message::Severity severity);
bool hasError() const; bool hasError() const;
signals: signals:
void progress (int current, int max, int type); void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMDoc::Message& message, int type);
const std::string& hint, int type);
void done (int type, bool failed); void done (int type, bool failed);
@ -63,6 +77,8 @@ namespace CSMDoc
void run(); void run();
void updateUserSetting (const QString& name, const QStringList& value);
private slots: private slots:
void executeStage(); void executeStage();

@ -1,6 +1,8 @@
#include "operationholder.hpp" #include "operationholder.hpp"
#include "../settings/usersettings.hpp"
#include "operation.hpp" #include "operation.hpp"
CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false) CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false)
@ -19,8 +21,8 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
this, SIGNAL (progress (int, int, int))); this, SIGNAL (progress (int, int, int)));
connect ( connect (
mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), mOperation, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int))); this, SIGNAL (reportMessage (const CSMDoc::Message&, int)));
connect ( connect (
mOperation, SIGNAL (done (int, bool)), mOperation, SIGNAL (done (int, bool)),
@ -29,6 +31,9 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort())); connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort()));
connect (&mThread, SIGNAL (started()), mOperation, SLOT (run())); connect (&mThread, SIGNAL (started()), mOperation, SLOT (run()));
connect (&CSMSettings::UserSettings::instance(), SIGNAL (userSettingUpdated (const QString&, const QStringList&)),
mOperation, SLOT (updateUserSetting (const QString&, const QStringList&)));
} }
bool CSMDoc::OperationHolder::isRunning() const bool CSMDoc::OperationHolder::isRunning() const

@ -4,6 +4,8 @@
#include <QObject> #include <QObject>
#include <QThread> #include <QThread>
#include "messages.hpp"
namespace CSMWorld namespace CSMWorld
{ {
class UniversalId; class UniversalId;
@ -44,8 +46,7 @@ namespace CSMDoc
void progress (int current, int max, int type); void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message, void reportMessage (const CSMDoc::Message& message, int type);
const std::string& hint, int type);
void done (int type, bool failed); void done (int type, bool failed);

@ -53,18 +53,16 @@ void CSMDoc::WriteHeaderStage::perform (int stage, Messages& messages)
mState.getWriter().clearMaster(); mState.getWriter().clearMaster();
mState.getWriter().setFormat (0);
if (mSimple) if (mSimple)
{ {
mState.getWriter().setAuthor (""); mState.getWriter().setAuthor ("");
mState.getWriter().setDescription (""); mState.getWriter().setDescription ("");
mState.getWriter().setRecordCount (0); mState.getWriter().setRecordCount (0);
mState.getWriter().setFormat (ESM::Header::CurrentFormat);
} }
else else
{ {
mState.getWriter().setAuthor (mDocument.getData().getAuthor()); mDocument.getData().getMetaData().save (mState.getWriter());
mState.getWriter().setDescription (mDocument.getData().getDescription());
mState.getWriter().setRecordCount ( mState.getWriter().setRecordCount (
mDocument.getData().count (CSMWorld::RecordBase::State_Modified) + mDocument.getData().count (CSMWorld::RecordBase::State_Modified) +
mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) + mDocument.getData().count (CSMWorld::RecordBase::State_ModifiedOnly) +

@ -2,3 +2,5 @@
#include "stage.hpp" #include "stage.hpp"
CSMDoc::Stage::~Stage() {} CSMDoc::Stage::~Stage() {}
void CSMDoc::Stage::updateUserSetting (const QString& name, const QStringList& value) {}

@ -8,6 +8,8 @@
#include "messages.hpp" #include "messages.hpp"
class QString;
namespace CSMDoc namespace CSMDoc
{ {
class Stage class Stage
@ -21,6 +23,9 @@ namespace CSMDoc
virtual void perform (int stage, Messages& messages) = 0; virtual void perform (int stage, Messages& messages) = 0;
///< Messages resulting from this stage will be appended to \a messages. ///< Messages resulting from this stage will be appended to \a messages.
/// Default-implementation: ignore
virtual void updateUserSetting (const QString& name, const QStringList& value);
}; };
} }

@ -12,8 +12,6 @@
#include <QTextCodec> #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
*/ */
@ -44,13 +42,9 @@ CSMSettings::UserSettings *CSMSettings::UserSettings::sUserSettingsInstance = 0;
void CSMSettings::UserSettings::buildSettingModelDefaults() void CSMSettings::UserSettings::buildSettingModelDefaults()
{ {
QString section; /*
declareSection ("3d-render", "3D Rendering"); declareSection ("3d-render", "3D Rendering");
{ {
Setting *shaders = createSetting (Type_CheckBox, "shaders", "Enable Shaders");
shaders->setDefaultValue ("true");
Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance"); Setting *farClipDist = createSetting (Type_DoubleSpinBox, "far-clip-distance", "Far clipping distance");
farClipDist->setDefaultValue (300000); farClipDist->setDefaultValue (300000);
farClipDist->setRange (0, 1000000); farClipDist->setRange (0, 1000000);
@ -62,23 +56,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
<< defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16"); << defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16");
antialiasing->setDefaultValue (defaultValue); antialiasing->setDefaultValue (defaultValue);
} }
*/
declareSection ("3d-render-adv", "3D Rendering (Advanced)"); /*
{
Setting *numLights = createSetting (Type_SpinBox, "num_lights",
"Number of lights per pass");
numLights->setDefaultValue (8);
numLights->setRange (1, 100);
}
declareSection ("scene-input", "Scene Input"); declareSection ("scene-input", "Scene Input");
{ {
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", Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor",
"Fast movement factor"); "Fast movement factor");
fastFactor->setDefaultValue (4); fastFactor->setDefaultValue (4);
@ -86,6 +68,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
fastFactor->setToolTip ( fastFactor->setToolTip (
"Factor by which movement is speed up while the shift key is held down."); "Factor by which movement is speed up while the shift key is held down.");
} }
*/
declareSection ("window", "Window"); declareSection ("window", "Window");
{ {
@ -234,6 +217,47 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
jumpToAdded->setDeclaredValues (jumpValues); jumpToAdded->setDeclaredValues (jumpValues);
} }
declareSection ("report-input", "Report Input");
{
QString none ("None");
QString edit ("Edit");
QString remove ("Remove");
QString editAndRemove ("Edit And Remove");
QStringList values;
values << none << edit << remove << editAndRemove;
QString toolTip = "<ul>"
"<li>None</li>"
"<li>Edit: Open a table or dialogue suitable for addressing the listed report</li>"
"<li>Remove: Remove the report from the report table</li>"
"<li>Edit and Remove: Open a table or dialogue suitable for addressing the listed report, then remove the report from the report table</li>"
"</ul>";
Setting *doubleClick = createSetting (Type_ComboBox, "double", "Double Click");
doubleClick->setDeclaredValues (values);
doubleClick->setDefaultValue (edit);
doubleClick->setToolTip ("Action on double click in report table:<p>" + toolTip);
Setting *shiftDoubleClick = createSetting (Type_ComboBox, "double-s",
"Shift Double Click");
shiftDoubleClick->setDeclaredValues (values);
shiftDoubleClick->setDefaultValue (remove);
shiftDoubleClick->setToolTip ("Action on shift double click in report table:<p>" + toolTip);
Setting *ctrlDoubleClick = createSetting (Type_ComboBox, "double-c",
"Control Double Click");
ctrlDoubleClick->setDeclaredValues (values);
ctrlDoubleClick->setDefaultValue (editAndRemove);
ctrlDoubleClick->setToolTip ("Action on control double click in report table:<p>" + toolTip);
Setting *shiftCtrlDoubleClick = createSetting (Type_ComboBox, "double-sc",
"Shift Control Double Click");
shiftCtrlDoubleClick->setDeclaredValues (values);
shiftCtrlDoubleClick->setDefaultValue (none);
shiftCtrlDoubleClick->setToolTip ("Action on shift control double click in report table:<p>" + toolTip);
}
declareSection ("search", "Search & Replace"); declareSection ("search", "Search & Replace");
{ {
Setting *before = createSetting (Type_SpinBox, "char-before", Setting *before = createSetting (Type_SpinBox, "char-before",
@ -252,7 +276,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
autoDelete->setDefaultValue ("true"); autoDelete->setDefaultValue ("true");
} }
declareSection ("script-editor", "Script Editor"); declareSection ("script-editor", "Scripts");
{ {
Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers"); Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers");
lineNum->setDefaultValue ("true"); lineNum->setDefaultValue ("true");
@ -271,6 +295,21 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
"\nA name from the list of colors defined in the list of SVG color keyword names." "\nA name from the list of colors defined in the list of SVG color keyword names."
"\nX11 color names may also work."; "\nX11 color names may also work.";
QString modeNormal ("Normal");
QStringList modes;
modes << "Ignore" << modeNormal << "Strict";
Setting *warnings = createSetting (Type_ComboBox, "warnings",
"Warning Mode");
warnings->setDeclaredValues (modes);
warnings->setDefaultValue (modeNormal);
warnings->setToolTip ("<ul>How to handle warning messages during compilation:<p>"
"<li>Ignore: Do not report warning</li>"
"<li>Normal: Report warning as a warning</li>"
"<li>Strict: Promote warning to an error</li>"
"</ul>");
Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int"); Setting *formatInt = createSetting (Type_LineEdit, "colour-int", "Highlight Colour: Int");
formatInt->setDefaultValues (QStringList() << "Dark magenta"); formatInt->setDefaultValues (QStringList() << "Dark magenta");
formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip); formatInt->setToolTip ("(Default: Green) Use one of the following formats:" + tooltip);
@ -300,6 +339,14 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip); formatId->setToolTip ("(Default: Blue) Use one of the following formats:" + tooltip);
} }
declareSection ("general-input", "General Input");
{
Setting *cycle = createSetting (Type_CheckBox, "cycle", "Cyclic next/previous");
cycle->setDefaultValue ("false");
cycle->setToolTip ("When using next/previous functions at the last/first item of a "
"list go to the first/last item");
}
{ {
/****************************************************************** /******************************************************************
* There are three types of values: * There are three types of values:
@ -562,15 +609,6 @@ 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);
} }

@ -30,9 +30,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
// check the number of pathgrid points // check the number of pathgrid points
if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size())) if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
messages.push_back (std::make_pair (id, pathgrid.mId + " has less points than expected")); messages.add (id, pathgrid.mId + " has less points than expected", "", CSMDoc::Message::Severity_Error);
else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size())) else if (pathgrid.mData.mS2 > static_cast<int>(pathgrid.mPoints.size()))
messages.push_back (std::make_pair (id, pathgrid.mId + " has more points than expected")); messages.add (id, pathgrid.mId + " has more points than expected", "", CSMDoc::Message::Severity_Error);
std::vector<CSMTools::Point> pointList(pathgrid.mPoints.size()); std::vector<CSMTools::Point> pointList(pathgrid.mPoints.size());
std::vector<int> duplList; std::vector<int> duplList;
@ -51,7 +51,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
std::ostringstream ss; std::ostringstream ss;
ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0 ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0
<< " and " << pathgrid.mEdges[i].mV1; << " and " << pathgrid.mEdges[i].mV1;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
break; break;
} }
} }
@ -64,7 +64,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0; ss << " has an edge connecting a non-existent point " << pathgrid.mEdges[i].mV0;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
} }
@ -75,13 +75,13 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has has less edges than expected for point " << i; ss << " has has less edges than expected for point " << i;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum) else if (pathgrid.mPoints[i].mConnectionNum < pointList[i].mConnectionNum)
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has has more edges than expected for point " << i; ss << " has has more edges than expected for point " << i;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
// check that edges are bidirectional // check that edges are bidirectional
@ -101,7 +101,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{ {
std::ostringstream ss; std::ostringstream ss;
ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j]; ss << " has a missing edge between points " << i << " and " << pointList[i].mOtherIndex[j];
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Error);
} }
} }
@ -124,7 +124,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX << ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY << ", y=" << pathgrid.mPoints[i].mY
<< ", z=" << pathgrid.mPoints[i].mZ; << ", z=" << pathgrid.mPoints[i].mZ;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning);
duplList.push_back(i); duplList.push_back(i);
break; break;
@ -143,7 +143,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX << ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY << ", y=" << pathgrid.mPoints[i].mY
<< ", z=" << pathgrid.mPoints[i].mZ; << ", z=" << pathgrid.mPoints[i].mZ;
messages.push_back (std::make_pair (id, pathgrid.mId + ss.str())); messages.add (id, pathgrid.mId + ss.str(), "", CSMDoc::Message::Severity_Warning);
} }
} }

@ -648,7 +648,7 @@ void CSMTools::ReferenceableCheckStage::npcCheck (
if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated if (npc.mNpdtType == ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS) //12 = autocalculated
{ {
if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0008 = autocalculated flag if ((npc.mFlags & ESM::NPC::Autocalc) == 0) //0x0010 = autocalculated flag
{ {
messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend? messages.push_back (std::make_pair (id, npc.mId + " mNpdtType or flags mismatch!")); //should not happend?
return; return;

@ -6,24 +6,18 @@
#include "../world/columns.hpp" #include "../world/columns.hpp"
CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message, CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn)
const std::string& hint) : mColumnField (-1), mColumnSeverity (-1)
: mId (id), mMessage (message), mHint (hint)
{}
CSMTools::ReportModel::ReportModel (bool fieldColumn)
{ {
int index = 3;
if (severityColumn)
mColumnSeverity = index++;
if (fieldColumn) if (fieldColumn)
{ mColumnField = index++;
mColumnField = 3;
mColumnDescription = 4;
}
else
{
mColumnDescription = 3;
mColumnField = -1; mColumnDescription = index;
}
} }
int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const int CSMTools::ReportModel::rowCount (const QModelIndex & parent) const
@ -88,6 +82,18 @@ QVariant CSMTools::ReportModel::data (const QModelIndex & index, int role) const
return QString::fromUtf8 (field.c_str()); return QString::fromUtf8 (field.c_str());
} }
if (index.column()==mColumnSeverity)
{
switch (mRows.at (index.row()).mSeverity)
{
case CSMDoc::Message::Severity_Info: return "Information";
case CSMDoc::Message::Severity_Warning: return "Warning";
case CSMDoc::Message::Severity_Error: return "Error";
case CSMDoc::Message::Severity_SeriousError: return "Serious Error";
case CSMDoc::Message::Severity_Default: break;
}
}
return QVariant(); return QVariant();
} }
@ -112,6 +118,9 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta
if (section==mColumnField) if (section==mColumnField)
return "Field"; return "Field";
if (section==mColumnSeverity)
return "Severity";
return "-"; return "-";
} }
@ -132,19 +141,18 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true; return true;
} }
void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message, void CSMTools::ReportModel::add (const CSMDoc::Message& message)
const std::string& hint)
{ {
beginInsertRows (QModelIndex(), mRows.size(), mRows.size()); beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (Line (id, message, hint)); mRows.push_back (message);
endInsertRows(); endInsertRows();
} }
void CSMTools::ReportModel::flagAsReplaced (int index) void CSMTools::ReportModel::flagAsReplaced (int index)
{ {
Line& line = mRows.at (index); CSMDoc::Message& line = mRows.at (index);
std::string hint = line.mHint; std::string hint = line.mHint;
if (hint.empty() || hint[0]!='R') if (hint.empty() || hint[0]!='R')
@ -176,3 +184,16 @@ void CSMTools::ReportModel::clear()
endRemoveRows(); endRemoveRows();
} }
} }
int CSMTools::ReportModel::countErrors() const
{
int count = 0;
for (std::vector<CSMDoc::Messages::Message>::const_iterator iter (mRows.begin());
iter!=mRows.end(); ++iter)
if (iter->mSeverity==CSMDoc::Message::Severity_Error ||
iter->mSeverity==CSMDoc::Message::Severity_SeriousError)
++count;
return count;
}

@ -6,6 +6,8 @@
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include "../doc/messages.hpp"
#include "../world/universalid.hpp" #include "../world/universalid.hpp"
namespace CSMTools namespace CSMTools
@ -14,17 +16,7 @@ namespace CSMTools
{ {
Q_OBJECT Q_OBJECT
struct Line std::vector<CSMDoc::Messages::Message> mRows;
{
Line (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint);
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
std::vector<Line> mRows;
// Fixed columns // Fixed columns
enum Columns enum Columns
@ -35,10 +27,11 @@ namespace CSMTools
// Configurable columns // Configurable columns
int mColumnDescription; int mColumnDescription;
int mColumnField; int mColumnField;
int mColumnSeverity;
public: public:
ReportModel (bool fieldColumn = false); ReportModel (bool fieldColumn = false, bool severityColumn = true);
virtual int rowCount (const QModelIndex & parent = QModelIndex()) const; virtual int rowCount (const QModelIndex & parent = QModelIndex()) const;
@ -50,8 +43,7 @@ namespace CSMTools
virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex()); virtual bool removeRows (int row, int count, const QModelIndex& parent = QModelIndex());
void add (const CSMWorld::UniversalId& id, const std::string& message, void add (const CSMDoc::Message& message);
const std::string& hint = "");
void flagAsReplaced (int index); void flagAsReplaced (int index);
@ -60,6 +52,9 @@ namespace CSMTools
std::string getHint (int row) const; std::string getHint (int row) const;
void clear(); void clear();
// Return number of messages with Error or SeriousError severity.
int countErrors() const;
}; };
} }

@ -11,6 +11,17 @@
#include "../world/data.hpp" #include "../world/data.hpp"
CSMDoc::Message::Severity CSMTools::ScriptCheckStage::getSeverity (Type type)
{
switch (type)
{
case WarningMessage: return CSMDoc::Message::Severity_Warning;
case ErrorMessage: return CSMDoc::Message::Severity_Error;
}
return CSMDoc::Message::Severity_SeriousError;
}
void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc, void CSMTools::ScriptCheckStage::report (const std::string& message, const Compiler::TokenLoc& loc,
Type type) Type type)
{ {
@ -18,11 +29,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
if (type==ErrorMessage)
stream << "error ";
else
stream << "warning ";
stream stream
<< "script " << mFile << "script " << mFile
<< ", line " << loc.mLine << ", column " << loc.mColumn << ", line " << loc.mLine << ", column " << loc.mColumn
@ -32,19 +38,21 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
hintStream << "l:" << loc.mLine << " " << loc.mColumn; hintStream << "l:" << loc.mLine << " " << loc.mColumn;
mMessages->add (id, stream.str(), hintStream.str()); mMessages->add (id, stream.str(), hintStream.str(), getSeverity (type));
} }
void CSMTools::ScriptCheckStage::report (const std::string& message, Type type) void CSMTools::ScriptCheckStage::report (const std::string& message, Type type)
{ {
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
mMessages->push_back (std::make_pair (id, std::ostringstream stream;
(type==ErrorMessage ? "error: " : "warning: ") + message)); stream << "script " << mFile << ": " << message;
mMessages->add (id, stream.str(), "", getSeverity (type));
} }
CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document) CSMTools::ScriptCheckStage::ScriptCheckStage (const CSMDoc::Document& document)
: mDocument (document), mContext (document.getData()), mMessages (0) : mDocument (document), mContext (document.getData()), mMessages (0), mWarningMode (Mode_Ignore)
{ {
/// \todo add an option to configure warning mode /// \todo add an option to configure warning mode
setWarningsMode (0); setWarningsMode (0);
@ -58,6 +66,7 @@ int CSMTools::ScriptCheckStage::setup()
mContext.clear(); mContext.clear();
mMessages = 0; mMessages = 0;
mId.clear(); mId.clear();
Compiler::ErrorHandler::reset();
return mDocument.getData().getScripts().getSize(); return mDocument.getData().getScripts().getSize();
} }
@ -72,6 +81,13 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
mMessages = &messages; mMessages = &messages;
switch (mWarningMode)
{
case Mode_Ignore: setWarningsMode (0); break;
case Mode_Normal: setWarningsMode (1); break;
case Mode_Strict: setWarningsMode (2); break;
}
try try
{ {
const CSMWorld::Data& data = mDocument.getData(); const CSMWorld::Data& data = mDocument.getData();
@ -93,9 +109,24 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
{ {
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
messages.push_back (std::make_pair (id, std::ostringstream stream;
std::string ("Critical compile error: ") + error.what())); stream << "script " << mFile << ": " << error.what();
messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError);
} }
mMessages = 0; mMessages = 0;
} }
void CSMTools::ScriptCheckStage::updateUserSetting (const QString& name, const QStringList& value)
{
if (name=="script-editor/warnings" && !value.isEmpty())
{
if (value.at (0)=="Ignore")
mWarningMode = Mode_Ignore;
else if (value.at (0)=="Normal")
mWarningMode = Mode_Normal;
else if (value.at (0)=="Strict")
mWarningMode = Mode_Strict;
}
}

@ -18,13 +18,23 @@ 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
{ {
enum WarningMode
{
Mode_Ignore,
Mode_Normal,
Mode_Strict
};
const CSMDoc::Document& mDocument; const CSMDoc::Document& mDocument;
Compiler::Extensions mExtensions; Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext; CSMWorld::ScriptContext mContext;
std::string mId; std::string mId;
std::string mFile; std::string mFile;
CSMDoc::Messages *mMessages; CSMDoc::Messages *mMessages;
WarningMode mWarningMode;
CSMDoc::Message::Severity getSeverity (Type type);
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type); virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user. ///< Report error to the user.
@ -40,6 +50,8 @@ namespace CSMTools
virtual void perform (int stage, CSMDoc::Messages& messages); virtual void perform (int stage, CSMDoc::Messages& messages);
///< Messages resulting from this tage will be appended to \a messages. ///< Messages resulting from this tage will be appended to \a messages.
virtual void updateUserSetting (const QString& name, const QStringList& value);
}; };
} }

@ -280,7 +280,7 @@ void CSMTools::Search::replace (CSMDoc::Document& document, CSMWorld::IdTableBas
bool CSMTools::Search::verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model, bool CSMTools::Search::verify (CSMDoc::Document& document, CSMWorld::IdTableBase *model,
const CSMWorld::UniversalId& id, const std::string& messageHint) const const CSMWorld::UniversalId& id, const std::string& messageHint) const
{ {
CSMDoc::Messages messages; CSMDoc::Messages messages (CSMDoc::Message::Severity_Info);
int row = model->getModelIndex (id.getId(), int row = model->getModelIndex (id.getId(),
model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row(); model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row();

@ -21,6 +21,8 @@ CSMTools::SearchOperation::SearchOperation (CSMDoc::Document& document)
iter!=types.end(); ++iter) iter!=types.end(); ++iter)
appendStage (new SearchStage (&dynamic_cast<CSMWorld::IdTableBase&> ( appendStage (new SearchStage (&dynamic_cast<CSMWorld::IdTableBase&> (
*document.getData().getTableModel (*iter)))); *document.getData().getTableModel (*iter))));
setDefaultSeverity (CSMDoc::Message::Severity_Info);
} }
void CSMTools::SearchOperation::configure (const Search& search) void CSMTools::SearchOperation::configure (const Search& search)

@ -0,0 +1,53 @@
#include "soundgencheck.hpp"
#include <sstream>
#include "../world/refiddata.hpp"
#include "../world/universalid.hpp"
CSMTools::SoundGenCheckStage::SoundGenCheckStage(const CSMWorld::IdCollection<ESM::SoundGenerator> &soundGens,
const CSMWorld::IdCollection<ESM::Sound> &sounds,
const CSMWorld::RefIdCollection &referenceables)
: mSoundGens(soundGens),
mSounds(sounds),
mReferenceables(referenceables)
{}
int CSMTools::SoundGenCheckStage::setup()
{
return mSoundGens.getSize();
}
void CSMTools::SoundGenCheckStage::perform(int stage, CSMDoc::Messages &messages)
{
const CSMWorld::Record<ESM::SoundGenerator> &record = mSoundGens.getRecord(stage);
if (record.isDeleted())
{
return;
}
const ESM::SoundGenerator soundGen = record.get();
CSMWorld::UniversalId id(CSMWorld::UniversalId::Type_SoundGen, soundGen.mId);
if (!soundGen.mCreature.empty())
{
CSMWorld::RefIdData::LocalIndex creatureIndex = mReferenceables.getDataSet().searchId(soundGen.mCreature);
if (creatureIndex.first == -1)
{
messages.push_back(std::make_pair(id, "No such creature '" + soundGen.mCreature + "'"));
}
else if (creatureIndex.second != CSMWorld::UniversalId::Type_Creature)
{
messages.push_back(std::make_pair(id, "'" + soundGen.mCreature + "' is not a creature"));
}
}
if (soundGen.mSound.empty())
{
messages.push_back(std::make_pair(id, "Sound is not specified"));
}
else if (mSounds.searchId(soundGen.mSound) == -1)
{
messages.push_back(std::make_pair(id, "No such sound '" + soundGen.mSound + "'"));
}
}

@ -0,0 +1,30 @@
#ifndef CSM_TOOLS_SOUNDGENCHECK_HPP
#define CSM_TOOLS_SOUNDGENCHECK_HPP
#include "../world/data.hpp"
#include "../doc/stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that sound gen records are internally consistent
class SoundGenCheckStage : public CSMDoc::Stage
{
const CSMWorld::IdCollection<ESM::SoundGenerator> &mSoundGens;
const CSMWorld::IdCollection<ESM::Sound> &mSounds;
const CSMWorld::RefIdCollection &mReferenceables;
public:
SoundGenCheckStage(const CSMWorld::IdCollection<ESM::SoundGenerator> &soundGens,
const CSMWorld::IdCollection<ESM::Sound> &sounds,
const CSMWorld::RefIdCollection &referenceables);
virtual int setup();
///< \return number of steps
virtual void perform(int stage, CSMDoc::Messages &messages);
///< Messages resulting from this stage will be appended to \a messages.
};
}
#endif

@ -27,6 +27,7 @@
#include "startscriptcheck.hpp" #include "startscriptcheck.hpp"
#include "searchoperation.hpp" #include "searchoperation.hpp"
#include "pathgridcheck.hpp" #include "pathgridcheck.hpp"
#include "soundgencheck.hpp"
CSMDoc::OperationHolder *CSMTools::Tools::get (int type) CSMDoc::OperationHolder *CSMTools::Tools::get (int type)
{ {
@ -50,11 +51,15 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
{ {
mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false); mVerifierOperation = new CSMDoc::Operation (CSMDoc::State_Verifying, false);
std::vector<QString> settings;
settings.push_back ("script-editor/warnings");
mVerifierOperation->configureSettings (settings);
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, bool)), this, SIGNAL (done (int, bool))); connect (&mVerifier, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mVerifier, connect (&mVerifier, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
std::vector<std::string> mandatoryIds; // I want C++11, damn it! std::vector<std::string> mandatoryIds; // I want C++11, damn it!
mandatoryIds.push_back ("Day"); mandatoryIds.push_back ("Day");
@ -99,6 +104,10 @@ CSMDoc::OperationHolder *CSMTools::Tools::getVerifier()
mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids())); mVerifierOperation->appendStage (new PathgridCheckStage (mData.getPathgrids()));
mVerifierOperation->appendStage (new SoundGenCheckStage (mData.getSoundGens(),
mData.getSounds(),
mData.getReferenceables()));
mVerifier.setOperation (mVerifierOperation); mVerifier.setOperation (mVerifierOperation);
} }
@ -115,9 +124,8 @@ CSMTools::Tools::Tools (CSMDoc::Document& document)
connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int))); connect (&mSearch, SIGNAL (progress (int, int, int)), this, SIGNAL (progress (int, int, int)));
connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool))); connect (&mSearch, SIGNAL (done (int, bool)), this, SIGNAL (done (int, bool)));
connect (&mSearch, connect (&mSearch, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)), this, SLOT (verifierMessage (const CSMDoc::Message&, int)));
this, SLOT (verifierMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
} }
CSMTools::Tools::~Tools() CSMTools::Tools::~Tools()
@ -138,19 +146,24 @@ CSMTools::Tools::~Tools()
delete iter->second; delete iter->second;
} }
CSMWorld::UniversalId CSMTools::Tools::runVerifier() CSMWorld::UniversalId CSMTools::Tools::runVerifier (const CSMWorld::UniversalId& reportId)
{ {
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel)); int reportNumber = reportId.getType()==CSMWorld::UniversalId::Type_VerificationResults ?
mActiveReports[CSMDoc::State_Verifying] = mNextReportNumber-1; reportId.getIndex() : mNextReportNumber++;
if (mReports.find (reportNumber)==mReports.end())
mReports.insert (std::make_pair (reportNumber, new ReportModel));
mActiveReports[CSMDoc::State_Verifying] = reportNumber;
getVerifier()->start(); getVerifier()->start();
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, mNextReportNumber-1); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_VerificationResults, reportNumber);
} }
CSMWorld::UniversalId CSMTools::Tools::newSearch() CSMWorld::UniversalId CSMTools::Tools::newSearch()
{ {
mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true))); mReports.insert (std::make_pair (mNextReportNumber++, new ReportModel (true, false)));
return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1); return CSMWorld::UniversalId (CSMWorld::UniversalId::Type_Search, mNextReportNumber-1);
} }
@ -205,12 +218,11 @@ CSMTools::ReportModel *CSMTools::Tools::getReport (const CSMWorld::UniversalId&
return mReports.at (id.getIndex()); return mReports.at (id.getIndex());
} }
void CSMTools::Tools::verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, void CSMTools::Tools::verifierMessage (const CSMDoc::Message& message, int type)
const std::string& hint, int type)
{ {
std::map<int, int>::iterator iter = mActiveReports.find (type); std::map<int, int>::iterator iter = mActiveReports.find (type);
if (iter!=mActiveReports.end()) if (iter!=mActiveReports.end())
mReports[iter->second]->add (id, message, hint); mReports[iter->second]->add (message);
} }

@ -57,8 +57,11 @@ namespace CSMTools
virtual ~Tools(); virtual ~Tools();
CSMWorld::UniversalId runVerifier(); /// \param reportId If a valid VerificationResults ID, run verifier for the
///< \return ID of the report for this verification run /// specified report instead of creating a new one.
///
/// \return ID of the report for this verification run
CSMWorld::UniversalId runVerifier (const CSMWorld::UniversalId& reportId = CSMWorld::UniversalId());
/// Return ID of the report for this search. /// Return ID of the report for this search.
CSMWorld::UniversalId newSearch(); CSMWorld::UniversalId newSearch();
@ -75,8 +78,7 @@ namespace CSMTools
private slots: private slots:
void verifierMessage (const CSMWorld::UniversalId& id, const std::string& message, void verifierMessage (const CSMDoc::Message& message, int type);
const std::string& hint, int type);
signals: signals:

@ -65,6 +65,8 @@ bool CSMWorld::ColumnBase::isId (Display display)
Display_JournalInfo, Display_JournalInfo,
Display_Scene, Display_Scene,
Display_GlobalVariable, Display_GlobalVariable,
Display_BodyPart,
Display_Enchantment,
Display_Script, Display_Script,
Display_Mesh, Display_Mesh,
@ -98,7 +100,8 @@ bool CSMWorld::ColumnBase::isId (Display display)
bool CSMWorld::ColumnBase::isText (Display display) bool CSMWorld::ColumnBase::isText (Display display)
{ {
return display==Display_String || display==Display_LongString; return display==Display_String || display==Display_LongString ||
display==Display_String32 || display==Display_LongString256;
} }
bool CSMWorld::ColumnBase::isScript (Display display) bool CSMWorld::ColumnBase::isScript (Display display)

@ -74,6 +74,8 @@ namespace CSMWorld
Display_JournalInfo, Display_JournalInfo,
Display_Scene, Display_Scene,
Display_GlobalVariable, Display_GlobalVariable,
Display_BodyPart,
Display_Enchantment,
//CONCRETE TYPES ENDS HERE //CONCRETE TYPES ENDS HERE
Display_Integer, Display_Integer,
@ -121,6 +123,8 @@ namespace CSMWorld
Display_InfoCondVar, Display_InfoCondVar,
Display_InfoCondComp, Display_InfoCondComp,
Display_RaceSkill, Display_RaceSkill,
Display_String32,
Display_LongString256,
//top level columns that nest other columns //top level columns that nest other columns
Display_NestedHeader Display_NestedHeader

@ -694,7 +694,7 @@ namespace CSMWorld
QColor colour = data.value<QColor>(); QColor colour = data.value<QColor>();
record2.mMapColor = colour.rgb() & 0xffffff; record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red();
record.setModified (record2); record.setModified (record2);
} }
@ -709,7 +709,7 @@ namespace CSMWorld
struct SleepListColumn : public Column<ESXRecordT> struct SleepListColumn : public Column<ESXRecordT>
{ {
SleepListColumn() SleepListColumn()
: Column<ESXRecordT> (Columns::ColumnId_SleepEncounter, ColumnBase::Display_String) : Column<ESXRecordT> (Columns::ColumnId_SleepEncounter, ColumnBase::Display_CreatureLevelledList)
{} {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
@ -735,7 +735,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct TextureColumn : public Column<ESXRecordT> struct TextureColumn : public Column<ESXRecordT>
{ {
TextureColumn() : Column<ESXRecordT> (Columns::ColumnId_Texture, ColumnBase::Display_String) {} TextureColumn() : Column<ESXRecordT> (Columns::ColumnId_Texture, ColumnBase::Display_Texture) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1269,7 +1269,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct TrapColumn : public Column<ESXRecordT> struct TrapColumn : public Column<ESXRecordT>
{ {
TrapColumn() : Column<ESXRecordT> (Columns::ColumnId_Trap, ColumnBase::Display_String) {} TrapColumn() : Column<ESXRecordT> (Columns::ColumnId_Trap, ColumnBase::Display_Spell) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1294,7 +1294,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct FilterColumn : public Column<ESXRecordT> struct FilterColumn : public Column<ESXRecordT>
{ {
FilterColumn() : Column<ESXRecordT> (Columns::ColumnId_Filter, ColumnBase::Display_String) {} FilterColumn() : Column<ESXRecordT> (Columns::ColumnId_Filter, ColumnBase::Display_Filter) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1497,7 +1497,10 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct TopicColumn : public Column<ESXRecordT> struct TopicColumn : public Column<ESXRecordT>
{ {
TopicColumn (bool journal) : Column<ESXRecordT> (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic, ColumnBase::Display_String) {} TopicColumn (bool journal)
: Column<ESXRecordT> (journal ? Columns::ColumnId_Journal : Columns::ColumnId_Topic,
journal ? ColumnBase::Display_Journal : ColumnBase::Display_Topic)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1527,7 +1530,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct ActorColumn : public Column<ESXRecordT> struct ActorColumn : public Column<ESXRecordT>
{ {
ActorColumn() : Column<ESXRecordT> (Columns::ColumnId_Actor, ColumnBase::Display_String) {} ActorColumn() : Column<ESXRecordT> (Columns::ColumnId_Actor, ColumnBase::Display_Npc) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -1830,7 +1833,7 @@ namespace CSMWorld
template<typename ESXRecordT> template<typename ESXRecordT>
struct ModelColumn : public Column<ESXRecordT> struct ModelColumn : public Column<ESXRecordT>
{ {
ModelColumn() : Column<ESXRecordT> (Columns::ColumnId_Model, ColumnBase::Display_String) {} ModelColumn() : Column<ESXRecordT> (Columns::ColumnId_Model, ColumnBase::Display_Mesh) {}
virtual QVariant get (const Record<ESXRecordT>& record) const virtual QVariant get (const Record<ESXRecordT>& record) const
{ {
@ -2158,7 +2161,9 @@ namespace CSMWorld
struct EffectTextureColumn : public Column<ESXRecordT> struct EffectTextureColumn : public Column<ESXRecordT>
{ {
EffectTextureColumn (Columns::ColumnId columnId) EffectTextureColumn (Columns::ColumnId columnId)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Texture) : Column<ESXRecordT> (columnId,
columnId == Columns::ColumnId_Particle ? ColumnBase::Display_Texture
: ColumnBase::Display_Icon)
{ {
assert (this->mColumnId==Columns::ColumnId_Icon || assert (this->mColumnId==Columns::ColumnId_Icon ||
this->mColumnId==Columns::ColumnId_Particle); this->mColumnId==Columns::ColumnId_Particle);
@ -2303,6 +2308,78 @@ namespace CSMWorld
return true; return true;
} }
}; };
template<typename ESXRecordT>
struct FormatColumn : public Column<ESXRecordT>
{
FormatColumn()
: Column<ESXRecordT> (Columns::ColumnId_FileFormat, ColumnBase::Display_Integer)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mFormat;
}
virtual bool isEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct AuthorColumn : public Column<ESXRecordT>
{
AuthorColumn()
: Column<ESXRecordT> (Columns::ColumnId_Author, ColumnBase::Display_String32)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mAuthor.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mAuthor = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct FileDescriptionColumn : public Column<ESXRecordT>
{
FileDescriptionColumn()
: Column<ESXRecordT> (Columns::ColumnId_FileDescription, ColumnBase::Display_LongString256)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mDescription.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mDescription = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
} }
#endif #endif

@ -92,7 +92,7 @@ namespace CSMWorld
{ ColumnId_Trainer, "Trainer" }, { ColumnId_Trainer, "Trainer" },
{ ColumnId_Spellmaking, "Spellmaking" }, { ColumnId_Spellmaking, "Spellmaking" },
{ ColumnId_EnchantingService, "Enchanting Service" }, { ColumnId_EnchantingService, "Enchanting Service" },
{ ColumnId_RepairService, "Repair Serivce" }, { ColumnId_RepairService, "Repair Service" },
{ ColumnId_ApparatusType, "Apparatus Type" }, { ColumnId_ApparatusType, "Apparatus Type" },
{ ColumnId_ArmorType, "Armor Type" }, { ColumnId_ArmorType, "Armor Type" },
{ ColumnId_Health, "Health" }, { ColumnId_Health, "Health" },
@ -311,6 +311,10 @@ namespace CSMWorld
{ ColumnId_WaterLevel, "Water Level" }, { ColumnId_WaterLevel, "Water Level" },
{ ColumnId_MapColor, "Map Color" }, { ColumnId_MapColor, "Map Color" },
{ ColumnId_FileFormat, "File Format" },
{ ColumnId_FileDescription, "File Description" },
{ ColumnId_Author, "Author" },
{ ColumnId_UseValue1, "Use value 1" }, { ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" }, { ColumnId_UseValue2, "Use value 2" },
{ ColumnId_UseValue3, "Use value 3" }, { ColumnId_UseValue3, "Use value 3" },

@ -302,6 +302,10 @@ namespace CSMWorld
ColumnId_WaterLevel = 273, ColumnId_WaterLevel = 273,
ColumnId_MapColor = 274, ColumnId_MapColor = 274,
ColumnId_FileFormat = 275,
ColumnId_FileDescription = 276,
ColumnId_Author = 277,
// 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,

@ -58,6 +58,25 @@ void CSMWorld::CreateCommand::applyModifications()
{ {
for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter) for (std::map<int, QVariant>::const_iterator iter (mValues.begin()); iter!=mValues.end(); ++iter)
mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second); mModel.setData (mModel.getModelIndex (mId, iter->first), iter->second);
if (!mNestedValues.empty())
{
CSMWorld::IdTree *tree = dynamic_cast<CSMWorld::IdTree *>(&mModel);
if (tree == NULL)
{
throw std::logic_error("CSMWorld::CreateCommand: Attempt to add nested values to the non-nested model");
}
std::map<int, std::pair<int, QVariant> >::const_iterator current = mNestedValues.begin();
std::map<int, std::pair<int, QVariant> >::const_iterator end = mNestedValues.end();
for (; current != end; ++current)
{
QModelIndex index = tree->index(0,
current->second.first,
tree->getNestedModelIndex(mId, current->first));
tree->setData(index, current->second.second);
}
}
} }
CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent) CSMWorld::CreateCommand::CreateCommand (IdTable& model, const std::string& id, QUndoCommand* parent)
@ -71,6 +90,11 @@ void CSMWorld::CreateCommand::addValue (int column, const QVariant& value)
mValues[column] = value; mValues[column] = value;
} }
void CSMWorld::CreateCommand::addNestedValue(int parentColumn, int nestedColumn, const QVariant &value)
{
mNestedValues[parentColumn] = std::make_pair(nestedColumn, value);
}
void CSMWorld::CreateCommand::setType (UniversalId::Type type) void CSMWorld::CreateCommand::setType (UniversalId::Type type)
{ {
mType = type; mType = type;

@ -48,6 +48,9 @@ namespace CSMWorld
class CreateCommand : public QUndoCommand class CreateCommand : public QUndoCommand
{ {
std::map<int, QVariant> mValues; std::map<int, QVariant> mValues;
std::map<int, std::pair<int, QVariant> > mNestedValues;
///< Parameter order: a parent column, a nested column, a data.
///< A nested row has index of 0.
protected: protected:
@ -68,6 +71,8 @@ namespace CSMWorld
void addValue (int column, const QVariant& value); void addValue (int column, const QVariant& value);
void addNestedValue(int parentColumn, int nestedColumn, const QVariant &value);
virtual void redo(); virtual void redo();
virtual void undo(); virtual void undo();

@ -62,7 +62,7 @@ int CSMWorld::Data::count (RecordBase::State state, const CollectionBase& collec
CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager) CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourcesManager)
: mEncoder (encoding), mPathgrids (mCells), mRefs (mCells), : mEncoder (encoding), mPathgrids (mCells), mRefs (mCells),
mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0) mResourcesManager (resourcesManager), mReader (0), mDialogue (0), mReaderIndex(0), mResourceSystem(resourcesManager.getVFS())
{ {
int index = 0; int index = 0;
@ -115,7 +115,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mFactions.getColumns()-1; index = mFactions.getColumns()-1;
mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ())); mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ()));
mFactions.getNestableColumn(index)->addColumn( mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String)); new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
mFactions.getNestableColumn(index)->addColumn( mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer)); new NestedChildColumn (Columns::ColumnId_FactionReaction, ColumnBase::Display_Integer));
@ -135,7 +135,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mRaces.getColumns()-1; index = mRaces.getColumns()-1;
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter<ESM::Race> ())); mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter<ESM::Race> ()));
mRaces.getNestableColumn(index)->addColumn( mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell));
// Race attributes // Race attributes
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceAttributes)); mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceAttributes));
index = mRaces.getColumns()-1; index = mRaces.getColumns()-1;
@ -180,7 +180,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mRegions.getColumns()-1; index = mRegions.getColumns()-1;
mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ())); mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ()));
mRegions.getNestableColumn(index)->addColumn( mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String)); new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_Sound));
mRegions.getNestableColumn(index)->addColumn( mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer)); new NestedChildColumn (Columns::ColumnId_SoundChance, ColumnBase::Display_Integer));
@ -196,7 +196,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index), mBirthsigns.addAdapter (std::make_pair(&mBirthsigns.getColumn(index),
new SpellListAdapter<ESM::BirthSign> ())); new SpellListAdapter<ESM::BirthSign> ()));
mBirthsigns.getNestableColumn(index)->addColumn( mBirthsigns.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String)); new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell));
mSpells.addColumn (new StringIdColumn<ESM::Spell>); mSpells.addColumn (new StringIdColumn<ESM::Spell>);
mSpells.addColumn (new RecordStateColumn<ESM::Spell>); mSpells.addColumn (new RecordStateColumn<ESM::Spell>);
@ -475,6 +475,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> ( mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
ScriptColumn<ESM::DebugProfile>::Type_Lines)); ScriptColumn<ESM::DebugProfile>::Type_Lines));
mMetaData.appendBlankRecord ("sys::meta");
mMetaData.addColumn (new StringIdColumn<MetaData> (true));
mMetaData.addColumn (new RecordStateColumn<MetaData>);
mMetaData.addColumn (new FixedRecordTypeColumn<MetaData> (UniversalId::Type_MetaData));
mMetaData.addColumn (new FormatColumn<MetaData>);
mMetaData.addColumn (new AuthorColumn<MetaData>);
mMetaData.addColumn (new FileDescriptionColumn<MetaData>);
addModel (new IdTable (&mGlobals), UniversalId::Type_Global); addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst); addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skill); addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
@ -515,6 +524,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
UniversalId::Type_Texture); UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)), addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video); UniversalId::Type_Video);
addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData);
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
} }
@ -527,6 +537,16 @@ CSMWorld::Data::~Data()
delete mReader; delete mReader;
} }
Resource::ResourceSystem* CSMWorld::Data::getResourceSystem()
{
return &mResourceSystem;
}
const Resource::ResourceSystem* CSMWorld::Data::getResourceSystem() const
{
return &mResourceSystem;
}
const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const const CSMWorld::IdCollection<ESM::Global>& CSMWorld::Data::getGlobals() const
{ {
return mGlobals; return mGlobals;
@ -803,6 +823,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id)
return mResourcesManager.get (id.getType()); return mResourcesManager.get (id.getType());
} }
const CSMWorld::MetaData& CSMWorld::Data::getMetaData() const
{
return mMetaData.getRecord (0).get();
}
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());
@ -847,9 +872,15 @@ int CSMWorld::Data::startLoading (const boost::filesystem::path& path, bool base
mBase = base; mBase = base;
mProject = project; mProject = project;
mAuthor = mReader->getAuthor(); if (!mProject && !mBase)
mDescription = mReader->getDesc(); {
MetaData metaData;
metaData.mId = "sys::meta";
metaData.load (*mReader);
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
}
return mReader->getRecordCount(); return mReader->getRecordCount();
} }
@ -923,7 +954,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
{ {
// log an error and continue loading the refs to the last loaded cell // log an error and continue loading the refs to the last loaded cell
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_None); CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_None);
messages.add (id, "Logic error: cell index out of bounds"); messages.add (id, "Logic error: cell index out of bounds", "", CSMDoc::Message::Severity_Error);
index = mCells.getSize()-1; index = mCells.getSize()-1;
} }
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index)); std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index));
@ -984,7 +1015,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
else else
{ {
messages.add (UniversalId::Type_None, messages.add (UniversalId::Type_None,
"Trying to delete dialogue record " + id + " which does not exist"); "Trying to delete dialogue record " + id + " which does not exist",
"", CSMDoc::Message::Severity_Warning);
} }
} }
else else
@ -1001,7 +1033,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (!mDialogue) if (!mDialogue)
{ {
messages.add (UniversalId::Type_None, messages.add (UniversalId::Type_None,
"Found info record not following a dialogue record"); "Found info record not following a dialogue record", "", CSMDoc::Message::Severity_Error);
mReader->skipRecord(); mReader->skipRecord();
break; break;
@ -1044,7 +1076,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (unhandledRecord) if (unhandledRecord)
{ {
messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString()); messages.add (UniversalId::Type_None, "Unsupported record type: " + n.toString(), "",
CSMDoc::Message::Severity_Error);
mReader->skipRecord(); mReader->skipRecord();
} }
@ -1101,26 +1134,6 @@ int CSMWorld::Data::count (RecordBase::State state) const
count (state, mPathgrids); count (state, mPathgrids);
} }
void CSMWorld::Data::setDescription (const std::string& description)
{
mDescription = description;
}
std::string CSMWorld::Data::getDescription() const
{
return mDescription;
}
void CSMWorld::Data::setAuthor (const std::string& author)
{
mAuthor = author;
}
std::string CSMWorld::Data::getAuthor() const
{
return mAuthor;
}
std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const std::vector<std::string> CSMWorld::Data::getIds (bool listDeleted) const
{ {
std::vector<std::string> ids; std::vector<std::string> ids;
@ -1159,3 +1172,8 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end)
{ {
emit idListChanged(); emit idListChanged();
} }
const VFS::Manager* CSMWorld::Data::getVFS() const
{
return mResourcesManager.getVFS();
}

@ -29,6 +29,8 @@
#include <components/esm/debugprofile.hpp> #include <components/esm/debugprofile.hpp>
#include <components/esm/filter.hpp> #include <components/esm/filter.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/to_utf8/to_utf8.hpp> #include <components/to_utf8/to_utf8.hpp>
#include "../doc/stage.hpp" #include "../doc/stage.hpp"
@ -44,12 +46,18 @@
#include "infocollection.hpp" #include "infocollection.hpp"
#include "nestedinfocollection.hpp" #include "nestedinfocollection.hpp"
#include "pathgrid.hpp" #include "pathgrid.hpp"
#include "metadata.hpp"
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include "subcellcollection.hpp" #include "subcellcollection.hpp"
#endif #endif
class QAbstractItemModel; class QAbstractItemModel;
namespace VFS
{
class Manager;
}
namespace ESM namespace ESM
{ {
class ESMReader; class ESMReader;
@ -94,11 +102,10 @@ namespace CSMWorld
RefIdCollection mReferenceables; RefIdCollection mReferenceables;
RefCollection mRefs; RefCollection mRefs;
IdCollection<ESM::Filter> mFilters; IdCollection<ESM::Filter> mFilters;
Collection<MetaData> mMetaData;
const ResourcesManager& mResourcesManager; 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 mDescription;
ESM::ESMReader *mReader; ESM::ESMReader *mReader;
const ESM::Dialogue *mDialogue; // last loaded dialogue const ESM::Dialogue *mDialogue; // last loaded dialogue
bool mBase; bool mBase;
@ -106,6 +113,8 @@ namespace CSMWorld
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache; std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
int mReaderIndex; int mReaderIndex;
Resource::ResourceSystem mResourceSystem;
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders; std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
// not implemented // not implemented
@ -127,6 +136,12 @@ namespace CSMWorld
virtual ~Data(); virtual ~Data();
const VFS::Manager* getVFS() const;
Resource::ResourceSystem* getResourceSystem();
const Resource::ResourceSystem* getResourceSystem() const;
const IdCollection<ESM::Global>& getGlobals() const; const IdCollection<ESM::Global>& getGlobals() const;
IdCollection<ESM::Global>& getGlobals(); IdCollection<ESM::Global>& getGlobals();
@ -238,6 +253,8 @@ namespace CSMWorld
/// Throws an exception, if \a id does not match a resources list. /// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const; const Resources& getResources (const UniversalId& id) const;
const MetaData& getMetaData() 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.
/// ///
@ -267,14 +284,6 @@ namespace CSMWorld
int count (RecordBase::State state) const; int count (RecordBase::State state) const;
///< Return number of top-level records with the given \a state. ///< Return number of top-level records with the given \a state.
void setDescription (const std::string& description);
std::string getDescription() const;
void setAuthor (const std::string& author);
std::string getAuthor() const;
signals: signals:
void idListChanged(); void idListChanged();

@ -0,0 +1,112 @@
#include "idcompletionmanager.hpp"
#include <boost/make_shared.hpp>
#include <QCompleter>
#include "../../view/widget/completerpopup.hpp"
#include "data.hpp"
#include "idtablebase.hpp"
namespace
{
std::map<CSMWorld::ColumnBase::Display, CSMWorld::UniversalId::Type> generateModelTypes()
{
std::map<CSMWorld::ColumnBase::Display, CSMWorld::UniversalId::Type> types;
types[CSMWorld::ColumnBase::Display_BodyPart ] = CSMWorld::UniversalId::Type_BodyPart;
types[CSMWorld::ColumnBase::Display_Cell ] = CSMWorld::UniversalId::Type_Cell;
types[CSMWorld::ColumnBase::Display_Class ] = CSMWorld::UniversalId::Type_Class;
types[CSMWorld::ColumnBase::Display_CreatureLevelledList] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Creature ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Enchantment ] = CSMWorld::UniversalId::Type_Enchantment;
types[CSMWorld::ColumnBase::Display_Faction ] = CSMWorld::UniversalId::Type_Faction;
types[CSMWorld::ColumnBase::Display_GlobalVariable ] = CSMWorld::UniversalId::Type_Global;
types[CSMWorld::ColumnBase::Display_Icon ] = CSMWorld::UniversalId::Type_Icon;
types[CSMWorld::ColumnBase::Display_Journal ] = CSMWorld::UniversalId::Type_Journal;
types[CSMWorld::ColumnBase::Display_Mesh ] = CSMWorld::UniversalId::Type_Mesh;
types[CSMWorld::ColumnBase::Display_Miscellaneous ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Npc ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Race ] = CSMWorld::UniversalId::Type_Race;
types[CSMWorld::ColumnBase::Display_Region ] = CSMWorld::UniversalId::Type_Region;
types[CSMWorld::ColumnBase::Display_Referenceable ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Script ] = CSMWorld::UniversalId::Type_Script;
types[CSMWorld::ColumnBase::Display_Skill ] = CSMWorld::UniversalId::Type_Skill;
types[CSMWorld::ColumnBase::Display_Sound ] = CSMWorld::UniversalId::Type_Sound;
types[CSMWorld::ColumnBase::Display_SoundRes ] = CSMWorld::UniversalId::Type_SoundRes;
types[CSMWorld::ColumnBase::Display_Spell ] = CSMWorld::UniversalId::Type_Spell;
types[CSMWorld::ColumnBase::Display_Static ] = CSMWorld::UniversalId::Type_Referenceable;
types[CSMWorld::ColumnBase::Display_Texture ] = CSMWorld::UniversalId::Type_Texture;
types[CSMWorld::ColumnBase::Display_Topic ] = CSMWorld::UniversalId::Type_Topic;
types[CSMWorld::ColumnBase::Display_Weapon ] = CSMWorld::UniversalId::Type_Referenceable;
return types;
}
typedef std::map<CSMWorld::ColumnBase::Display,
CSMWorld::UniversalId::Type>::const_iterator ModelTypeConstIterator;
}
const std::map<CSMWorld::ColumnBase::Display, CSMWorld::UniversalId::Type>
CSMWorld::IdCompletionManager::sCompleterModelTypes = generateModelTypes();
std::vector<CSMWorld::ColumnBase::Display> CSMWorld::IdCompletionManager::getDisplayTypes()
{
std::vector<CSMWorld::ColumnBase::Display> types;
ModelTypeConstIterator current = sCompleterModelTypes.begin();
ModelTypeConstIterator end = sCompleterModelTypes.end();
for (; current != end; ++current)
{
types.push_back(current->first);
}
return types;
}
CSMWorld::IdCompletionManager::IdCompletionManager(CSMWorld::Data &data)
{
generateCompleters(data);
}
bool CSMWorld::IdCompletionManager::hasCompleterFor(CSMWorld::ColumnBase::Display display) const
{
return mCompleters.find(display) != mCompleters.end();
}
boost::shared_ptr<QCompleter> CSMWorld::IdCompletionManager::getCompleter(CSMWorld::ColumnBase::Display display)
{
if (!hasCompleterFor(display))
{
throw std::logic_error("This column doesn't have an ID completer");
}
return mCompleters[display];
}
void CSMWorld::IdCompletionManager::generateCompleters(CSMWorld::Data &data)
{
ModelTypeConstIterator current = sCompleterModelTypes.begin();
ModelTypeConstIterator end = sCompleterModelTypes.end();
for (; current != end; ++current)
{
QAbstractItemModel *model = data.getTableModel(current->second);
CSMWorld::IdTableBase *table = dynamic_cast<CSMWorld::IdTableBase *>(model);
if (table != NULL)
{
int idColumn = table->searchColumnIndex(CSMWorld::Columns::ColumnId_Id);
if (idColumn != -1)
{
boost::shared_ptr<QCompleter> completer = boost::make_shared<QCompleter>(table);
completer->setCompletionColumn(idColumn);
// The completion role must be Qt::DisplayRole to get the ID values from the model
completer->setCompletionRole(Qt::DisplayRole);
completer->setCaseSensitivity(Qt::CaseInsensitive);
QAbstractItemView *popup = new CSVWidget::CompleterPopup();
completer->setPopup(popup); // The completer takes ownership of the popup
completer->setMaxVisibleItems(10);
mCompleters[current->first] = completer;
}
}
}
}

@ -0,0 +1,41 @@
#ifndef CSM_WORLD_IDCOMPLETIONMANAGER_HPP
#define CSM_WORLD_IDCOMPLETIONMANAGER_HPP
#include <vector>
#include <map>
#include <boost/shared_ptr.hpp>
#include "columnbase.hpp"
#include "universalid.hpp"
class QCompleter;
namespace CSMWorld
{
class Data;
/// \brief Creates and stores all ID completers
class IdCompletionManager
{
static const std::map<ColumnBase::Display, UniversalId::Type> sCompleterModelTypes;
std::map<ColumnBase::Display, boost::shared_ptr<QCompleter> > mCompleters;
// Don't allow copying
IdCompletionManager(const IdCompletionManager &);
IdCompletionManager &operator = (const IdCompletionManager &);
void generateCompleters(Data &data);
public:
static std::vector<ColumnBase::Display> getDisplayTypes();
IdCompletionManager(Data &data);
bool hasCompleterFor(ColumnBase::Display display) const;
boost::shared_ptr<QCompleter> getCompleter(ColumnBase::Display display);
};
}
#endif

@ -33,6 +33,9 @@ QVariant CSMWorld::IdTable::data (const QModelIndex & index, int role) const
if (index.row() < 0 || index.column() < 0) if (index.row() < 0 || index.column() < 0)
return QVariant(); return QVariant();
if (role==ColumnBase::Role_Display)
return QVariant(mIdCollection->getColumn(index.column()).mDisplayType);
if (role==ColumnBase::Role_ColumnId) if (role==ColumnBase::Role_ColumnId)
return QVariant (getColumnId (index.column())); return QVariant (getColumnId (index.column()));
@ -84,6 +87,9 @@ bool CSMWorld::IdTable::setData (const QModelIndex &index, const QVariant &value
Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const Qt::ItemFlags CSMWorld::IdTable::flags (const QModelIndex & index) const
{ {
if (!index.isValid())
return 0;
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled; Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (mIdCollection->getColumn (index.column()).isUserEditable()) if (mIdCollection->getColumn (index.column()).isUserEditable())

@ -24,6 +24,14 @@ void CSMWorld::IdTableProxyModel::updateColumnMap()
bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent)
const const
{ {
// It is not possible to use filterAcceptsColumn() and check for
// sourceModel()->headerData (sourceColumn, Qt::Horizontal, CSMWorld::ColumnBase::Role_Flags)
// because the sourceColumn parameter excludes the hidden columns, i.e. wrong columns can
// be rejected. Workaround by disallowing tree branches (nested columns), which are not meant
// to be visible, from the filter.
if (sourceParent.isValid())
return false;
if (!mFilter) if (!mFilter)
return true; return true;
@ -44,9 +52,10 @@ QModelIndex CSMWorld::IdTableProxyModel::getModelIndex (const std::string& id, i
void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter) void CSMWorld::IdTableProxyModel::setFilter (const boost::shared_ptr<CSMFilter::Node>& filter)
{ {
beginResetModel();
mFilter = filter; mFilter = filter;
updateColumnMap(); updateColumnMap();
reset(); endResetModel();
} }
bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const

@ -24,8 +24,6 @@ namespace CSMWorld
void updateColumnMap(); void updateColumnMap();
bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
public: public:
IdTableProxyModel (QObject *parent = 0); IdTableProxyModel (QObject *parent = 0);
@ -39,6 +37,8 @@ namespace CSMWorld
protected: protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
virtual bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
}; };
} }

@ -35,28 +35,29 @@ QVariant CSMWorld::IdTree::data (const QModelIndex & index, int role) const
if (!index.isValid()) if (!index.isValid())
return QVariant(); return QVariant();
if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0)
return QVariant();
if (index.internalId() != 0) if (index.internalId() != 0)
{ {
std::pair<int, int> parentAddress(unfoldIndexAddress(index.internalId())); std::pair<int, int> parentAddress(unfoldIndexAddress(index.internalId()));
const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second);
if (role == Qt::EditRole && if (role == ColumnBase::Role_Display)
!mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable()) return parentColumn->nestedColumn(index.column()).mDisplayType;
{
if (role == ColumnBase::Role_ColumnId)
return parentColumn->nestedColumn(index.column()).mColumnId;
if (role == Qt::EditRole && !parentColumn->nestedColumn(index.column()).isEditable())
return QVariant();
if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant(); return QVariant();
}
return mNestedCollection->getNestedData(parentAddress.first, return mNestedCollection->getNestedData(parentAddress.first,
parentAddress.second, index.row(), index.column()); parentAddress.second, index.row(), index.column());
} }
else else
{ {
if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable()) return IdTable::data(index, role);
return QVariant();
return idCollection()->getData (index.row(), index.column());
} }
} }
@ -79,6 +80,9 @@ QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Ori
if (role==ColumnBase::Role_Display) if (role==ColumnBase::Role_Display)
return parentColumn->nestedColumn(subSection).mDisplayType; return parentColumn->nestedColumn(subSection).mDisplayType;
if (role==ColumnBase::Role_ColumnId)
return parentColumn->nestedColumn(subSection).mColumnId;
return QVariant(); return QVariant();
} }
@ -257,3 +261,13 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde
return mNestedCollection->nestedTable(index.row(), index.column()); return mNestedCollection->nestedTable(index.row(), index.column());
} }
int CSMWorld::IdTree::searchNestedColumnIndex(int parentColumn, Columns::ColumnId id)
{
return mNestedCollection->searchNestedColumnIndex(parentColumn, id);
}
int CSMWorld::IdTree::findNestedColumnIndex(int parentColumn, Columns::ColumnId id)
{
return mNestedCollection->findNestedColumnIndex(parentColumn, id);
}

@ -73,6 +73,12 @@ namespace CSMWorld
virtual bool hasChildren (const QModelIndex& index) const; virtual bool hasChildren (const QModelIndex& index) const;
virtual int searchNestedColumnIndex(int parentColumn, Columns::ColumnId id);
///< \return the column index or -1 if the requested column wasn't found.
virtual int findNestedColumnIndex(int parentColumn, Columns::ColumnId id);
///< \return the column index or throws an exception if the requested column wasn't found.
signals: signals:
void resetStart(const QString& id); void resetStart(const QString& id);

@ -97,7 +97,8 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int
return false; return false;
// Check that topics match // Check that topics match
if (getRecord (baseIndex).get().mTopicId!=getRecord (lastIndex).get().mTopicId) if (!Misc::StringUtils::ciEqual(getRecord(baseIndex).get().mTopicId,
getRecord(lastIndex).get().mTopicId))
return false; return false;
// reorder // reorder

@ -0,0 +1,79 @@
#include "infotableproxymodel.hpp"
#include <components/misc/stringops.hpp>
#include "idtablebase.hpp"
#include "columns.hpp"
namespace
{
QString toLower(const QString &str)
{
return QString::fromUtf8(Misc::StringUtils::lowerCase(str.toStdString()).c_str());
}
}
CSMWorld::InfoTableProxyModel::InfoTableProxyModel(CSMWorld::UniversalId::Type type, QObject *parent)
: IdTableProxyModel(parent),
mType(type),
mSourceModel(NULL),
mInfoColumnId(type == UniversalId::Type_TopicInfos ? Columns::ColumnId_Topic :
Columns::ColumnId_Journal)
{
Q_ASSERT(type == UniversalId::Type_TopicInfos || type == UniversalId::Type_JournalInfos);
}
void CSMWorld::InfoTableProxyModel::setSourceModel(QAbstractItemModel *sourceModel)
{
IdTableProxyModel::setSourceModel(sourceModel);
mSourceModel = dynamic_cast<IdTableBase *>(sourceModel);
if (mSourceModel != NULL)
{
connect(mSourceModel,
SIGNAL(rowsInserted(const QModelIndex &, int, int)),
this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
connect(mSourceModel,
SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
this,
SLOT(modelRowsChanged(const QModelIndex &, int, int)));
mFirstRowCache.clear();
}
}
bool CSMWorld::InfoTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
{
QModelIndex first = mSourceModel->index(getFirstInfoRow(left.row()), left.column());
QModelIndex second = mSourceModel->index(getFirstInfoRow(right.row()), right.column());
// If both indexes are belonged to the same Topic/Journal, compare their original rows only
if (first.row() == second.row())
{
return sortOrder() == Qt::AscendingOrder ? left.row() < right.row() : right.row() < left.row();
}
return IdTableProxyModel::lessThan(first, second);
}
int CSMWorld::InfoTableProxyModel::getFirstInfoRow(int currentRow) const
{
int row = currentRow;
int column = mSourceModel->findColumnIndex(mInfoColumnId);
QString info = toLower(mSourceModel->data(mSourceModel->index(row, column)).toString());
if (mFirstRowCache.contains(info))
{
return mFirstRowCache[info];
}
while (--row >= 0 &&
toLower(mSourceModel->data(mSourceModel->index(row, column)).toString()) == info);
++row;
mFirstRowCache[info] = row;
return row;
}
void CSMWorld::InfoTableProxyModel::modelRowsChanged(const QModelIndex &/*parent*/, int /*start*/, int /*end*/)
{
mFirstRowCache.clear();
}

@ -0,0 +1,41 @@
#ifndef CSM_WORLD_INFOTABLEPROXYMODEL_HPP
#define CSM_WORLD_INFOTABLEPROXYMODEL_HPP
#include <QHash>
#include "idtableproxymodel.hpp"
#include "columns.hpp"
#include "universalid.hpp"
namespace CSMWorld
{
class IdTableBase;
class InfoTableProxyModel : public IdTableProxyModel
{
Q_OBJECT
UniversalId::Type mType;
IdTableBase *mSourceModel;
Columns::ColumnId mInfoColumnId;
///< Contains ID for Topic or Journal ID
mutable QHash<QString, int> mFirstRowCache;
int getFirstInfoRow(int currentRow) const;
///< Finds the first row with the same topic (journal entry) as in \a currentRow
public:
InfoTableProxyModel(UniversalId::Type type, QObject *parent = 0);
void setSourceModel(QAbstractItemModel *sourceModel);
protected:
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
private slots:
void modelRowsChanged(const QModelIndex &parent, int start, int end);
};
}
#endif

@ -0,0 +1,27 @@
#include "metadata.hpp"
#include <components/esm/loadtes3.hpp>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
void CSMWorld::MetaData::blank()
{
mFormat = ESM::Header::CurrentFormat;
mAuthor.clear();
mDescription.clear();
}
void CSMWorld::MetaData::load (ESM::ESMReader& esm)
{
mFormat = esm.getHeader().mFormat;
mAuthor = esm.getHeader().mData.author.toString();
mDescription = esm.getHeader().mData.desc.toString();
}
void CSMWorld::MetaData::save (ESM::ESMWriter& esm) const
{
esm.setFormat (mFormat);
esm.setAuthor (mAuthor);
esm.setDescription (mDescription);
}

@ -0,0 +1,29 @@
#ifndef CSM_WOLRD_METADATA_H
#define CSM_WOLRD_METADATA_H
#include <string>
namespace ESM
{
class ESMReader;
class ESMWriter;
}
namespace CSMWorld
{
struct MetaData
{
std::string mId;
int mFormat;
std::string mAuthor;
std::string mDescription;
void blank();
void load (ESM::ESMReader& esm);
void save (ESM::ESMWriter& esm) const;
};
}
#endif

@ -906,7 +906,7 @@ namespace CSMWorld
NestedTableWrapperBase* RaceAttributeAdapter::table(const Record<ESM::Race>& record) const NestedTableWrapperBase* RaceAttributeAdapter::table(const Record<ESM::Race>& record) const
{ {
std::vector<typename ESM::Race::RADTstruct> wrap; std::vector<ESM::Race::RADTstruct> wrap;
wrap.push_back(record.get().mData); wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring // deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap); return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap);
@ -983,7 +983,7 @@ namespace CSMWorld
NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record<ESM::Race>& record) const NestedTableWrapperBase* RaceSkillsBonusAdapter::table(const Record<ESM::Race>& record) const
{ {
std::vector<typename ESM::Race::RADTstruct> wrap; std::vector<ESM::Race::RADTstruct> wrap;
wrap.push_back(record.get().mData); wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring // deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap); return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap);

@ -15,3 +15,28 @@ int CSMWorld::NestedCollection::getNestedColumnsCount(int row, int column) const
{ {
return 0; return 0;
} }
int CSMWorld::NestedCollection::searchNestedColumnIndex(int parentColumn, Columns::ColumnId id)
{
// Assumed that the parentColumn is always a valid index
const NestableColumn *parent = getNestableColumn(parentColumn);
int nestedColumnCount = getNestedColumnsCount(0, parentColumn);
for (int i = 0; i < nestedColumnCount; ++i)
{
if (parent->nestedColumn(i).mColumnId == id)
{
return i;
}
}
return -1;
}
int CSMWorld::NestedCollection::findNestedColumnIndex(int parentColumn, Columns::ColumnId id)
{
int index = searchNestedColumnIndex(parentColumn, id);
if (index == -1)
{
throw std::logic_error("CSMWorld::NestedCollection: No such nested column");
}
return index;
}

@ -1,6 +1,8 @@
#ifndef CSM_WOLRD_NESTEDCOLLECTION_H #ifndef CSM_WOLRD_NESTEDCOLLECTION_H
#define CSM_WOLRD_NESTEDCOLLECTION_H #define CSM_WOLRD_NESTEDCOLLECTION_H
#include "columns.hpp"
class QVariant; class QVariant;
namespace CSMWorld namespace CSMWorld
@ -33,6 +35,12 @@ namespace CSMWorld
virtual int getNestedColumnsCount(int row, int column) const; virtual int getNestedColumnsCount(int row, int column) const;
virtual NestableColumn *getNestableColumn(int column) = 0; virtual NestableColumn *getNestableColumn(int column) = 0;
virtual int searchNestedColumnIndex(int parentColumn, Columns::ColumnId id);
///< \return the column index or -1 if the requested column wasn't found.
virtual int findNestedColumnIndex(int parentColumn, Columns::ColumnId id);
///< \return the column index or throws an exception if the requested column wasn't found.
}; };
} }

@ -161,8 +161,19 @@ namespace CSMWorld
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const
{ {
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).getColumnsCount( const ColumnBase &nestedColumn = Collection<ESXRecordT, IdAccessorT>::getColumn(column);
Collection<ESXRecordT, IdAccessorT>::getRecord(row)); int numRecords = Collection<ESXRecordT, IdAccessorT>::getSize();
if (row >= 0 && row < numRecords)
{
const Record<ESXRecordT>& record = Collection<ESXRecordT, IdAccessorT>::getRecord(row);
return getAdapter(nestedColumn).getColumnsCount(record);
}
else
{
// If the row is invalid (or there no records), retrieve the column count using a blank record
const Record<ESXRecordT> record;
return getAdapter(nestedColumn).getColumnsCount(record);
}
} }
template<typename ESXRecordT, typename IdAccessorT> template<typename ESXRecordT, typename IdAccessorT>

@ -192,4 +192,8 @@ void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& top
emit dataChanged(index(0,0), emit dataChanged(index(0,0),
index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1)); index(mMainModel->rowCount(parent)-1, mMainModel->columnCount(parent)-1));
} }
else if (topLeft.parent() == parent && bottomRight.parent() == parent)
{
emit dataChanged(index(topLeft.row(), topLeft.column()), index(bottomRight.row(), bottomRight.column()));
}
} }

@ -37,10 +37,18 @@ void CSMWorld::PotionRefIdAdapter::setData (const RefIdColumn *column, RefIdData
Record<ESM::Potion>& record = static_cast<Record<ESM::Potion>&> ( Record<ESM::Potion>& record = static_cast<Record<ESM::Potion>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion)));
ESM::Potion potion = record.get();
if (column==mAutoCalc) if (column==mAutoCalc)
record.get().mData.mAutoCalc = value.toInt(); potion.mData.mAutoCalc = value.toInt();
else else
{
InventoryRefIdAdapter<ESM::Potion>::setData (column, data, index, value); InventoryRefIdAdapter<ESM::Potion>::setData (column, data, index, value);
return;
}
record.setModified(potion);
} }
@ -71,12 +79,19 @@ void CSMWorld::ApparatusRefIdAdapter::setData (const RefIdColumn *column, RefIdD
Record<ESM::Apparatus>& record = static_cast<Record<ESM::Apparatus>&> ( Record<ESM::Apparatus>& record = static_cast<Record<ESM::Apparatus>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus)));
ESM::Apparatus apparatus = record.get();
if (column==mType) if (column==mType)
record.get().mData.mType = value.toInt(); apparatus.mData.mType = value.toInt();
else if (column==mQuality) else if (column==mQuality)
record.get().mData.mQuality = value.toFloat(); apparatus.mData.mQuality = value.toFloat();
else else
{
InventoryRefIdAdapter<ESM::Apparatus>::setData (column, data, index, value); InventoryRefIdAdapter<ESM::Apparatus>::setData (column, data, index, value);
return;
}
record.setModified(apparatus);
} }
@ -114,14 +129,22 @@ void CSMWorld::ArmorRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Armor>& record = static_cast<Record<ESM::Armor>&> ( Record<ESM::Armor>& record = static_cast<Record<ESM::Armor>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor)));
ESM::Armor armor = record.get();
if (column==mType) if (column==mType)
record.get().mData.mType = value.toInt(); armor.mData.mType = value.toInt();
else if (column==mHealth) else if (column==mHealth)
record.get().mData.mHealth = value.toInt(); armor.mData.mHealth = value.toInt();
else if (column==mArmor) else if (column==mArmor)
record.get().mData.mArmor = value.toInt(); armor.mData.mArmor = value.toInt();
else else
{
EnchantableRefIdAdapter<ESM::Armor>::setData (column, data, index, value); EnchantableRefIdAdapter<ESM::Armor>::setData (column, data, index, value);
return;
}
record.setModified(armor);
} }
CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns, CSMWorld::BookRefIdAdapter::BookRefIdAdapter (const EnchantableColumns& columns,
@ -151,12 +174,20 @@ void CSMWorld::BookRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Book>& record = static_cast<Record<ESM::Book>&> ( Record<ESM::Book>& record = static_cast<Record<ESM::Book>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book)));
ESM::Book book = record.get();
if (column==mScroll) if (column==mScroll)
record.get().mData.mIsScroll = value.toInt(); book.mData.mIsScroll = value.toInt();
else if (column==mSkill) else if (column==mSkill)
record.get().mData.mSkillID = value.toInt(); book.mData.mSkillID = value.toInt();
else else
{
EnchantableRefIdAdapter<ESM::Book>::setData (column, data, index, value); EnchantableRefIdAdapter<ESM::Book>::setData (column, data, index, value);
return;
}
record.setModified(book);
} }
CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns, CSMWorld::ClothingRefIdAdapter::ClothingRefIdAdapter (const EnchantableColumns& columns,
@ -186,10 +217,18 @@ void CSMWorld::ClothingRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
Record<ESM::Clothing>& record = static_cast<Record<ESM::Clothing>&> ( Record<ESM::Clothing>& record = static_cast<Record<ESM::Clothing>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing)));
ESM::Clothing clothing = record.get();
if (column==mType) if (column==mType)
record.get().mData.mType = value.toInt(); clothing.mData.mType = value.toInt();
else else
{
EnchantableRefIdAdapter<ESM::Clothing>::setData (column, data, index, value); EnchantableRefIdAdapter<ESM::Clothing>::setData (column, data, index, value);
return;
}
record.setModified(clothing);
} }
CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns, CSMWorld::ContainerRefIdAdapter::ContainerRefIdAdapter (const NameColumns& columns,
@ -226,24 +265,32 @@ void CSMWorld::ContainerRefIdAdapter::setData (const RefIdColumn *column, RefIdD
Record<ESM::Container>& record = static_cast<Record<ESM::Container>&> ( Record<ESM::Container>& record = static_cast<Record<ESM::Container>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
ESM::Container container = record.get();
if (column==mWeight) if (column==mWeight)
record.get().mWeight = value.toFloat(); container.mWeight = value.toFloat();
else if (column==mOrganic) else if (column==mOrganic)
{ {
if (value.toInt()) if (value.toInt())
record.get().mFlags |= ESM::Container::Organic; container.mFlags |= ESM::Container::Organic;
else else
record.get().mFlags &= ~ESM::Container::Organic; container.mFlags &= ~ESM::Container::Organic;
} }
else if (column==mRespawn) else if (column==mRespawn)
{ {
if (value.toInt()) if (value.toInt())
record.get().mFlags |= ESM::Container::Respawn; container.mFlags |= ESM::Container::Respawn;
else else
record.get().mFlags &= ~ESM::Container::Respawn; container.mFlags &= ~ESM::Container::Respawn;
} }
else else
{
NameRefIdAdapter<ESM::Container>::setData (column, data, index, value); NameRefIdAdapter<ESM::Container>::setData (column, data, index, value);
return;
}
record.setModified(container);
} }
CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns) CSMWorld::CreatureColumns::CreatureColumns (const ActorColumns& actorColumns)
@ -303,20 +350,22 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
Record<ESM::Creature>& record = static_cast<Record<ESM::Creature>&> ( Record<ESM::Creature>& record = static_cast<Record<ESM::Creature>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
if (column==mColumns.mType) if (column==mColumns.mType)
record.get().mData.mType = value.toInt(); creature.mData.mType = value.toInt();
else if (column==mColumns.mSoul) else if (column==mColumns.mSoul)
record.get().mData.mSoul = value.toInt(); creature.mData.mSoul = value.toInt();
else if (column==mColumns.mScale) else if (column==mColumns.mScale)
record.get().mScale = value.toFloat(); creature.mScale = value.toFloat();
else if (column==mColumns.mOriginal) else if (column==mColumns.mOriginal)
record.get().mOriginal = value.toString().toUtf8().constData(); creature.mOriginal = value.toString().toUtf8().constData();
else if (column==mColumns.mCombat) else if (column==mColumns.mCombat)
record.get().mData.mCombat = value.toInt(); creature.mData.mCombat = value.toInt();
else if (column==mColumns.mMagic) else if (column==mColumns.mMagic)
record.get().mData.mMagic = value.toInt(); creature.mData.mMagic = value.toInt();
else if (column==mColumns.mStealth) else if (column==mColumns.mStealth)
record.get().mData.mStealth = value.toInt(); creature.mData.mStealth = value.toInt();
else else
{ {
std::map<const RefIdColumn *, unsigned int>::const_iterator iter = std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -325,13 +374,19 @@ void CSMWorld::CreatureRefIdAdapter::setData (const RefIdColumn *column, RefIdDa
if (iter!=mColumns.mFlags.end()) if (iter!=mColumns.mFlags.end())
{ {
if (value.toInt()!=0) if (value.toInt()!=0)
record.get().mFlags |= iter->second; creature.mFlags |= iter->second;
else else
record.get().mFlags &= ~iter->second; creature.mFlags &= ~iter->second;
} }
else else
{
ActorRefIdAdapter<ESM::Creature>::setData (column, data, index, value); ActorRefIdAdapter<ESM::Creature>::setData (column, data, index, value);
return;
}
} }
record.setModified(creature);
} }
CSMWorld::DoorRefIdAdapter::DoorRefIdAdapter (const NameColumns& columns, CSMWorld::DoorRefIdAdapter::DoorRefIdAdapter (const NameColumns& columns,
@ -361,12 +416,20 @@ void CSMWorld::DoorRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Door>& record = static_cast<Record<ESM::Door>&> ( Record<ESM::Door>& record = static_cast<Record<ESM::Door>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door)));
ESM::Door door = record.get();
if (column==mOpenSound) if (column==mOpenSound)
record.get().mOpenSound = value.toString().toUtf8().constData(); door.mOpenSound = value.toString().toUtf8().constData();
else if (column==mCloseSound) else if (column==mCloseSound)
record.get().mCloseSound = value.toString().toUtf8().constData(); door.mCloseSound = value.toString().toUtf8().constData();
else else
{
NameRefIdAdapter<ESM::Door>::setData (column, data, index, value); NameRefIdAdapter<ESM::Door>::setData (column, data, index, value);
return;
}
record.setModified(door);
} }
CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns) CSMWorld::LightColumns::LightColumns (const InventoryColumns& columns)
@ -409,14 +472,16 @@ void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Light>& record = static_cast<Record<ESM::Light>&> ( Record<ESM::Light>& record = static_cast<Record<ESM::Light>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light)));
ESM::Light light = record.get();
if (column==mColumns.mTime) if (column==mColumns.mTime)
record.get().mData.mTime = value.toInt(); light.mData.mTime = value.toInt();
else if (column==mColumns.mRadius) else if (column==mColumns.mRadius)
record.get().mData.mRadius = value.toInt(); light.mData.mRadius = value.toInt();
else if (column==mColumns.mColor) else if (column==mColumns.mColor)
record.get().mData.mColor = value.toInt(); light.mData.mColor = value.toInt();
else if (column==mColumns.mSound) else if (column==mColumns.mSound)
record.get().mSound = value.toString().toUtf8().constData(); light.mSound = value.toString().toUtf8().constData();
else else
{ {
std::map<const RefIdColumn *, unsigned int>::const_iterator iter = std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -425,13 +490,19 @@ void CSMWorld::LightRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
if (iter!=mColumns.mFlags.end()) if (iter!=mColumns.mFlags.end())
{ {
if (value.toInt()!=0) if (value.toInt()!=0)
record.get().mData.mFlags |= iter->second; light.mData.mFlags |= iter->second;
else else
record.get().mData.mFlags &= ~iter->second; light.mData.mFlags &= ~iter->second;
} }
else else
{
InventoryRefIdAdapter<ESM::Light>::setData (column, data, index, value); InventoryRefIdAdapter<ESM::Light>::setData (column, data, index, value);
return;
}
} }
record.setModified (light);
} }
CSMWorld::MiscRefIdAdapter::MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key) CSMWorld::MiscRefIdAdapter::MiscRefIdAdapter (const InventoryColumns& columns, const RefIdColumn *key)
@ -456,10 +527,18 @@ void CSMWorld::MiscRefIdAdapter::setData (const RefIdColumn *column, RefIdData&
Record<ESM::Miscellaneous>& record = static_cast<Record<ESM::Miscellaneous>&> ( Record<ESM::Miscellaneous>& record = static_cast<Record<ESM::Miscellaneous>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous)));
ESM::Miscellaneous misc = record.get();
if (column==mKey) if (column==mKey)
record.get().mData.mIsKey = value.toInt(); misc.mData.mIsKey = value.toInt();
else else
{
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value); InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
return;
}
record.setModified(misc);
} }
CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns) CSMWorld::NpcColumns::NpcColumns (const ActorColumns& actorColumns)
@ -525,16 +604,18 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d
Record<ESM::NPC>& record = static_cast<Record<ESM::NPC>&> ( Record<ESM::NPC>& record = static_cast<Record<ESM::NPC>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
if (column==mColumns.mRace) if (column==mColumns.mRace)
record.get().mRace = value.toString().toUtf8().constData(); npc.mRace = value.toString().toUtf8().constData();
else if (column==mColumns.mClass) else if (column==mColumns.mClass)
record.get().mClass = value.toString().toUtf8().constData(); npc.mClass = value.toString().toUtf8().constData();
else if (column==mColumns.mFaction) else if (column==mColumns.mFaction)
record.get().mFaction = value.toString().toUtf8().constData(); npc.mFaction = value.toString().toUtf8().constData();
else if (column==mColumns.mHair) else if (column==mColumns.mHair)
record.get().mHair = value.toString().toUtf8().constData(); npc.mHair = value.toString().toUtf8().constData();
else if (column==mColumns.mHead) else if (column==mColumns.mHead)
record.get().mHead = value.toString().toUtf8().constData(); npc.mHead = value.toString().toUtf8().constData();
else else
{ {
std::map<const RefIdColumn *, unsigned int>::const_iterator iter = std::map<const RefIdColumn *, unsigned int>::const_iterator iter =
@ -543,13 +624,23 @@ void CSMWorld::NpcRefIdAdapter::setData (const RefIdColumn *column, RefIdData& d
if (iter!=mColumns.mFlags.end()) if (iter!=mColumns.mFlags.end())
{ {
if (value.toInt()!=0) if (value.toInt()!=0)
record.get().mFlags |= iter->second; npc.mFlags |= iter->second;
else else
record.get().mFlags &= ~iter->second; npc.mFlags &= ~iter->second;
if (iter->second == ESM::NPC::Autocalc)
npc.mNpdtType = (value.toInt() != 0) ? ESM::NPC::NPC_WITH_AUTOCALCULATED_STATS
: ESM::NPC::NPC_DEFAULT;
} }
else else
{
ActorRefIdAdapter<ESM::NPC>::setData (column, data, index, value); ActorRefIdAdapter<ESM::NPC>::setData (column, data, index, value);
return;
}
} }
record.setModified (npc);
} }
CSMWorld::NpcAttributesRefIdAdapter::NpcAttributesRefIdAdapter () CSMWorld::NpcAttributesRefIdAdapter::NpcAttributesRefIdAdapter ()
@ -576,7 +667,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col
// store the whole struct // store the whole struct
npc.mNpdt52 = npc.mNpdt52 =
static_cast<const NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0); static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
record.setModified (npc); record.setModified (npc);
} }
@ -588,10 +679,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
// return the whole struct // return the whole struct
std::vector<typename ESM::NPC::NPDTstruct52> wrap; std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt52); wrap.push_back(record.get().mNpdt52);
// deleted by dtor of NestedTableStoring // deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> >(wrap); return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
} }
QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *column, QVariant CSMWorld::NpcAttributesRefIdAdapter::getNestedData (const RefIdColumn *column,
@ -694,7 +785,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column,
// store the whole struct // store the whole struct
npc.mNpdt52 = npc.mNpdt52 =
static_cast<const NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0); static_cast<const NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> > &>(nestedTable).mNestedTable.at(0);
record.setModified (npc); record.setModified (npc);
} }
@ -706,10 +797,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable (
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc))); static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
// return the whole struct // return the whole struct
std::vector<typename ESM::NPC::NPDTstruct52> wrap; std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt52); wrap.push_back(record.get().mNpdt52);
// deleted by dtor of NestedTableStoring // deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<typename ESM::NPC::NPDTstruct52> >(wrap); return new NestedTableWrapper<std::vector<ESM::NPC::NPDTstruct52> >(wrap);
} }
QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *column, QVariant CSMWorld::NpcSkillsRefIdAdapter::getNestedData (const RefIdColumn *column,

@ -99,7 +99,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
EnchantableColumns enchantableColumns (inventoryColumns); EnchantableColumns enchantableColumns (inventoryColumns);
mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Enchantment, ColumnBase::Display_Enchantment));
enchantableColumns.mEnchantment = &mColumns.back(); enchantableColumns.mEnchantment = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer)); mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer));
enchantableColumns.mEnchantmentPoints = &mColumns.back(); enchantableColumns.mEnchantmentPoints = &mColumns.back();
@ -135,7 +135,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedInventoryRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature))); new NestedInventoryRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap)); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
@ -150,7 +150,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedSpellRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature))); new NestedSpellRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap)); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String)); new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell));
// Nested table // Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations, mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations,
@ -163,7 +163,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedTravelRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature))); new NestedTravelRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap)); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String)); new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float)); new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn( mColumns.back().addColumn(
@ -289,7 +289,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedInventoryRefIdAdapter<ESM::Container> (UniversalId::Type_Container))); new NestedInventoryRefIdAdapter<ESM::Container> (UniversalId::Type_Container)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap)); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String)); new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
@ -301,7 +301,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mSoul = &mColumns.back(); creatureColumns.mSoul = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float));
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_Creature));
creatureColumns.mOriginal = &mColumns.back(); creatureColumns.mOriginal = &mColumns.back();
mColumns.push_back ( mColumns.push_back (
RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer)); RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer));
@ -409,10 +409,10 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
npcColumns.mFaction = &mColumns.back(); npcColumns.mFaction = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::Columnid_Hair, ColumnBase::Display_BodyPart));
npcColumns.mHair = &mColumns.back(); npcColumns.mHair = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_String)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart));
npcColumns.mHead = &mColumns.back(); npcColumns.mHead = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Female, ColumnBase::Display_Boolean)); mColumns.push_back (RefIdColumn (Columns::ColumnId_Female, ColumnBase::Display_Boolean));
@ -539,9 +539,9 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType)); new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String)); new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_BodyPart));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String)); new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_BodyPart));
LevListColumns levListColumns (baseColumns); LevListColumns levListColumns (baseColumns);
@ -556,7 +556,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList))); new NestedLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap)); mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String)); new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn( mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer)); new RefIdColumn (Columns::ColumnId_LevelledItemLevel, CSMWorld::ColumnBase::Display_Integer));

@ -334,9 +334,9 @@ QVariant CSMWorld::RegionMap::data (const QModelIndex& index, int role) const
mColours.find (Misc::StringUtils::lowerCase (cell->second.mRegion)); mColours.find (Misc::StringUtils::lowerCase (cell->second.mRegion));
if (iter!=mColours.end()) if (iter!=mColours.end())
return QBrush ( return QBrush (QColor (iter->second & 0xff,
QColor (iter->second>>24, (iter->second>>16) & 255, (iter->second>>8) & 255, (iter->second >> 8) & 0xff,
iter->second & 255)); (iter->second >> 16) & 0xff));
if (cell->second.mRegion.empty()) if (cell->second.mRegion.empty())
return QBrush (Qt::Dense6Pattern); // no region return QBrush (Qt::Dense6Pattern); // no region

@ -5,61 +5,49 @@
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <algorithm>
#include <OgreResourceGroupManager.h> #include <components/vfs/manager.hpp>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
CSMWorld::Resources::Resources (const std::string& baseDirectory, UniversalId::Type type, CSMWorld::Resources::Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type,
const char * const *extensions) const char * const *extensions)
: mBaseDirectory (baseDirectory), mType (type) : mBaseDirectory (baseDirectory), mType (type)
{ {
int baseSize = mBaseDirectory.size(); int baseSize = mBaseDirectory.size();
Ogre::StringVector resourcesGroups = const std::map<std::string, VFS::File*>& index = vfs->getIndex();
Ogre::ResourceGroupManager::getSingleton().getResourceGroups(); for (std::map<std::string, VFS::File*>::const_iterator it = index.begin(); it != index.end(); ++it)
for (Ogre::StringVector::iterator iter (resourcesGroups.begin());
iter!=resourcesGroups.end(); ++iter)
{ {
if (*iter=="General" || *iter=="Internal" || *iter=="Autodetect") std::string filepath = it->first;
if (static_cast<int> (filepath.size())<baseSize+1 ||
filepath.substr (0, baseSize)!=mBaseDirectory ||
(filepath[baseSize]!='/' && filepath[baseSize]!='\\'))
continue; continue;
Ogre::StringVectorPtr resources = if (extensions)
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 || std::string::size_type index = filepath.find_last_of ('.');
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) if (index==std::string::npos)
continue; continue;
std::string extension = iter->substr (index+1);
int i = 0; std::string extension = filepath.substr (index+1);
for (; extensions[i]; ++i) int i = 0;
if (extensions[i]==extension)
break;
if (!extensions[i]) for (; extensions[i]; ++i)
continue; if (extensions[i]==extension)
} break;
std::string file = iter->substr (baseSize+1); if (!extensions[i])
mFiles.push_back (file); continue;
std::replace (file.begin(), file.end(), '\\', '/');
mIndex.insert (std::make_pair (
Misc::StringUtils::lowerCase (file), static_cast<int> (mFiles.size())-1));
} }
std::string file = filepath.substr (baseSize+1);
mFiles.push_back (file);
std::replace (file.begin(), file.end(), '\\', '/');
mIndex.insert (std::make_pair (
Misc::StringUtils::lowerCase (file), static_cast<int> (mFiles.size())-1));
} }
} }

@ -7,6 +7,11 @@
#include "universalid.hpp" #include "universalid.hpp"
namespace VFS
{
class Manager;
}
namespace CSMWorld namespace CSMWorld
{ {
class Resources class Resources
@ -19,7 +24,7 @@ namespace CSMWorld
public: public:
/// \param type Type of resources in this table. /// \param type Type of resources in this table.
Resources (const std::string& baseDirectory, UniversalId::Type type, Resources (const VFS::Manager* vfs, const std::string& baseDirectory, UniversalId::Type type,
const char * const *extensions = 0); const char * const *extensions = 0);
int getSize() const; int getSize() const;

@ -3,6 +3,11 @@
#include <stdexcept> #include <stdexcept>
CSMWorld::ResourcesManager::ResourcesManager()
: mVFS(NULL)
{
}
void CSMWorld::ResourcesManager::addResources (const Resources& resources) void CSMWorld::ResourcesManager::addResources (const Resources& resources)
{ {
mResources.insert (std::make_pair (resources.getType(), resources)); mResources.insert (std::make_pair (resources.getType(), resources));
@ -10,16 +15,24 @@ void CSMWorld::ResourcesManager::addResources (const Resources& resources)
resources)); resources));
} }
void CSMWorld::ResourcesManager::listResources() void CSMWorld::ResourcesManager::setVFS(const VFS::Manager *vfs)
{ {
mVFS = vfs;
mResources.clear();
static const char * const sMeshTypes[] = { "nif", 0 }; static const char * const sMeshTypes[] = { "nif", 0 };
addResources (Resources ("meshes", UniversalId::Type_Mesh, sMeshTypes)); addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes));
addResources (Resources ("icons", UniversalId::Type_Icon)); addResources (Resources (vfs, "icons", UniversalId::Type_Icon));
addResources (Resources ("music", UniversalId::Type_Music)); addResources (Resources (vfs, "music", UniversalId::Type_Music));
addResources (Resources ("sound", UniversalId::Type_SoundRes)); addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes));
addResources (Resources ("textures", UniversalId::Type_Texture)); addResources (Resources (vfs, "textures", UniversalId::Type_Texture));
addResources (Resources ("videos", UniversalId::Type_Video)); addResources (Resources (vfs, "videos", UniversalId::Type_Video));
}
const VFS::Manager* CSMWorld::ResourcesManager::getVFS() const
{
return mVFS;
} }
const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const

@ -6,11 +6,17 @@
#include "universalid.hpp" #include "universalid.hpp"
#include "resources.hpp" #include "resources.hpp"
namespace VFS
{
class Manager;
}
namespace CSMWorld namespace CSMWorld
{ {
class ResourcesManager class ResourcesManager
{ {
std::map<UniversalId::Type, Resources> mResources; std::map<UniversalId::Type, Resources> mResources;
const VFS::Manager* mVFS;
private: private:
@ -18,8 +24,11 @@ namespace CSMWorld
public: public:
/// Ask OGRE for a list of available resources. ResourcesManager();
void listResources();
const VFS::Manager* getVFS() const;
void setVFS(const VFS::Manager* vfs);
const Resources& get (UniversalId::Type type) const; const Resources& get (UniversalId::Type type) const;
}; };

@ -264,6 +264,8 @@ namespace
{ CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture }, { CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture },
{ CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video }, { CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video },
{ CSMWorld::UniversalId::Type_Global, CSMWorld::ColumnBase::Display_GlobalVariable }, { CSMWorld::UniversalId::Type_Global, CSMWorld::ColumnBase::Display_GlobalVariable },
{ CSMWorld::UniversalId::Type_BodyPart, CSMWorld::ColumnBase::Display_BodyPart },
{ CSMWorld::UniversalId::Type_Enchantment, CSMWorld::ColumnBase::Display_Enchantment },
{ CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker { CSMWorld::UniversalId::Type_None, CSMWorld::ColumnBase::Display_None } // end marker
}; };

@ -56,6 +56,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MagicEffects, "Magic Effects", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Pathgrids, "Pathgrids", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 }, { CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_StartScripts, "Start Scripts", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_MetaDatas, "Meta Data Table", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };
@ -120,6 +121,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MagicEffect, "Magic Effect", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Pathgrid, "Pathgrid", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 }, { CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_StartScript, "Start Script", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_MetaData, "Meta Data", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker { CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
}; };

@ -131,6 +131,8 @@ namespace CSMWorld
Type_StartScripts, Type_StartScripts,
Type_StartScript, Type_StartScript,
Type_Search, Type_Search,
Type_MetaDatas,
Type_MetaData,
Type_RunLog Type_RunLog
}; };

@ -33,6 +33,11 @@ void CSVDoc::FileDialog::addFiles(const QString &path)
mSelector->addFiles(path); mSelector->addFiles(path);
} }
void CSVDoc::FileDialog::clearFiles()
{
mSelector->clearFiles();
}
QStringList CSVDoc::FileDialog::selectedFilePaths() QStringList CSVDoc::FileDialog::selectedFilePaths()
{ {
QStringList filePaths; QStringList filePaths;
@ -105,7 +110,6 @@ void CSVDoc::FileDialog::buildNewFileView()
connect (mFileWidget, SIGNAL (nameChanged(const QString &, bool)), connect (mFileWidget, SIGNAL (nameChanged(const QString &, bool)),
this, SLOT (slotUpdateAcceptButton(const QString &, bool))); this, SLOT (slotUpdateAcceptButton(const QString &, bool)));
} }
ui.projectGroupBoxLayout->insertWidget (0, mFileWidget); ui.projectGroupBoxLayout->insertWidget (0, mFileWidget);
@ -139,7 +143,7 @@ void CSVDoc::FileDialog::slotUpdateAcceptButton(int)
{ {
QString name = ""; QString name = "";
if (mAction == ContentAction_New) if (mFileWidget && mAction == ContentAction_New)
name = mFileWidget->getName(); name = mFileWidget->getName();
slotUpdateAcceptButton (name, true); slotUpdateAcceptButton (name, true);

@ -45,6 +45,7 @@ namespace CSVDoc
void showDialog (ContentAction action); void showDialog (ContentAction action);
void addFiles (const QString &path); void addFiles (const QString &path);
void clearFiles ();
QString filename() const; QString filename() const;
QStringList selectedFilePaths(); QStringList selectedFilePaths();

@ -45,6 +45,7 @@ void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id)
{ {
mUniversalId = id; mUniversalId = id;
setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str())); setWindowTitle (QString::fromUtf8(mUniversalId.toString().c_str()));
emit universalIdChanged (mUniversalId);
} }
void CSVDoc::SubView::closeEvent (QCloseEvent *event) void CSVDoc::SubView::closeEvent (QCloseEvent *event)

@ -68,6 +68,8 @@ namespace CSVDoc
void updateSubViewIndicies (SubView *view = 0); void updateSubViewIndicies (SubView *view = 0);
void universalIdChanged (const CSMWorld::UniversalId& universalId);
protected slots: protected slots:
void closeRequest(); void closeRequest();

@ -7,7 +7,7 @@
#include <QMenuBar> #include <QMenuBar>
#include <QMdiArea> #include <QMdiArea>
#include <QDockWidget> #include <QDockWidget>
#include <QtGui/QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QScrollArea> #include <QScrollArea>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -70,6 +70,10 @@ void CSVDoc::View::setupFileMenu()
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog())); connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
file->addAction (loadErrors); file->addAction (loadErrors);
QAction *meta = new QAction (tr ("Meta Data"), this);
connect (meta, SIGNAL (triggered()), this, SLOT (addMetaDataSubView()));
file->addAction (meta);
QAction *close = new QAction (tr ("&Close"), this); QAction *close = new QAction (tr ("&Close"), this);
connect (close, SIGNAL (triggered()), this, SLOT (close())); connect (close, SIGNAL (triggered()), this, SLOT (close()));
file->addAction(close); file->addAction(close);
@ -515,6 +519,10 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
} }
} }
if (mScroll)
QObject::connect(mScroll->horizontalScrollBar(),
SIGNAL(rangeChanged(int,int)), this, SLOT(moveScrollBarToEnd(int,int)));
// User setting for limiting the number of sub views per top level view. // User setting for limiting the number of sub views per top level view.
// Automatically open a new top level view if this number is exceeded // Automatically open a new top level view if this number is exceeded
// //
@ -586,12 +594,6 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minWidth); mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minWidth);
move(0, y()); move(0, y());
} }
// Make the new subview visible, setFocus() or raise() don't seem to work
// On Ubuntu the scrollbar does not go right to the end, even if using
// mScroll->horizontalScrollBar()->setValue(mScroll->horizontalScrollBar()->maximum());
if (mSubViewWindow.width() > rect.width())
mScroll->horizontalScrollBar()->setValue(mSubViewWindow.width());
} }
mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view);
@ -614,6 +616,17 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
view->useHint (hint); view->useHint (hint);
} }
void CSVDoc::View::moveScrollBarToEnd(int min, int max)
{
if (mScroll)
{
mScroll->horizontalScrollBar()->setValue(max);
QObject::disconnect(mScroll->horizontalScrollBar(),
SIGNAL(rangeChanged(int,int)), this, SLOT(moveScrollBarToEnd(int,int)));
}
}
void CSVDoc::View::newView() void CSVDoc::View::newView()
{ {
mViewManager.addView (mDocument); mViewManager.addView (mDocument);
@ -804,6 +817,11 @@ void CSVDoc::View::addSearchSubView()
addSubView (mDocument->newSearch()); addSubView (mDocument->newSearch());
} }
void CSVDoc::View::addMetaDataSubView()
{
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta"));
}
void CSVDoc::View::abortOperation (int type) void CSVDoc::View::abortOperation (int type)
{ {
mDocument->abortOperation (type); mDocument->abortOperation (type);

@ -224,6 +224,8 @@ namespace CSVDoc
void addSearchSubView(); void addSearchSubView();
void addMetaDataSubView();
void toggleShowStatusBar (bool show); void toggleShowStatusBar (bool show);
void loadErrorLog(); void loadErrorLog();
@ -233,6 +235,8 @@ namespace CSVDoc
void stop(); void stop();
void closeRequest (SubView *subView); void closeRequest (SubView *subView);
void moveScrollBarToEnd(int min, int max);
}; };
} }

@ -1,30 +1,32 @@
#include "viewmanager.hpp" #include "viewmanager.hpp"
#include <vector>
#include <map> #include <map>
#include <QApplication> #include <QApplication>
#include <QDesktopWidget> #include <QDesktopWidget>
#include <QMessageBox>
#include <QPushButton>
#include "../../model/doc/documentmanager.hpp" #include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp" #include "../../model/doc/document.hpp"
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/universalid.hpp" #include "../../model/world/universalid.hpp"
#include "../../model/world/idcompletionmanager.hpp"
#include "../world/util.hpp" #include "../world/util.hpp"
#include "../world/enumdelegate.hpp" #include "../world/enumdelegate.hpp"
#include "../world/vartypedelegate.hpp" #include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp" #include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp" #include "../world/idtypedelegate.hpp"
#include "../world/idcompletiondelegate.hpp"
#include "../world/colordelegate.hpp"
#include "../../model/settings/usersettings.hpp" #include "../../model/settings/usersettings.hpp"
#include "view.hpp" #include "view.hpp"
#include <QMessageBox>
#include <QPushButton>
#include <QtGui/QApplication>
void CSVDoc::ViewManager::updateIndices() void CSVDoc::ViewManager::updateIndices()
{ {
std::map<CSMDoc::Document *, std::pair<int, int> > documents; std::map<CSMDoc::Document *, std::pair<int, int> > documents;
@ -60,6 +62,17 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType, mDelegateFactories->add (CSMWorld::ColumnBase::Display_RefRecordType,
new CSVWorld::IdTypeDelegateFactory()); new CSVWorld::IdTypeDelegateFactory());
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Colour,
new CSVWorld::ColorDelegateFactory());
std::vector<CSMWorld::ColumnBase::Display> idCompletionColumns = CSMWorld::IdCompletionManager::getDisplayTypes();
for (std::vector<CSMWorld::ColumnBase::Display>::const_iterator current = idCompletionColumns.begin();
current != idCompletionColumns.end();
++current)
{
mDelegateFactories->add(*current, new CSVWorld::IdCompletionDelegateFactory());
}
struct Mapping struct Mapping
{ {
CSMWorld::ColumnBase::Display mDisplay; CSMWorld::ColumnBase::Display mDisplay;

@ -1,8 +1,7 @@
#include "cell.hpp" #include "cell.hpp"
#include <OgreSceneManager.h> #include <osg/Group>
#include <OgreSceneNode.h>
#include <components/misc/stringops.hpp> #include <components/misc/stringops.hpp>
#include <components/esm/loadland.hpp> #include <components/esm/loadland.hpp>
@ -11,7 +10,6 @@
#include "../../model/world/columns.hpp" #include "../../model/world/columns.hpp"
#include "../../model/world/data.hpp" #include "../../model/world/data.hpp"
#include "../../model/world/refcollection.hpp" #include "../../model/world/refcollection.hpp"
#include "../world/physicssystem.hpp"
#include "elements.hpp" #include "elements.hpp"
#include "terrainstorage.hpp" #include "terrainstorage.hpp"
@ -45,7 +43,7 @@ bool CSVRender::Cell::addObjects (int start, int end)
{ {
std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId); std::string id = Misc::StringUtils::lowerCase (collection.getRecord (i).get().mId);
mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false, mPhysics))); mObjects.insert (std::make_pair (id, new Object (mData, mCellNode, id, false)));
modified = true; modified = true;
} }
} }
@ -53,12 +51,11 @@ bool CSVRender::Cell::addObjects (int start, int end)
return modified; return modified;
} }
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id)
const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin) : mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0)
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mPhysics(physics), mSceneMgr(sceneManager), mX(0), mY(0)
{ {
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode(); mCellNode = new osg::Group;
mCellNode->setPosition (origin); rootNode->addChild(mCellNode);
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> ( CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*mData.getTableModel (CSMWorld::UniversalId::Type_References)); *mData.getTableModel (CSMWorld::UniversalId::Type_References));
@ -74,31 +71,23 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get(); const ESM::Land* esmLand = land.getRecord(mId).get().mLand.get();
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT) if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
{ {
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true, mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
Terrain::Align_XY));
mTerrain->loadCell(esmLand->mX, mTerrain->loadCell(esmLand->mX,
esmLand->mY); esmLand->mY);
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
mX = esmLand->mX; mX = esmLand->mX;
mY = esmLand->mY; mY = esmLand->mY;
mPhysics->addHeightField(sceneManager,
esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts);
} }
} }
} }
CSVRender::Cell::~Cell() CSVRender::Cell::~Cell()
{ {
if (mTerrain.get())
mPhysics->removeHeightField(mSceneMgr, mX, mY);
for (std::map<std::string, Object *>::iterator iter (mObjects.begin()); for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter) iter!=mObjects.end(); ++iter)
delete iter->second; delete iter->second;
mCellNode->getCreator()->destroySceneNode (mCellNode); mCellNode->getParent(0)->removeChild(mCellNode);
} }
bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft, bool CSVRender::Cell::referenceableDataChanged (const QModelIndex& topLeft,
@ -186,7 +175,7 @@ bool CSVRender::Cell::referenceDataChanged (const QModelIndex& topLeft,
for (std::map<std::string, bool>::iterator iter (ids.begin()); iter!=ids.end(); ++iter) for (std::map<std::string, bool>::iterator iter (ids.begin()); iter!=ids.end(); ++iter)
{ {
mObjects.insert (std::make_pair ( mObjects.insert (std::make_pair (
iter->first, new Object (mData, mCellNode, iter->first, false, mPhysics))); iter->first, new Object (mData, mCellNode, iter->first, false)));
modified = true; modified = true;
} }
@ -222,11 +211,3 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
return addObjects (start, end); return addObjects (start, end);
} }
float CSVRender::Cell::getTerrainHeightAt(const Ogre::Vector3 &pos) const
{
if(mTerrain.get() != NULL)
return mTerrain->getHeightAt(pos);
else
return -std::numeric_limits<float>::max();
}

@ -7,7 +7,7 @@
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <OgreVector3.h> #include <osg/ref_ptr>
#ifndef Q_MOC_RUN #ifndef Q_MOC_RUN
#include <components/terrain/terraingrid.hpp> #include <components/terrain/terraingrid.hpp>
@ -17,10 +17,9 @@
class QModelIndex; class QModelIndex;
namespace Ogre namespace osg
{ {
class SceneManager; class Group;
class SceneNode;
} }
namespace CSMWorld namespace CSMWorld
@ -28,22 +27,15 @@ namespace CSMWorld
class Data; class Data;
} }
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSVRender namespace CSVRender
{ {
class Cell class Cell
{ {
CSMWorld::Data& mData; CSMWorld::Data& mData;
std::string mId; std::string mId;
Ogre::SceneNode *mCellNode; osg::ref_ptr<osg::Group> mCellNode;
std::map<std::string, Object *> mObjects; std::map<std::string, Object *> mObjects;
std::auto_ptr<Terrain::TerrainGrid> mTerrain; std::auto_ptr<Terrain::TerrainGrid> mTerrain;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
Ogre::SceneManager *mSceneMgr;
int mX; int mX;
int mY; int mY;
@ -59,8 +51,7 @@ namespace CSVRender
public: public:
Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id, Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id);
boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0));
~Cell(); ~Cell();
@ -84,8 +75,6 @@ namespace CSVRender
/// \return Did this call result in a modification of the visual representation of /// \return Did this call result in a modification of the visual representation of
/// this cell? /// this cell?
bool referenceAdded (const QModelIndex& parent, int start, int end); bool referenceAdded (const QModelIndex& parent, int start, int end);
float getTerrainHeightAt(const Ogre::Vector3 &pos) const;
}; };
} }

@ -1,4 +1,5 @@
#include "lighting.hpp" #include "lighting.hpp"
#include <osg/LightSource>
CSVRender::Lighting::~Lighting() {} CSVRender::Lighting::~Lighting() {}

@ -1,10 +1,13 @@
#ifndef OPENCS_VIEW_LIGHTING_H #ifndef OPENCS_VIEW_LIGHTING_H
#define OPENCS_VIEW_LIGHTING_H #define OPENCS_VIEW_LIGHTING_H
namespace Ogre #include <osg/ref_ptr>
namespace osg
{ {
class SceneManager; class Vec4f;
class ColourValue; class LightSource;
class Group;
} }
namespace CSVRender namespace CSVRender
@ -13,14 +16,19 @@ namespace CSVRender
{ {
public: public:
Lighting() : mRootNode(0) {}
virtual ~Lighting(); virtual ~Lighting();
virtual void activate (Ogre::SceneManager *sceneManager, virtual void activate (osg::Group* rootNode) = 0;
const Ogre::ColourValue *defaultAmbient = 0) = 0;
virtual void deactivate() = 0; virtual void deactivate() = 0;
virtual void setDefaultAmbient (const Ogre::ColourValue& colour) = 0; virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient) = 0;
protected:
osg::ref_ptr<osg::LightSource> mLightSource;
osg::Group* mRootNode;
}; };
} }

@ -1,30 +1,35 @@
#include "lightingbright.hpp" #include "lightingbright.hpp"
#include <OgreSceneManager.h> #include <osg/LightSource>
CSVRender::LightingBright::LightingBright() : mSceneManager (0), mLight (0) {} CSVRender::LightingBright::LightingBright() {}
void CSVRender::LightingBright::activate (Ogre::SceneManager *sceneManager, void CSVRender::LightingBright::activate (osg::Group* rootNode)
const Ogre::ColourValue *defaultAmbient)
{ {
mSceneManager = sceneManager; mRootNode = rootNode;
mSceneManager->setAmbientLight (Ogre::ColourValue (1.0, 1.0, 1.0, 1)); mLightSource = (new osg::LightSource);
mLight = mSceneManager->createLight(); osg::ref_ptr<osg::Light> light (new osg::Light);
mLight->setType (Ogre::Light::LT_DIRECTIONAL); light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f));
mLight->setDirection (Ogre::Vector3 (0, 0, -1)); light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f));
mLight->setDiffuseColour (Ogre::ColourValue (1.0, 1.0, 1.0)); light->setDiffuse(osg::Vec4f(1.f, 1.f, 1.f, 1.f));
light->setSpecular(osg::Vec4f(0.f, 0.f, 0.f, 0.f));
light->setConstantAttenuation(1.f);
mLightSource->setLight(light);
mRootNode->addChild(mLightSource);
} }
void CSVRender::LightingBright::deactivate() void CSVRender::LightingBright::deactivate()
{ {
if (mLight) if (mRootNode && mLightSource.get())
{ mRootNode->removeChild(mLightSource);
mSceneManager->destroyLight (mLight);
mLight = 0;
}
} }
void CSVRender::LightingBright::setDefaultAmbient (const Ogre::ColourValue& colour) {} osg::Vec4f CSVRender::LightingBright::getAmbientColour(osg::Vec4f* /*defaultAmbient*/)
{
return osg::Vec4f(1.f, 1.f, 1.f, 1.f);
}

@ -3,28 +3,25 @@
#include "lighting.hpp" #include "lighting.hpp"
namespace Ogre namespace osg
{ {
class Light; class Light;
class Group;
} }
namespace CSVRender namespace CSVRender
{ {
class LightingBright : public Lighting class LightingBright : public Lighting
{ {
Ogre::SceneManager *mSceneManager;
Ogre::Light *mLight;
public: public:
LightingBright(); LightingBright();
virtual void activate (Ogre::SceneManager *sceneManager, virtual void activate (osg::Group* rootNode);
const Ogre::ColourValue *defaultAmbient = 0);
virtual void deactivate(); virtual void deactivate();
virtual void setDefaultAmbient (const Ogre::ColourValue& colour); virtual osg::Vec4f getAmbientColour(osg::Vec4f* defaultAmbient);
}; };
} }

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

Loading…
Cancel
Save