Merge branch 'master' into appveyor

coverity_scan
Alexander "Ace" Olofsson 10 years ago
commit 6d25dc299f

@ -1,6 +1,6 @@
os:
- linux
- osx
# - osx
language: cpp
branches:
only:
@ -38,7 +38,7 @@ before_script:
- if [ "${TRAVIS_OS_NAME}" = "osx" ]; then ./CI/before_script.osx.sh; fi
script:
- 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
after_script:
- 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
sudo apt-get update -qq
sudo apt-get install -qq libgtest-dev google-mock
sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
sudo apt-get install -qq 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 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
sudo mkdir /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")
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(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)
# Apps and tools
option(BUILD_OPENMW "build OpenMW" ON)
option(BUILD_BSATOOL "build BSA extractor" ON)
option(BUILD_ESMTOOL "build ESM inspector" 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_WITH_CODE_COVERAGE "Enable code coverage with gconv" 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)
# OS X deployment
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
if (APPLE)
set(MORROWIND_DATA_FILES "./data" CACHE PATH "location of Morrowind data files")
@ -98,24 +100,30 @@ endif()
cmake_minimum_required(VERSION 2.6)
# Sound setup
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
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 )
message(FATAL_ERROR "FFmpeg component required, but not found!")
endif()
set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
if( SWRESAMPLE_FOUND )
add_definitions(-DHAVE_LIBSWRESAMPLE)
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${SWRESAMPLE_LIBRARIES})
else()
if( AVRESAMPLE_FOUND )
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
set (FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
else()
message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
endif()
endif()
# Required for building the FFmpeg headers
add_definitions(-D__STDC_CONSTANT_MACROS)
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES})
# TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
@ -136,21 +144,32 @@ endif()
if (WIN32)
if(NOT MINGW)
set(Boost_USE_STATIC_LIBS ON)
set(PLATFORM_INCLUDE_DIR "platform")
add_definitions(-DBOOST_ALL_NO_LIB)
endif(NOT MINGW)
# Suppress WinMain(), provided by SDL
add_definitions(-DSDL_MAIN_HANDLED)
else (WIN32)
set(PLATFORM_INCLUDE_DIR "")
endif (WIN32)
if (MSVC10)
set(PLATFORM_INCLUDE_DIR "")
# Get rid of useless crud from windows.h
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
endif()
# 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
if (UNIX AND NOT APPLE)
find_package (Threads)
@ -171,7 +190,7 @@ if (HAVE_UNORDERED_MAP)
endif ()
set(BOOST_COMPONENTS system filesystem program_options)
set(BOOST_COMPONENTS system filesystem program_options thread)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
@ -180,10 +199,8 @@ IF(BOOST_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif()
find_package(OGRE REQUIRED)
if (${OGRE_VERSION} VERSION_LESS "1.9")
message(FATAL_ERROR "OpenMW requires Ogre 1.9 or later, please install the latest stable version from http://ogre3d.org")
endif()
find_package(OpenSceneGraph 3.2.0 REQUIRED osgDB osgViewer osgGA osgAnimation osgParticle osgQt osgUtil osgFX)
include_directories(${OPENSCENEGRAPH_INCLUDE_DIRS})
find_package(MyGUI REQUIRED)
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
@ -195,87 +212,22 @@ find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Bullet REQUIRED)
set(OGRE_PLUGIN_INCLUDE_DIRS "")
set(OGRE_STATIC_PLUGINS "")
macro(add_static_ogre_plugin PLUGIN)
if(OGRE_${PLUGIN}_FOUND)
# strip RenderSystem_ or Plugin_ prefix from plugin name
string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN})
string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP})
add_definitions(-DENABLE_PLUGIN_${PLUGIN_NAME})
list(APPEND OGRE_PLUGIN_INCLUDE_DIRS ${OGRE_${PLUGIN}_INCLUDE_DIRS})
list(APPEND OGRE_STATIC_PLUGINS ${OGRE_${PLUGIN}_LIBRARIES})
endif(OGRE_${PLUGIN}_FOUND)
endmacro(add_static_ogre_plugin)
if(OGRE_STATIC)
# set up OGRE_PLUGIN_INCLUDE_DIRS and OGRE_STATIC_PLUGINS
add_static_ogre_plugin(Plugin_OctreeSceneManager)
add_static_ogre_plugin(Plugin_ParticleFX)
find_package(Cg)
if(Cg_FOUND)
add_static_ogre_plugin(Plugin_CgProgramManager)
list(APPEND OGRE_STATIC_PLUGINS ${Cg_LIBRARIES})
endif(Cg_FOUND)
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}
include_directories("."
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}
${Boost_INCLUDE_DIR}
${PLATFORM_INCLUDE_DIR}
${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${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)
add_definitions(-DMYGUI_STATIC)
endif (MYGUI_STATIC)
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
"${APP_BUNDLE_DIR}/Contents/Info.plist")
@ -286,30 +238,7 @@ endif (APPLE)
# Set up DEBUG define
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/mygui)
# Specify build paths
@ -326,9 +255,6 @@ endif (APPLE)
configure_file(${OpenMW_SOURCE_DIR}/files/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
"${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)
elseif (MSVC)
# Enable link-time code generation globally for all linking
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_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")
if (OPENMW_LTO_BUILD)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /GL")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_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)
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")
# 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)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-launcher" DESTINATION "${BINDIR}" )
ENDIF(BUILD_LAUNCHER)
@ -413,19 +345,15 @@ IF(NOT WIN32 AND NOT APPLE)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-cs" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENCS)
IF(BUILD_NIFTEST)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
ENDIF(BUILD_NIFTEST)
IF(BUILD_WIZARD)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw-wizard" DESTINATION "${BINDIR}" )
ENDIF(BUILD_WIZARD)
if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
ENDIF(BUILD_MYGUI_PLUGIN)
#if(BUILD_MYGUI_PLUGIN)
# INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Plugin_MyGUI_OpenMW_Resources.so" DESTINATION "${LIBDIR}" )
#ENDIF(BUILD_MYGUI_PLUGIN)
# Install licenses
INSTALL(FILES "docs/license/DejaVu Font License.txt" DESTINATION "${LICDIR}" )
INSTALL(FILES "extern/shiny/License.txt" DESTINATION "${LICDIR}" RENAME "Shiny License.txt" )
# Install icon and desktop file
INSTALL(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(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}/gamecontrollerdb.txt" DESTINATION "${SYSCONFDIR}" COMPONENT "openmw")
@ -460,7 +387,6 @@ if(WIN32)
"${OpenMW_SOURCE_DIR}/Docs/license/GPL3.txt"
"${OpenMW_SOURCE_DIR}/Docs/license/DejaVu Font License.txt"
"${OpenMW_BINARY_DIR}/settings-default.cfg"
"${OpenMW_BINARY_DIR}/transparency-overrides.cfg"
"${OpenMW_BINARY_DIR}/gamecontrollerdb.txt"
"${OpenMW_BINARY_DIR}/Release/openmw.exe"
DESTINATION ".")
@ -486,6 +412,8 @@ if(WIN32)
ENDIF(BUILD_MYGUI_PLUGIN)
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_PACKAGE_NAME "OpenMW")
@ -546,31 +474,22 @@ if(WIN32)
include(CPack)
endif(WIN32)
# Libs
include_directories(libs)
add_subdirectory(libs/openengine)
# Extern
add_subdirectory (extern/shiny)
add_subdirectory (extern/ogre-ffmpeg-videoplayer)
add_subdirectory (extern/osg-ffmpeg-videoplayer)
add_subdirectory (extern/oics)
add_subdirectory (extern/sdl4ogre)
# Components
add_subdirectory (components)
# Plugins
if (BUILD_MYGUI_PLUGIN)
add_subdirectory(plugins/mygui_resource_plugin)
endif()
#Testing
if (BUILD_NIFTEST)
add_subdirectory(components/nif/tests/)
endif(BUILD_NIFTEST)
#if (BUILD_MYGUI_PLUGIN)
# add_subdirectory(plugins/mygui_resource_plugin)
#endif()
# Apps and tools
add_subdirectory( apps/openmw )
if (BUILD_OPENMW)
add_subdirectory( apps/openmw )
endif()
if (BUILD_BSATOOL)
add_subdirectory( apps/bsatool )
@ -607,9 +526,9 @@ endif()
if (WIN32)
if (MSVC)
if (MULTITHREADED_BUILD)
if (OPENMW_MP_BUILD)
set( MT_BUILD "/MP")
endif (MULTITHREADED_BUILD)
endif()
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
@ -617,20 +536,22 @@ if (WIN32)
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" )
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_RELWITHDEBINFO "/SUBSYSTEM: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
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:WINDOWS")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:WINDOWS")
endif()
# Release builds use the debug console
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES COMPILE_DEFINITIONS_RELEASE "_CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE")
if (BUILD_OPENMW)
# Release builds use the debug console
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELEASE "/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
@ -639,8 +560,8 @@ if (WIN32)
set(WARNINGS_DISABLE
# Warnings that aren't enabled normally and don't need to be enabled
# 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
4061 4263 4264 4266 4350 4371 4514 4548 4571 4610 4619 4623 4625 4626 4628 4640 4668 4710 4711 4820 4826 4917 4946
# Not going to bother commenting them as they tend to warn on every standard library file
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
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)
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
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
@ -668,6 +583,7 @@ if (WIN32)
4127 # Conditional expression is constant
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)
4245 # Signed/unsigned mismatch
4267 # Conversion from 'size_t' to 'int', possible loss of data
4305 # Truncating value (double to float, 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}")
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
set(SHINY_WARNINGS "${WARNINGS} /wd4245")
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
# oics uses tinyxml, which has an initialized but unused variable
set(OICS_WARNINGS "${WARNINGS} /wd4189")
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")
if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${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)
# QT triggers an informational warning that the object layout may differ when compiled with /vd2
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435")
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS})
endif (BUILD_OPENCS)
set_target_properties(openmw-cs PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif()
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)
# 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}/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}/transparency-overrides.cfg" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
install(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION "${INSTALL_SUBDIR}" COMPONENT Runtime)
set(CPACK_GENERATOR "DragNDrop")
@ -728,90 +664,14 @@ if (APPLE)
set(OPENCS_BUNDLE_NAME "OpenMW-CS.app")
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 "
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities)
" 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
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)
endif (APPLE)

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

@ -1,4 +1,5 @@
#include <iostream>
#include <iomanip>
#include <vector>
#include <exception>
@ -237,12 +238,14 @@ int extract(Bsa::BSAFile& bsa, Arguments& info)
}
// 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);
// Write the file to disk
std::cout << "Extracting " << info.extractfile << " to " << target << std::endl;
out.write(data->getAsString().c_str(), data->size());
out << stream->rdbuf();
out.close();
return 0;
@ -276,12 +279,12 @@ int extractAll(Bsa::BSAFile& bsa, Arguments& info)
// Get a stream for the file to extract
// (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);
// Write the file to disk
std::cout << "Extracting " << target << std::endl;
out.write(data->getAsString().c_str(), data->size());
out << data->rdbuf();
out.close();
}

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

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

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

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

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

@ -2,8 +2,7 @@
#include <stdexcept>
#include <OgreImage.h>
#include <OgreColourValue.h>
#include <osgDB/WriteFile>
#include <components/esm/creaturestate.hpp>
#include <components/esm/containerstate.hpp>
@ -15,12 +14,14 @@
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;
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(data, size));
screenshot.loadRawData(stream, width, height, 1, pf);
screenshot.save(out);
osg::ref_ptr<osg::Image> image (new osg::Image);
image->allocateImage(width, height, 1, pf, GL_UNSIGNED_BYTE);
memcpy(image->data(), data, size);
image->flipVertical();
osgDB::writeImageFile(*image, out);
}
@ -71,17 +72,20 @@ namespace ESSImport
data.resize(esm.getSubSize());
esm.getExact(&data[0], data.size());
Ogre::DataStreamPtr stream (new Ogre::MemoryDataStream(&data[0], data.size()));
mGlobalMapImage.loadRawData(stream, maph.size, maph.size, 1, Ogre::PF_BYTE_RGB);
mGlobalMapImage = new osg::Image;
mGlobalMapImage->allocateImage(maph.size, maph.size, 1, GL_RGB, GL_UNSIGNED_BYTE);
memcpy(mGlobalMapImage->data(), &data[0], data.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)
{
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
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)
@ -90,12 +94,14 @@ namespace ESSImport
mContext->mGlobalMapState.mBounds.mMinY = -(numcells-1)/2;
mContext->mGlobalMapState.mBounds.mMaxY = numcells/2;
Ogre::Image image2;
std::vector<Ogre::uint8> data;
osg::ref_ptr<osg::Image> image2 (new osg::Image);
int width = cellSize*numcells;
int height = cellSize*numcells;
std::vector<unsigned char> data;
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)
{
@ -108,8 +114,8 @@ namespace ESSImport
continue;
}
int imageLeftSrc = mGlobalMapImage.getWidth()/2;
int imageTopSrc = mGlobalMapImage.getHeight()/2;
int imageLeftSrc = mGlobalMapImage->s()/2;
int imageTopSrc = mGlobalMapImage->t()/2;
imageLeftSrc += it->first * cellSize;
imageTopSrc -= it->second * cellSize;
int imageLeftDst = width/2;
@ -118,13 +124,31 @@ namespace ESSImport
imageTopDst -= it->second * cellSize;
for (int x=0; x<cellSize; ++x)
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");
mContext->mGlobalMapState.mImageData.resize(encoded->size());
encoded->read(&mContext->mGlobalMapState.mImageData[0], encoded->size());
std::string outData = ostream.str();
mContext->mGlobalMapState.mImageData = std::vector<char>(outData.begin(), outData.end());
esm.startRecord(ESM::REC_GMAP);
mContext->mGlobalMapState.save(esm);
@ -194,7 +218,7 @@ namespace ESSImport
std::ostringstream filename;
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
#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/esmwriter.hpp>
@ -311,7 +314,7 @@ public:
virtual void write(ESM::ESMWriter &esm);
private:
Ogre::Image mGlobalMapImage;
osg::ref_ptr<osg::Image> mGlobalMapImage;
};
class ConvertCell : public Converter

@ -18,7 +18,7 @@ namespace ESSImport
for (int i=0; i<8; ++i)
out.mObject.mNpcStats.mSkillIncrease[i] = pcdt.mPNAM.mSkillIncreases[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;
if (pcdt.mPNAM.mDrawState & PCDT::DrawState_Weapon)

@ -1,7 +1,11 @@
#include "importer.hpp"
#include <iomanip>
#include <boost/shared_ptr.hpp>
#include <OgreRoot.h>
#include <osgDB/ReadFile>
#include <osg/ImageUtils>
#include <components/esm/esmreader.hpp>
#include <components/esm/esmwriter.hpp>
@ -32,13 +36,48 @@ namespace
void writeScreenshot(const ESM::Header& fileHeader, ESM::SavedGame& out)
{
Ogre::Image screenshot;
std::vector<unsigned char> screenshotData = fileHeader.mSCRS; // MemoryDataStream doesn't work with const data :(
Ogre::DataStreamPtr screenshotStream (new Ogre::MemoryDataStream(&screenshotData[0], screenshotData.size()));
screenshot.loadRawData(screenshotStream, 128, 128, 1, Ogre::PF_BYTE_BGRA);
Ogre::DataStreamPtr encoded = screenshot.encode("jpg");
out.mScreenshot.resize(encoded->size());
encoded->read(&out.mScreenshot[0], encoded->size());
if (fileHeader.mSCRS.size() != 128*128*4)
{
std::cerr << "unexpected screenshot size " << std::endl;
return;
}
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()
{
// construct Ogre::Root to gain access to image codecs
Ogre::LogManager logman;
Ogre::Root root;
ToUTF8::Utf8Encoder encoder(ToUTF8::calculateEncoding(mEncoding));
ESM::ESMReader esm;
esm.open(mEssFile);
@ -292,7 +327,7 @@ namespace ESSImport
ESM::ESMWriter writer;
writer.setFormat (ESM::Header::CurrentFormat);
writer.setFormat (ESM::SavedGame::sCurrentFormat);
std::ofstream stream(mOutFile.c_str(), std::ios::binary);
// all unused

@ -57,7 +57,6 @@ set(LAUNCHER_UI
source_group(launcher FILES ${LAUNCHER} ${LAUNCHER_HEADER})
find_package(Qt4 REQUIRED)
set(QT_USE_QTGUI 1)
# Set some platform specific settings
@ -66,12 +65,17 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE)
endif(WIN32)
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})
if (DESIRED_QT_VERSION MATCHES 4)
include(${QT_USE_FILE})
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})
if(NOT WIN32)
include_directories(${LIBUNSHIELD_INCLUDE_DIR})
@ -88,17 +92,25 @@ add_executable(openmw-launcher
)
target_link_libraries(openmw-launcher
${Boost_LIBRARIES}
${OGRE_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SDL2_LIBRARY_ONLY}
${QT_LIBRARIES}
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)
add_definitions (--coverage)
target_link_libraries(openmw-launcher gcov)
endif()

@ -12,9 +12,6 @@
#include <SDL_video.h>
#include <OgreRoot.h>
#include <OgreRenderSystem.h>
#include <boost/math/common_factor.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)
: QWidget(parent)
, mOgre(NULL)
, mSelectedRenderSystem(NULL)
, mOpenGLRenderSystem(NULL)
, mDirect3DRenderSystem(NULL)
, mCfgMgr(cfg)
, mGraphicsSettings(graphicsSetting)
{
@ -52,79 +45,12 @@ Launcher::GraphicsPage::GraphicsPage(Files::ConfigurationManager &cfg, GraphicsS
customWidthSpinBox->setMaximum(res.width());
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(standardRadioButton, SIGNAL(toggled(bool)), this, SLOT(slotStandardToggled(bool)));
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()
{
int displays = SDL_GetNumVideoDisplays();
@ -153,8 +79,6 @@ bool Launcher::GraphicsPage::loadSettings()
{
if (!setupSDL())
return false;
if (!mOgre && !setupOgre())
return false;
if (mGraphicsSettings.value(QString("Video/vsync")) == QLatin1String("true"))
vSyncCheckBox->setCheckState(Qt::Checked);
@ -203,7 +127,6 @@ void Launcher::GraphicsPage::saveSettings()
: mGraphicsSettings.setValue(QString("Video/window border"), QString("false"));
mGraphicsSettings.setValue(QString("Video/antialiasing"), antiAliasingComboBox->currentText());
mGraphicsSettings.setValue(QString("Video/render system"), rendererComboBox->currentText());
if (standardRadioButton->isChecked()) {
@ -221,39 +144,6 @@ void Launcher::GraphicsPage::saveSettings()
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 result;
@ -316,15 +206,6 @@ QRect Launcher::GraphicsPage::getMaximumResolution()
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)
{
if (screen >= 0) {

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

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

@ -199,7 +199,7 @@ bool Launcher::MainDialog::setup()
// Now create the pages as they need the settings
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())
return false;
@ -490,7 +490,7 @@ bool Launcher::MainDialog::writeSettings()
// Game settings
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
QMessageBox msgBox;
msgBox.setWindowTitle(tr("Error writing OpenMW configuration file"));
@ -503,10 +503,8 @@ bool Launcher::MainDialog::writeSettings()
return false;
}
QTextStream stream(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));
mGameSettings.writeFile(stream);
mGameSettings.writeFileWithComments(file);
file.close();
// Graphics settings
@ -525,6 +523,7 @@ bool Launcher::MainDialog::writeSettings()
return false;
}
QTextStream stream(&file);
stream.setDevice(&file);
stream.setCodec(QTextCodec::codecForName("UTF-8"));

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

@ -18,7 +18,7 @@ opencs_hdrs_noqt (model/doc
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
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
pathgrid landtexture land nestedtablewrapper nestedcollection nestedcoladapterimp nestedinfocollection
idcompletionmanager metadata
)
opencs_hdrs_noqt (model/world
@ -40,7 +41,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
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
cellcreator referenceablecreator referencecreator scenesubview
infocreator scriptedit dialoguesubview previewsubview regionmap dragrecordtable nestedtable
dialoguespinbox
dialoguespinbox recordbuttonbar tableeditidaction
)
opencs_units_noqt (view/world
subviews enumdelegate vartypedelegate recordstatusdelegate idtypedelegate datadisplaydelegate
scripthighlighter idvalidator dialoguecreator physicssystem
scripthighlighter idvalidator dialoguecreator idcompletiondelegate
colordelegate dragdroputils
)
opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun modebutton
scenetooltoggle2
scenetooltoggle2 completerpopup coloreditor colorpickerpopup droplineedit
)
opencs_units (view/render
@ -82,8 +84,8 @@ opencs_units (view/render
)
opencs_units_noqt (view/render
navigation navigation1st navigationfree navigationorbit lighting lightingday lightingnight
lightingbright object cell terrainstorage textoverlay overlaymask overlaysystem mousestate
lighting lightingday lightingnight
lightingbright object cell terrainstorage
)
opencs_hdrs_noqt (view/render
@ -152,19 +154,16 @@ if(WIN32)
set(QT_USE_QTMAIN TRUE)
endif(WIN32)
set(BOOST_COMPONENTS system filesystem program_options thread wave)
if(WIN32)
set(BOOST_COMPONENTS ${BOOST_COMPONENTS} locale)
endif(WIN32)
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(Qt4 COMPONENTS QtCore QtGui QtNetwork REQUIRED)
include(${QT_USE_FILE})
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})
if (DESIRED_QT_VERSION MATCHES 4)
include(${QT_USE_FILE})
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})
else()
qt5_wrap_ui(OPENCS_UI_HDR ${OPENCS_UI})
qt5_wrap_cpp(OPENCS_MOC_SRC ${OPENCS_HDR_QT})
qt5_add_resources(OPENCS_RES_SRC ${OPENCS_RES})
endif()
# for compiled .ui files
include_directories(${CMAKE_CURRENT_BINARY_DIR})
@ -200,17 +199,35 @@ if(APPLE)
endif(APPLE)
target_link_libraries(openmw-cs
${OENGINE_LIBRARY}
${OGRE_LIBRARIES}
${OGRE_Overlay_LIBRARIES}
${OGRE_STATIC_PLUGINS}
${SHINY_LIBRARIES}
${Boost_LIBRARIES}
${BULLET_LIBRARIES}
${QT_LIBRARIES}
${OPENSCENEGRAPH_LIBRARIES}
${Boost_SYSTEM_LIBRARY}
${Boost_FILESYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY}
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)
INSTALL(TARGETS openmw-cs BUNDLE DESTINATION OpenMW COMPONENT BUNDLE)
endif()

@ -1,28 +1,25 @@
#include "editor.hpp"
#include <openengine/bullet/BulletShapeLoader.h>
#include <QApplication>
#include <QLocalServer>
#include <QLocalSocket>
#include <QMessageBox>
#include <OgreRoot.h>
#include <OgreRenderWindow.h>
#include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgrePlatform.hpp>
#include <components/vfs/manager.hpp>
#include <components/vfs/registerarchives.hpp>
#include <components/ogreinit/ogreinit.hpp>
#include <components/nifogre/ogrenifloader.hpp>
#include <components/bsa/resources.hpp>
#include <components/nifosg/nifloader.hpp>
#include "model/doc/document.hpp"
#include "model/world/data.hpp"
CS::Editor::Editor (OgreInit::OgreInit& ogreInit)
: mUserSettings (mCfgMgr), mOverlaySystem (0), mDocumentManager (mCfgMgr),
#ifdef _WIN32
#include <Windows.h>
#endif
CS::Editor::Editor ()
: mUserSettings (mCfgMgr), mDocumentManager (mCfgMgr),
mViewManager (mDocumentManager), mPid(""),
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");
mSettings.setModel (CSMSettings::UserSettings::instance());
ogreInit.init ((mCfgMgr.getUserConfigPath() / "opencsOgre.log").string());
NifOgre::Loader::setShowMarkers(true);
NifOsg::Loader::setShowMarkers(true);
mOverlaySystem.reset (new CSVRender::OverlaySystem);
mVFS.reset(new VFS::Manager(mFsStrict));
Bsa::registerResources (Files::Collections (config.first, !mFsStrict), config.second, true,
mFsStrict);
VFS::registerArchives(mVFS.get(), Files::Collections(config.first, !mFsStrict), config.second, true);
mDocumentManager.listResources();
mDocumentManager.setVFS(mVFS.get());
mNewGame.setLocalData (mLocal);
mFileDialog.setLocalData (mLocal);
@ -81,9 +75,6 @@ CS::Editor::~Editor ()
if(mServer && boost::filesystem::exists(mPid))
static_cast<void> ( // silence coverity warning
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)
@ -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::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);
mCfgMgr.readConfiguration(variables, desc);
mCfgMgr.readConfiguration(variables, desc, quiet);
mDocumentManager.setEncoding (
ToUTF8::calculateEncoding (variables["encoding"].as<std::string>()));
@ -195,6 +186,11 @@ void CS::Editor::cancelCreateGame()
void CS::Editor::createAddon()
{
mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
mFileDialog.showDialog (CSVDoc::ContentAction_New);
}
@ -215,6 +211,11 @@ void CS::Editor::cancelFileDialog()
void CS::Editor::loadDocument()
{
mStartup.hide();
mFileDialog.clearFiles();
std::pair<Files::PathContainer, std::vector<std::string> > config = readConfig(/*quiet*/true);
setupDataFiles (config.first);
mFileDialog.showDialog (CSVDoc::ContentAction_Edit);
}
@ -307,12 +308,12 @@ bool CS::Editor::makeIPCServer()
mServer->close();
fullPath.remove(QRegExp("dummy$"));
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
std::cout << "Detected unclean shutdown." << std::endl;
// delete the stale file
if(remove(fullPath.toStdString().c_str()))
if(remove(fullPath.toUtf8().constData()))
std::cerr << "ERROR removing stale connection file" << std::endl;
}
}
@ -354,114 +355,6 @@ int CS::Editor::run()
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)
{
mViewManager.addView (document);

@ -11,16 +11,12 @@
#include <QLocalServer>
#include <QLocalSocket>
#include <extern/shiny/Main/Factory.hpp>
#ifndef Q_MOC_RUN
#include <components/files/configurationmanager.hpp>
#endif
#include <components/files/multidircollection.hpp>
#include <components/nifcache/nifcache.hpp>
#include "model/settings/usersettings.hpp"
#include "model/doc/documentmanager.hpp"
@ -30,11 +26,10 @@
#include "view/doc/newgame.hpp"
#include "view/settings/dialog.hpp"
#include "view/render/overlaysystem.hpp"
namespace OgreInit
namespace VFS
{
class OgreInit;
class Manager;
}
namespace CS
@ -43,10 +38,11 @@ namespace CS
{
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;
CSMSettings::UserSettings mUserSettings;
std::auto_ptr<CSVRender::OverlaySystem> mOverlaySystem;
CSMDoc::DocumentManager mDocumentManager;
CSVDoc::ViewManager mViewManager;
CSVDoc::StartupDialogue mStartup;
@ -62,7 +58,7 @@ namespace CS
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
// not implemented
@ -71,7 +67,7 @@ namespace CS
public:
Editor (OgreInit::OgreInit& ogreInit);
Editor ();
~Editor ();
bool makeIPCServer();
@ -80,9 +76,6 @@ namespace CS
int run();
///< \return error status
std::auto_ptr<sh::Factory> setupGraphics();
///< The returned factory must persist at least as long as *this.
private slots:
void createGame();

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

@ -2,6 +2,7 @@
#include <cassert>
#include <fstream>
#include <iostream>
#include <boost/filesystem.hpp>
@ -9,8 +10,6 @@
#include <components/files/configurationmanager.hpp>
#endif
#include "../../view/world/physicssystem.hpp"
void CSMDoc::Document::addGmsts()
{
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 boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
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),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSavingOperation (*this, mProjectPath, encoding),
mSaving (&mSavingOperation),
mResDir(resDir),
mRunner (mProjectPath), mPhysics(boost::shared_ptr<CSVWorld::PhysicsSystem>())
mRunner (mProjectPath), mIdCompletionManager(mData)
{
if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence");
@ -2271,7 +2270,7 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
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
{
@ -2281,9 +2280,6 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
if (mNew)
{
mData.setDescription ("");
mData.setAuthor ("");
if (mContentFiles.size()==1)
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 (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
&mSaving, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SLOT (reportMessage (const CSMDoc::Message&, int)));
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()
{
return mUndoStack;
@ -2368,9 +2369,9 @@ void CSMDoc::Document::save()
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);
return id;
}
@ -2400,11 +2401,10 @@ void CSMDoc::Document::modificationStateChanged (bool clean)
emit stateChanged (getState(), this);
}
void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type)
void CSMDoc::Document::reportMessage (const CSMDoc::Message& message, int type)
{
/// \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)
@ -2481,10 +2481,7 @@ void CSMDoc::Document::progress (int current, int max, int type)
emit progress (current, max, type, 1, this);
}
boost::shared_ptr<CSVWorld::PhysicsSystem> CSMDoc::Document::getPhysics ()
CSMWorld::IdCompletionManager &CSMDoc::Document::getIdCompletionManager()
{
if(!mPhysics)
mPhysics = boost::shared_ptr<CSVWorld::PhysicsSystem> (new CSVWorld::PhysicsSystem());
return mPhysics;
return mIdCompletionManager;
}

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

@ -13,7 +13,7 @@
#include "document.hpp"
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";
@ -57,7 +57,7 @@ bool CSMDoc::DocumentManager::isEmpty()
void CSMDoc::DocumentManager::addDocument (const std::vector<boost::filesystem::path>& files, const boost::filesystem::path& savePath,
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);
@ -95,11 +95,6 @@ void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector<std::stri
mBlacklistedScripts = scriptIds;
}
void CSMDoc::DocumentManager::listResources()
{
mResourcesManager.listResources();
}
void CSMDoc::DocumentManager::documentLoaded (Document *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
removeDocument (document);
}
void CSMDoc::DocumentManager::setVFS(const VFS::Manager *vfs)
{
mResourcesManager.setVFS(vfs);
mVFS = vfs;
}

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

@ -52,7 +52,7 @@ void CSMDoc::Loader::load()
{
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
if (document->getData().continueLoading (messages))
{
@ -68,7 +68,7 @@ void CSMDoc::Loader::load()
for (CSMDoc::Messages::Iterator iter (messages.begin());
iter!=messages.end(); ++iter)
{
document->getReport (log)->add (iter->mId, iter->mMessage);
document->getReport (log)->add (*iter);
emit loadMessage (document, iter->mMessage);
}
}

@ -1,15 +1,25 @@
#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,
const std::string& hint)
const std::string& hint, Message::Severity severity)
{
Message data;
data.mId = id;
data.mMessage = message;
data.mHint = hint;
mMessages.push_back (data);
if (severity==Message::Severity_Default)
severity = mDefault;
mMessages.push_back (Message (id, message, hint, severity));
}
void CSMDoc::Messages::push_back (const std::pair<CSMWorld::UniversalId, std::string>& data)

@ -4,20 +4,41 @@
#include <string>
#include <vector>
#include <QMetaType>
#include "../world/universalid.hpp"
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
{
public:
struct Message
{
CSMWorld::UniversalId mId;
std::string mMessage;
std::string mHint;
};
// \deprecated Use CSMDoc::Message directly instead.
typedef CSMDoc::Message Message;
typedef std::vector<Message> Collection;
@ -26,11 +47,15 @@ namespace CSMDoc
private:
Collection mMessages;
Message::Severity mDefault;
public:
Messages (Message::Severity default_);
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.
void push_back (const std::pair<CSMWorld::UniversalId, std::string>& data);
@ -41,4 +66,6 @@ namespace CSMDoc
};
}
Q_DECLARE_METATYPE (CSMDoc::Message)
#endif

@ -7,6 +7,7 @@
#include <QTimer>
#include "../world/universalid.hpp"
#include "../settings/usersettings.hpp"
#include "state.hpp"
#include "stage.hpp"
@ -23,13 +24,17 @@ void CSMDoc::Operation::prepareStages()
{
iter->second = iter->first->setup();
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)
: mType (type), mStages(std::vector<std::pair<Stage *, int> >()), mCurrentStage(mStages.begin()),
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);
}
@ -49,8 +54,8 @@ void CSMDoc::Operation::run()
connect (mTimer, SIGNAL (timeout()), this, SLOT (executeStage()));
mConnected = true;
}
prepareStages();
mPrepared = false;
mTimer->start (0);
}
@ -60,6 +65,19 @@ void CSMDoc::Operation::appendStage (Stage *stage)
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
{
return mError;
@ -84,9 +102,23 @@ void CSMDoc::Operation::abort()
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()
{
Messages messages;
if (!mPrepared)
{
prepareStages();
mPrepared = true;
}
Messages messages (mDefaultSeverity);
while (mCurrentStage!=mStages.end())
{
@ -103,7 +135,7 @@ void CSMDoc::Operation::executeStage()
}
catch (const std::exception& e)
{
emit reportMessage (CSMWorld::UniversalId(), e.what(), "", mType);
emit reportMessage (Message (CSMWorld::UniversalId(), e.what(), "", Message::Severity_SeriousError), mType);
abort();
}
@ -115,7 +147,7 @@ void CSMDoc::Operation::executeStage()
emit progress (mCurrentStepTotal, mTotalSteps ? mTotalSteps : 1, mType);
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())
operationDone();

@ -2,9 +2,13 @@
#define CSM_DOC_OPERATION_H
#include <vector>
#include <map>
#include <QObject>
#include <QTimer>
#include <QStringList>
#include "messages.hpp"
namespace CSMWorld
{
@ -30,6 +34,9 @@ namespace CSMDoc
bool mError;
bool mConnected;
QTimer *mTimer;
std::map<QString, QStringList> mSettings;
bool mPrepared;
Message::Severity mDefaultSeverity;
void prepareStages();
@ -46,14 +53,21 @@ namespace CSMDoc
///
/// \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;
signals:
void progress (int current, int max, int type);
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint, int type);
void reportMessage (const CSMDoc::Message& message, int type);
void done (int type, bool failed);
@ -63,6 +77,8 @@ namespace CSMDoc
void run();
void updateUserSetting (const QString& name, const QStringList& value);
private slots:
void executeStage();

@ -1,6 +1,8 @@
#include "operationholder.hpp"
#include "../settings/usersettings.hpp"
#include "operation.hpp"
CSMDoc::OperationHolder::OperationHolder (Operation *operation) : mRunning (false)
@ -19,8 +21,8 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
this, SIGNAL (progress (int, int, int)));
connect (
mOperation, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)),
this, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, const std::string&, int)));
mOperation, SIGNAL (reportMessage (const CSMDoc::Message&, int)),
this, SIGNAL (reportMessage (const CSMDoc::Message&, int)));
connect (
mOperation, SIGNAL (done (int, bool)),
@ -29,6 +31,9 @@ void CSMDoc::OperationHolder::setOperation (Operation *operation)
connect (this, SIGNAL (abortSignal()), mOperation, SLOT (abort()));
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

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

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

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

@ -8,6 +8,8 @@
#include "messages.hpp"
class QString;
namespace CSMDoc
{
class Stage
@ -21,6 +23,9 @@ namespace CSMDoc
virtual void perform (int stage, Messages& messages) = 0;
///< 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 <QDebug>
#include <extern/shiny/Main/Factory.hpp>
/**
* 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()
{
QString section;
/*
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");
farClipDist->setDefaultValue (300000);
farClipDist->setRange (0, 1000000);
@ -62,23 +56,11 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
<< defaultValue << "MSAA 2" << "MSAA 4" << "MSAA 8" << "MSAA 16");
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");
{
Setting *timer = createSetting (Type_SpinBox, "timer", "Input responsiveness");
timer->setDefaultValue (20);
timer->setRange (1, 100);
timer->setToolTip ("The time between two checks for user input in milliseconds.<p>"
"Lower value result in higher responsiveness.");
Setting *fastFactor = createSetting (Type_SpinBox, "fast-factor",
"Fast movement factor");
fastFactor->setDefaultValue (4);
@ -86,6 +68,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
fastFactor->setToolTip (
"Factor by which movement is speed up while the shift key is held down.");
}
*/
declareSection ("window", "Window");
{
@ -234,6 +217,47 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
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");
{
Setting *before = createSetting (Type_SpinBox, "char-before",
@ -252,7 +276,7 @@ void CSMSettings::UserSettings::buildSettingModelDefaults()
autoDelete->setDefaultValue ("true");
}
declareSection ("script-editor", "Script Editor");
declareSection ("script-editor", "Scripts");
{
Setting *lineNum = createSetting (Type_CheckBox, "show-linenum", "Show Line Numbers");
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."
"\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");
formatInt->setDefaultValues (QStringList() << "Dark magenta");
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);
}
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:
@ -562,15 +609,6 @@ void CSMSettings::UserSettings::updateUserSetting(const QString &settingKey,
{
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);
}

@ -30,9 +30,9 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
// check the number of pathgrid points
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()))
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<int> duplList;
@ -51,7 +51,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
std::ostringstream ss;
ss << "has a duplicate edge between points" << pathgrid.mEdges[i].mV0
<< " 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;
}
}
@ -64,7 +64,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{
std::ostringstream ss;
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;
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)
{
std::ostringstream ss;
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
@ -101,7 +101,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
{
std::ostringstream ss;
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
<< ", y=" << pathgrid.mPoints[i].mY
<< ", 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);
break;
@ -143,7 +143,7 @@ void CSMTools::PathgridCheckStage::perform (int stage, CSMDoc::Messages& message
<< ") x=" << pathgrid.mPoints[i].mX
<< ", y=" << pathgrid.mPoints[i].mY
<< ", 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.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?
return;

@ -6,24 +6,18 @@
#include "../world/columns.hpp"
CSMTools::ReportModel::Line::Line (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
: mId (id), mMessage (message), mHint (hint)
{}
CSMTools::ReportModel::ReportModel (bool fieldColumn)
CSMTools::ReportModel::ReportModel (bool fieldColumn, bool severityColumn)
: mColumnField (-1), mColumnSeverity (-1)
{
int index = 3;
if (severityColumn)
mColumnSeverity = index++;
if (fieldColumn)
{
mColumnField = 3;
mColumnDescription = 4;
}
else
{
mColumnDescription = 3;
mColumnField = index++;
mColumnField = -1;
}
mColumnDescription = index;
}
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());
}
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();
}
@ -112,6 +118,9 @@ QVariant CSMTools::ReportModel::headerData (int section, Qt::Orientation orienta
if (section==mColumnField)
return "Field";
if (section==mColumnSeverity)
return "Severity";
return "-";
}
@ -132,19 +141,18 @@ bool CSMTools::ReportModel::removeRows (int row, int count, const QModelIndex& p
return true;
}
void CSMTools::ReportModel::add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint)
void CSMTools::ReportModel::add (const CSMDoc::Message& message)
{
beginInsertRows (QModelIndex(), mRows.size(), mRows.size());
mRows.push_back (Line (id, message, hint));
mRows.push_back (message);
endInsertRows();
}
void CSMTools::ReportModel::flagAsReplaced (int index)
{
Line& line = mRows.at (index);
CSMDoc::Message& line = mRows.at (index);
std::string hint = line.mHint;
if (hint.empty() || hint[0]!='R')
@ -176,3 +184,16 @@ void CSMTools::ReportModel::clear()
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 "../doc/messages.hpp"
#include "../world/universalid.hpp"
namespace CSMTools
@ -14,17 +16,7 @@ namespace CSMTools
{
Q_OBJECT
struct Line
{
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;
std::vector<CSMDoc::Messages::Message> mRows;
// Fixed columns
enum Columns
@ -35,10 +27,11 @@ namespace CSMTools
// Configurable columns
int mColumnDescription;
int mColumnField;
int mColumnSeverity;
public:
ReportModel (bool fieldColumn = false);
ReportModel (bool fieldColumn = false, bool severityColumn = true);
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());
void add (const CSMWorld::UniversalId& id, const std::string& message,
const std::string& hint = "");
void add (const CSMDoc::Message& message);
void flagAsReplaced (int index);
@ -60,6 +52,9 @@ namespace CSMTools
std::string getHint (int row) const;
void clear();
// Return number of messages with Error or SeriousError severity.
int countErrors() const;
};
}

@ -11,6 +11,17 @@
#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,
Type type)
{
@ -18,11 +29,6 @@ void CSMTools::ScriptCheckStage::report (const std::string& message, const Compi
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
if (type==ErrorMessage)
stream << "error ";
else
stream << "warning ";
stream
<< "script " << mFile
<< ", 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;
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)
{
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Script, mId);
mMessages->push_back (std::make_pair (id,
(type==ErrorMessage ? "error: " : "warning: ") + message));
std::ostringstream stream;
stream << "script " << mFile << ": " << message;
mMessages->add (id, stream.str(), "", getSeverity (type));
}
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
setWarningsMode (0);
@ -58,6 +66,7 @@ int CSMTools::ScriptCheckStage::setup()
mContext.clear();
mMessages = 0;
mId.clear();
Compiler::ErrorHandler::reset();
return mDocument.getData().getScripts().getSize();
}
@ -72,6 +81,13 @@ void CSMTools::ScriptCheckStage::perform (int stage, CSMDoc::Messages& messages)
mMessages = &messages;
switch (mWarningMode)
{
case Mode_Ignore: setWarningsMode (0); break;
case Mode_Normal: setWarningsMode (1); break;
case Mode_Strict: setWarningsMode (2); break;
}
try
{
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);
messages.push_back (std::make_pair (id,
std::string ("Critical compile error: ") + error.what()));
std::ostringstream stream;
stream << "script " << mFile << ": " << error.what();
messages.add (id, stream.str(), "", CSMDoc::Message::Severity_SeriousError);
}
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
class ScriptCheckStage : public CSMDoc::Stage, private Compiler::ErrorHandler
{
enum WarningMode
{
Mode_Ignore,
Mode_Normal,
Mode_Strict
};
const CSMDoc::Document& mDocument;
Compiler::Extensions mExtensions;
CSMWorld::ScriptContext mContext;
std::string mId;
std::string mFile;
CSMDoc::Messages *mMessages;
WarningMode mWarningMode;
CSMDoc::Message::Severity getSeverity (Type type);
virtual void report (const std::string& message, const Compiler::TokenLoc& loc, Type type);
///< Report error to the user.
@ -40,6 +50,8 @@ namespace CSMTools
virtual void perform (int stage, CSMDoc::Messages& 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,
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(),
model->findColumnIndex (CSMWorld::Columns::ColumnId_Id)).row();

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

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

@ -65,6 +65,8 @@ bool CSMWorld::ColumnBase::isId (Display display)
Display_JournalInfo,
Display_Scene,
Display_GlobalVariable,
Display_BodyPart,
Display_Enchantment,
Display_Script,
Display_Mesh,
@ -98,7 +100,8 @@ bool CSMWorld::ColumnBase::isId (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)

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

@ -694,7 +694,7 @@ namespace CSMWorld
QColor colour = data.value<QColor>();
record2.mMapColor = colour.rgb() & 0xffffff;
record2.mMapColor = (colour.blue() << 16) | (colour.green() << 8) | colour.red();
record.setModified (record2);
}
@ -709,7 +709,7 @@ namespace CSMWorld
struct SleepListColumn : public Column<ESXRecordT>
{
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
@ -735,7 +735,7 @@ namespace CSMWorld
template<typename 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
{
@ -1269,7 +1269,7 @@ namespace CSMWorld
template<typename 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
{
@ -1294,7 +1294,7 @@ namespace CSMWorld
template<typename 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
{
@ -1497,7 +1497,10 @@ namespace CSMWorld
template<typename 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
{
@ -1527,7 +1530,7 @@ namespace CSMWorld
template<typename 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
{
@ -1830,7 +1833,7 @@ namespace CSMWorld
template<typename 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
{
@ -2158,7 +2161,9 @@ namespace CSMWorld
struct EffectTextureColumn : public Column<ESXRecordT>
{
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 ||
this->mColumnId==Columns::ColumnId_Particle);
@ -2303,6 +2308,78 @@ namespace CSMWorld
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

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

@ -302,6 +302,10 @@ namespace CSMWorld
ColumnId_WaterLevel = 273,
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
// to extend the number of use values.
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)
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)
@ -71,6 +90,11 @@ void CSMWorld::CreateCommand::addValue (int column, const QVariant& 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)
{
mType = type;

@ -48,6 +48,9 @@ namespace CSMWorld
class CreateCommand : public QUndoCommand
{
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:
@ -68,6 +71,8 @@ namespace CSMWorld
void addValue (int column, const QVariant& value);
void addNestedValue(int parentColumn, int nestedColumn, const QVariant &value);
virtual void redo();
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)
: 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;
@ -115,7 +115,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mFactions.getColumns()-1;
mFactions.addAdapter (std::make_pair(&mFactions.getColumn(index), new FactionReactionsAdapter ()));
mFactions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_String));
new NestedChildColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
mFactions.getNestableColumn(index)->addColumn(
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;
mRaces.addAdapter (std::make_pair(&mRaces.getColumn(index), new SpellListAdapter<ESM::Race> ()));
mRaces.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_String));
new NestedChildColumn (Columns::ColumnId_SpellId, ColumnBase::Display_Spell));
// Race attributes
mRaces.addColumn (new NestedParentColumn<ESM::Race> (Columns::ColumnId_RaceAttributes));
index = mRaces.getColumns()-1;
@ -180,7 +180,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
index = mRegions.getColumns()-1;
mRegions.addAdapter (std::make_pair(&mRegions.getColumn(index), new RegionSoundListAdapter ()));
mRegions.getNestableColumn(index)->addColumn(
new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_String));
new NestedChildColumn (Columns::ColumnId_SoundName, ColumnBase::Display_Sound));
mRegions.getNestableColumn(index)->addColumn(
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),
new SpellListAdapter<ESM::BirthSign> ()));
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 RecordStateColumn<ESM::Spell>);
@ -475,6 +475,15 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
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 (&mGmsts), UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skill);
@ -515,6 +524,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video);
addModel (new IdTable (&mMetaData), UniversalId::Type_MetaData);
mRefLoadCache.clear(); // clear here rather than startLoading() and continueLoading() for multiple content files
}
@ -527,6 +537,16 @@ CSMWorld::Data::~Data()
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
{
return mGlobals;
@ -803,6 +823,11 @@ const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id)
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)
{
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;
mProject = project;
mAuthor = mReader->getAuthor();
mDescription = mReader->getDesc();
if (!mProject && !mBase)
{
MetaData metaData;
metaData.mId = "sys::meta";
metaData.load (*mReader);
mMetaData.setRecord (0, Record<MetaData> (RecordBase::State_ModifiedOnly, 0, &metaData));
}
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
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;
}
std::string cellId = Misc::StringUtils::lowerCase (mCells.getId (index));
@ -984,7 +1015,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
else
{
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
@ -1001,7 +1033,7 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
if (!mDialogue)
{
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();
break;
@ -1044,7 +1076,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Messages& messages)
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();
}
@ -1101,26 +1134,6 @@ int CSMWorld::Data::count (RecordBase::State state) const
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> ids;
@ -1159,3 +1172,8 @@ void CSMWorld::Data::rowsChanged (const QModelIndex& parent, int start, int end)
{
emit idListChanged();
}
const VFS::Manager* CSMWorld::Data::getVFS() const
{
return mResourcesManager.getVFS();
}

@ -29,6 +29,8 @@
#include <components/esm/debugprofile.hpp>
#include <components/esm/filter.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/to_utf8/to_utf8.hpp>
#include "../doc/stage.hpp"
@ -44,12 +46,18 @@
#include "infocollection.hpp"
#include "nestedinfocollection.hpp"
#include "pathgrid.hpp"
#include "metadata.hpp"
#ifndef Q_MOC_RUN
#include "subcellcollection.hpp"
#endif
class QAbstractItemModel;
namespace VFS
{
class Manager;
}
namespace ESM
{
class ESMReader;
@ -94,11 +102,10 @@ namespace CSMWorld
RefIdCollection mReferenceables;
RefCollection mRefs;
IdCollection<ESM::Filter> mFilters;
Collection<MetaData> mMetaData;
const ResourcesManager& mResourcesManager;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
std::string mAuthor;
std::string mDescription;
ESM::ESMReader *mReader;
const ESM::Dialogue *mDialogue; // last loaded dialogue
bool mBase;
@ -106,6 +113,8 @@ namespace CSMWorld
std::map<std::string, std::map<ESM::RefNum, std::string> > mRefLoadCache;
int mReaderIndex;
Resource::ResourceSystem mResourceSystem;
std::vector<boost::shared_ptr<ESM::ESMReader> > mReaders;
// not implemented
@ -127,6 +136,12 @@ namespace CSMWorld
virtual ~Data();
const VFS::Manager* getVFS() const;
Resource::ResourceSystem* getResourceSystem();
const Resource::ResourceSystem* getResourceSystem() const;
const IdCollection<ESM::Global>& getGlobals() const;
IdCollection<ESM::Global>& getGlobals();
@ -238,6 +253,8 @@ namespace CSMWorld
/// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const;
const MetaData& getMetaData() const;
QAbstractItemModel *getTableModel (const UniversalId& id);
///< 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;
///< 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:
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)
return QVariant();
if (role==ColumnBase::Role_Display)
return QVariant(mIdCollection->getColumn(index.column()).mDisplayType);
if (role==ColumnBase::Role_ColumnId)
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
{
if (!index.isValid())
return 0;
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (mIdCollection->getColumn (index.column()).isUserEditable())

@ -24,6 +24,14 @@ void CSMWorld::IdTableProxyModel::updateColumnMap()
bool CSMWorld::IdTableProxyModel::filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent)
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)
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)
{
beginResetModel();
mFilter = filter;
updateColumnMap();
reset();
endResetModel();
}
bool CSMWorld::IdTableProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const

@ -24,8 +24,6 @@ namespace CSMWorld
void updateColumnMap();
bool filterAcceptsRow (int sourceRow, const QModelIndex& sourceParent) const;
public:
IdTableProxyModel (QObject *parent = 0);
@ -39,6 +37,8 @@ namespace CSMWorld
protected:
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())
return QVariant();
if ((role!=Qt::DisplayRole && role!=Qt::EditRole) || index.row() < 0 || index.column() < 0)
return QVariant();
if (index.internalId() != 0)
{
std::pair<int, int> parentAddress(unfoldIndexAddress(index.internalId()));
const NestableColumn *parentColumn = mNestedCollection->getNestableColumn(parentAddress.second);
if (role == Qt::EditRole &&
!mNestedCollection->getNestableColumn(parentAddress.second)->nestedColumn(index.column()).isEditable())
{
if (role == ColumnBase::Role_Display)
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 mNestedCollection->getNestedData(parentAddress.first,
parentAddress.second, index.row(), index.column());
}
else
{
if (role==Qt::EditRole && !idCollection()->getColumn (index.column()).isEditable())
return QVariant();
return idCollection()->getData (index.row(), index.column());
return IdTable::data(index, role);
}
}
@ -79,6 +80,9 @@ QVariant CSMWorld::IdTree::nestedHeaderData(int section, int subSection, Qt::Ori
if (role==ColumnBase::Role_Display)
return parentColumn->nestedColumn(subSection).mDisplayType;
if (role==ColumnBase::Role_ColumnId)
return parentColumn->nestedColumn(subSection).mColumnId;
return QVariant();
}
@ -257,3 +261,13 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::IdTree::nestedTable(const QModelInde
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 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:
void resetStart(const QString& id);

@ -97,7 +97,8 @@ bool CSMWorld::InfoCollection::reorderRows (int baseIndex, const std::vector<int
return false;
// 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;
// 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
{
std::vector<typename ESM::Race::RADTstruct> wrap;
std::vector<ESM::Race::RADTstruct> wrap;
wrap.push_back(record.get().mData);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap);
@ -983,7 +983,7 @@ namespace CSMWorld
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);
// deleted by dtor of NestedTableStoring
return new NestedTableWrapper<std::vector<ESM::Race::RADTstruct> >(wrap);

@ -15,3 +15,28 @@ int CSMWorld::NestedCollection::getNestedColumnsCount(int row, int column) const
{
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
#define CSM_WOLRD_NESTEDCOLLECTION_H
#include "columns.hpp"
class QVariant;
namespace CSMWorld
@ -33,6 +35,12 @@ namespace CSMWorld
virtual int getNestedColumnsCount(int row, int column) const;
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>
int NestedIdCollection<ESXRecordT, IdAccessorT>::getNestedColumnsCount(int row, int column) const
{
return getAdapter(Collection<ESXRecordT, IdAccessorT>::getColumn(column)).getColumnsCount(
Collection<ESXRecordT, IdAccessorT>::getRecord(row));
const ColumnBase &nestedColumn = Collection<ESXRecordT, IdAccessorT>::getColumn(column);
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>

@ -192,4 +192,8 @@ void CSMWorld::NestedTableProxyModel::forwardDataChanged (const QModelIndex& top
emit dataChanged(index(0,0),
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Potion)));
ESM::Potion potion = record.get();
if (column==mAutoCalc)
record.get().mData.mAutoCalc = value.toInt();
potion.mData.mAutoCalc = value.toInt();
else
{
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Apparatus)));
ESM::Apparatus apparatus = record.get();
if (column==mType)
record.get().mData.mType = value.toInt();
apparatus.mData.mType = value.toInt();
else if (column==mQuality)
record.get().mData.mQuality = value.toFloat();
apparatus.mData.mQuality = value.toFloat();
else
{
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Armor)));
ESM::Armor armor = record.get();
if (column==mType)
record.get().mData.mType = value.toInt();
armor.mData.mType = value.toInt();
else if (column==mHealth)
record.get().mData.mHealth = value.toInt();
armor.mData.mHealth = value.toInt();
else if (column==mArmor)
record.get().mData.mArmor = value.toInt();
armor.mData.mArmor = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Armor>::setData (column, data, index, value);
return;
}
record.setModified(armor);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Book)));
ESM::Book book = record.get();
if (column==mScroll)
record.get().mData.mIsScroll = value.toInt();
book.mData.mIsScroll = value.toInt();
else if (column==mSkill)
record.get().mData.mSkillID = value.toInt();
book.mData.mSkillID = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Book>::setData (column, data, index, value);
return;
}
record.setModified(book);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Clothing)));
ESM::Clothing clothing = record.get();
if (column==mType)
record.get().mData.mType = value.toInt();
clothing.mData.mType = value.toInt();
else
{
EnchantableRefIdAdapter<ESM::Clothing>::setData (column, data, index, value);
return;
}
record.setModified(clothing);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Container)));
ESM::Container container = record.get();
if (column==mWeight)
record.get().mWeight = value.toFloat();
container.mWeight = value.toFloat();
else if (column==mOrganic)
{
if (value.toInt())
record.get().mFlags |= ESM::Container::Organic;
container.mFlags |= ESM::Container::Organic;
else
record.get().mFlags &= ~ESM::Container::Organic;
container.mFlags &= ~ESM::Container::Organic;
}
else if (column==mRespawn)
{
if (value.toInt())
record.get().mFlags |= ESM::Container::Respawn;
container.mFlags |= ESM::Container::Respawn;
else
record.get().mFlags &= ~ESM::Container::Respawn;
container.mFlags &= ~ESM::Container::Respawn;
}
else
{
NameRefIdAdapter<ESM::Container>::setData (column, data, index, value);
return;
}
record.setModified(container);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Creature)));
ESM::Creature creature = record.get();
if (column==mColumns.mType)
record.get().mData.mType = value.toInt();
creature.mData.mType = value.toInt();
else if (column==mColumns.mSoul)
record.get().mData.mSoul = value.toInt();
creature.mData.mSoul = value.toInt();
else if (column==mColumns.mScale)
record.get().mScale = value.toFloat();
creature.mScale = value.toFloat();
else if (column==mColumns.mOriginal)
record.get().mOriginal = value.toString().toUtf8().constData();
creature.mOriginal = value.toString().toUtf8().constData();
else if (column==mColumns.mCombat)
record.get().mData.mCombat = value.toInt();
creature.mData.mCombat = value.toInt();
else if (column==mColumns.mMagic)
record.get().mData.mMagic = value.toInt();
creature.mData.mMagic = value.toInt();
else if (column==mColumns.mStealth)
record.get().mData.mStealth = value.toInt();
creature.mData.mStealth = value.toInt();
else
{
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 (value.toInt()!=0)
record.get().mFlags |= iter->second;
creature.mFlags |= iter->second;
else
record.get().mFlags &= ~iter->second;
creature.mFlags &= ~iter->second;
}
else
{
ActorRefIdAdapter<ESM::Creature>::setData (column, data, index, value);
return;
}
}
record.setModified(creature);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Door)));
ESM::Door door = record.get();
if (column==mOpenSound)
record.get().mOpenSound = value.toString().toUtf8().constData();
door.mOpenSound = value.toString().toUtf8().constData();
else if (column==mCloseSound)
record.get().mCloseSound = value.toString().toUtf8().constData();
door.mCloseSound = value.toString().toUtf8().constData();
else
{
NameRefIdAdapter<ESM::Door>::setData (column, data, index, value);
return;
}
record.setModified(door);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Light)));
ESM::Light light = record.get();
if (column==mColumns.mTime)
record.get().mData.mTime = value.toInt();
light.mData.mTime = value.toInt();
else if (column==mColumns.mRadius)
record.get().mData.mRadius = value.toInt();
light.mData.mRadius = value.toInt();
else if (column==mColumns.mColor)
record.get().mData.mColor = value.toInt();
light.mData.mColor = value.toInt();
else if (column==mColumns.mSound)
record.get().mSound = value.toString().toUtf8().constData();
light.mSound = value.toString().toUtf8().constData();
else
{
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 (value.toInt()!=0)
record.get().mData.mFlags |= iter->second;
light.mData.mFlags |= iter->second;
else
record.get().mData.mFlags &= ~iter->second;
light.mData.mFlags &= ~iter->second;
}
else
{
InventoryRefIdAdapter<ESM::Light>::setData (column, data, index, value);
return;
}
}
record.setModified (light);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Miscellaneous)));
ESM::Miscellaneous misc = record.get();
if (column==mKey)
record.get().mData.mIsKey = value.toInt();
misc.mData.mIsKey = value.toInt();
else
{
InventoryRefIdAdapter<ESM::Miscellaneous>::setData (column, data, index, value);
return;
}
record.setModified(misc);
}
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>&> (
data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
ESM::NPC npc = record.get();
if (column==mColumns.mRace)
record.get().mRace = value.toString().toUtf8().constData();
npc.mRace = value.toString().toUtf8().constData();
else if (column==mColumns.mClass)
record.get().mClass = value.toString().toUtf8().constData();
npc.mClass = value.toString().toUtf8().constData();
else if (column==mColumns.mFaction)
record.get().mFaction = value.toString().toUtf8().constData();
npc.mFaction = value.toString().toUtf8().constData();
else if (column==mColumns.mHair)
record.get().mHair = value.toString().toUtf8().constData();
npc.mHair = value.toString().toUtf8().constData();
else if (column==mColumns.mHead)
record.get().mHead = value.toString().toUtf8().constData();
npc.mHead = value.toString().toUtf8().constData();
else
{
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 (value.toInt()!=0)
record.get().mFlags |= iter->second;
npc.mFlags |= iter->second;
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
{
ActorRefIdAdapter<ESM::NPC>::setData (column, data, index, value);
return;
}
}
record.setModified (npc);
}
CSMWorld::NpcAttributesRefIdAdapter::NpcAttributesRefIdAdapter ()
@ -576,7 +667,7 @@ void CSMWorld::NpcAttributesRefIdAdapter::setNestedTable (const RefIdColumn* col
// store the whole struct
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);
}
@ -588,10 +679,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcAttributesRefIdAdapter::nestedTab
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
// return the whole struct
std::vector<typename ESM::NPC::NPDTstruct52> wrap;
std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt52);
// 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,
@ -694,7 +785,7 @@ void CSMWorld::NpcSkillsRefIdAdapter::setNestedTable (const RefIdColumn* column,
// store the whole struct
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);
}
@ -706,10 +797,10 @@ CSMWorld::NestedTableWrapperBase* CSMWorld::NpcSkillsRefIdAdapter::nestedTable (
static_cast<const Record<ESM::NPC>&> (data.getRecord (RefIdData::LocalIndex (index, UniversalId::Type_Npc)));
// return the whole struct
std::vector<typename ESM::NPC::NPDTstruct52> wrap;
std::vector<ESM::NPC::NPDTstruct52> wrap;
wrap.push_back(record.get().mNpdt52);
// 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,

@ -99,7 +99,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_EnchantmentPoints, ColumnBase::Display_Integer));
enchantableColumns.mEnchantmentPoints = &mColumns.back();
@ -135,7 +135,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedInventoryRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), inventoryMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
@ -150,7 +150,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedSpellRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), spellsMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_SpellId, CSMWorld::ColumnBase::Display_Spell));
// Nested table
mColumns.push_back(RefIdColumn (Columns::ColumnId_NpcDestinations,
@ -163,7 +163,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedTravelRefIdAdapter<ESM::Creature> (UniversalId::Type_Creature)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), destMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_DestinationCell, CSMWorld::ColumnBase::Display_Cell));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PosX, CSMWorld::ColumnBase::Display_Float));
mColumns.back().addColumn(
@ -289,7 +289,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedInventoryRefIdAdapter<ESM::Container> (UniversalId::Type_Container)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), contMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_InventoryItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_ItemCount, CSMWorld::ColumnBase::Display_Integer));
@ -301,7 +301,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
creatureColumns.mSoul = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Scale, ColumnBase::Display_Float));
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();
mColumns.push_back (
RefIdColumn (Columns::ColumnId_CombatState, ColumnBase::Display_Integer));
@ -409,10 +409,10 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.push_back (RefIdColumn (Columns::ColumnId_Faction, ColumnBase::Display_Faction));
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();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_String));
mColumns.push_back (RefIdColumn (Columns::ColumnId_Head, ColumnBase::Display_BodyPart));
npcColumns.mHead = &mColumns.back();
mColumns.push_back (RefIdColumn (Columns::ColumnId_Female, ColumnBase::Display_Boolean));
@ -539,9 +539,9 @@ CSMWorld::RefIdCollection::RefIdCollection()
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefType, CSMWorld::ColumnBase::Display_PartRefType));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_PartRefMale, CSMWorld::ColumnBase::Display_BodyPart));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_PartRefFemale, CSMWorld::ColumnBase::Display_BodyPart));
LevListColumns levListColumns (baseColumns);
@ -556,7 +556,7 @@ CSMWorld::RefIdCollection::RefIdCollection()
new NestedLevListRefIdAdapter<ESM::ItemLevList> (UniversalId::Type_ItemLevelledList)));
mNestedAdapters.push_back (std::make_pair(&mColumns.back(), levListMap));
mColumns.back().addColumn(
new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_String));
new RefIdColumn (Columns::ColumnId_LevelledItemId, CSMWorld::ColumnBase::Display_Referenceable));
mColumns.back().addColumn(
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));
if (iter!=mColours.end())
return QBrush (
QColor (iter->second>>24, (iter->second>>16) & 255, (iter->second>>8) & 255,
iter->second & 255));
return QBrush (QColor (iter->second & 0xff,
(iter->second >> 8) & 0xff,
(iter->second >> 16) & 0xff));
if (cell->second.mRegion.empty())
return QBrush (Qt::Dense6Pattern); // no region

@ -5,61 +5,49 @@
#include <stdexcept>
#include <algorithm>
#include <OgreResourceGroupManager.h>
#include <components/vfs/manager.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)
: mBaseDirectory (baseDirectory), mType (type)
{
int baseSize = mBaseDirectory.size();
Ogre::StringVector resourcesGroups =
Ogre::ResourceGroupManager::getSingleton().getResourceGroups();
for (Ogre::StringVector::iterator iter (resourcesGroups.begin());
iter!=resourcesGroups.end(); ++iter)
const std::map<std::string, VFS::File*>& index = vfs->getIndex();
for (std::map<std::string, VFS::File*>::const_iterator it = index.begin(); it != index.end(); ++it)
{
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;
Ogre::StringVectorPtr resources =
Ogre::ResourceGroupManager::getSingleton().listResourceNames (*iter);
for (Ogre::StringVector::const_iterator iter (resources->begin());
iter!=resources->end(); ++iter)
if (extensions)
{
if (static_cast<int> (iter->size())<baseSize+1 ||
iter->substr (0, baseSize)!=mBaseDirectory ||
((*iter)[baseSize]!='/' && (*iter)[baseSize]!='\\'))
continue;
if (extensions)
{
std::string::size_type index = iter->find_last_of ('.');
std::string::size_type index = filepath.find_last_of ('.');
if (index==std::string::npos)
continue;
std::string extension = iter->substr (index+1);
if (index==std::string::npos)
continue;
int i = 0;
std::string extension = filepath.substr (index+1);
for (; extensions[i]; ++i)
if (extensions[i]==extension)
break;
int i = 0;
if (!extensions[i])
continue;
}
for (; extensions[i]; ++i)
if (extensions[i]==extension)
break;
std::string file = iter->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));
if (!extensions[i])
continue;
}
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"
namespace VFS
{
class Manager;
}
namespace CSMWorld
{
class Resources
@ -19,7 +24,7 @@ namespace CSMWorld
public:
/// \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);
int getSize() const;

@ -3,6 +3,11 @@
#include <stdexcept>
CSMWorld::ResourcesManager::ResourcesManager()
: mVFS(NULL)
{
}
void CSMWorld::ResourcesManager::addResources (const Resources& resources)
{
mResources.insert (std::make_pair (resources.getType(), resources));
@ -10,16 +15,24 @@ void CSMWorld::ResourcesManager::addResources (const 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 };
addResources (Resources ("meshes", UniversalId::Type_Mesh, sMeshTypes));
addResources (Resources ("icons", UniversalId::Type_Icon));
addResources (Resources ("music", UniversalId::Type_Music));
addResources (Resources ("sound", UniversalId::Type_SoundRes));
addResources (Resources ("textures", UniversalId::Type_Texture));
addResources (Resources ("videos", UniversalId::Type_Video));
addResources (Resources (vfs, "meshes", UniversalId::Type_Mesh, sMeshTypes));
addResources (Resources (vfs, "icons", UniversalId::Type_Icon));
addResources (Resources (vfs, "music", UniversalId::Type_Music));
addResources (Resources (vfs, "sound", UniversalId::Type_SoundRes));
addResources (Resources (vfs, "textures", UniversalId::Type_Texture));
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

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

@ -264,6 +264,8 @@ namespace
{ CSMWorld::UniversalId::Type_Texture, CSMWorld::ColumnBase::Display_Texture },
{ CSMWorld::UniversalId::Type_Video, CSMWorld::ColumnBase::Display_Video },
{ 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
};

@ -56,6 +56,7 @@ namespace
{ 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_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
};
@ -120,6 +121,7 @@ namespace
{ 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_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
};

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

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

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

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

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

@ -7,7 +7,7 @@
#include <QMenuBar>
#include <QMdiArea>
#include <QDockWidget>
#include <QtGui/QApplication>
#include <QApplication>
#include <QDesktopWidget>
#include <QScrollArea>
#include <QHBoxLayout>
@ -70,6 +70,10 @@ void CSVDoc::View::setupFileMenu()
connect (loadErrors, SIGNAL (triggered()), this, SLOT (loadErrorLog()));
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);
connect (close, SIGNAL (triggered()), this, SLOT (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.
// 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);
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);
@ -614,6 +616,17 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin
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()
{
mViewManager.addView (mDocument);
@ -804,6 +817,11 @@ void CSVDoc::View::addSearchSubView()
addSubView (mDocument->newSearch());
}
void CSVDoc::View::addMetaDataSubView()
{
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_MetaData, "sys::meta"));
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);

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

@ -1,30 +1,32 @@
#include "viewmanager.hpp"
#include <vector>
#include <map>
#include <QApplication>
#include <QDesktopWidget>
#include <QMessageBox>
#include <QPushButton>
#include "../../model/doc/documentmanager.hpp"
#include "../../model/doc/document.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/universalid.hpp"
#include "../../model/world/idcompletionmanager.hpp"
#include "../world/util.hpp"
#include "../world/enumdelegate.hpp"
#include "../world/vartypedelegate.hpp"
#include "../world/recordstatusdelegate.hpp"
#include "../world/idtypedelegate.hpp"
#include "../world/idcompletiondelegate.hpp"
#include "../world/colordelegate.hpp"
#include "../../model/settings/usersettings.hpp"
#include "view.hpp"
#include <QMessageBox>
#include <QPushButton>
#include <QtGui/QApplication>
void CSVDoc::ViewManager::updateIndices()
{
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,
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
{
CSMWorld::ColumnBase::Display mDisplay;

@ -1,8 +1,7 @@
#include "cell.hpp"
#include <OgreSceneManager.h>
#include <OgreSceneNode.h>
#include <osg/Group>
#include <components/misc/stringops.hpp>
#include <components/esm/loadland.hpp>
@ -11,7 +10,6 @@
#include "../../model/world/columns.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/refcollection.hpp"
#include "../world/physicssystem.hpp"
#include "elements.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);
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;
}
}
@ -53,12 +51,11 @@ bool CSVRender::Cell::addObjects (int start, int end)
return modified;
}
CSVRender::Cell::Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager,
const std::string& id, boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin)
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mPhysics(physics), mSceneMgr(sceneManager), mX(0), mY(0)
CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id)
: mData (data), mId (Misc::StringUtils::lowerCase (id)), mX(0), mY(0)
{
mCellNode = sceneManager->getRootSceneNode()->createChildSceneNode();
mCellNode->setPosition (origin);
mCellNode = new osg::Group;
rootNode->addChild(mCellNode);
CSMWorld::IdTable& references = dynamic_cast<CSMWorld::IdTable&> (
*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();
if(esmLand && esmLand->mDataTypes&ESM::Land::DATA_VHGT)
{
mTerrain.reset(new Terrain::TerrainGrid(sceneManager, new TerrainStorage(mData), Element_Terrain, true,
Terrain::Align_XY));
mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem(), NULL, new TerrainStorage(mData), Element_Terrain<<1));
mTerrain->loadCell(esmLand->mX,
esmLand->mY);
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
mX = esmLand->mX;
mY = esmLand->mY;
mPhysics->addHeightField(sceneManager,
esmLand->mLandData->mHeights, mX, mY, 0, worldsize / (verts-1), verts);
}
}
}
CSVRender::Cell::~Cell()
{
if (mTerrain.get())
mPhysics->removeHeightField(mSceneMgr, mX, mY);
for (std::map<std::string, Object *>::iterator iter (mObjects.begin());
iter!=mObjects.end(); ++iter)
delete iter->second;
mCellNode->getCreator()->destroySceneNode (mCellNode);
mCellNode->getParent(0)->removeChild(mCellNode);
}
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)
{
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;
}
@ -222,11 +211,3 @@ bool CSVRender::Cell::referenceAdded (const QModelIndex& parent, int start, int
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 <OgreVector3.h>
#include <osg/ref_ptr>
#ifndef Q_MOC_RUN
#include <components/terrain/terraingrid.hpp>
@ -17,10 +17,9 @@
class QModelIndex;
namespace Ogre
namespace osg
{
class SceneManager;
class SceneNode;
class Group;
}
namespace CSMWorld
@ -28,22 +27,15 @@ namespace CSMWorld
class Data;
}
namespace CSVWorld
{
class PhysicsSystem;
}
namespace CSVRender
{
class Cell
{
CSMWorld::Data& mData;
std::string mId;
Ogre::SceneNode *mCellNode;
osg::ref_ptr<osg::Group> mCellNode;
std::map<std::string, Object *> mObjects;
std::auto_ptr<Terrain::TerrainGrid> mTerrain;
boost::shared_ptr<CSVWorld::PhysicsSystem> mPhysics;
Ogre::SceneManager *mSceneMgr;
int mX;
int mY;
@ -59,8 +51,7 @@ namespace CSVRender
public:
Cell (CSMWorld::Data& data, Ogre::SceneManager *sceneManager, const std::string& id,
boost::shared_ptr<CSVWorld::PhysicsSystem> physics, const Ogre::Vector3& origin = Ogre::Vector3 (0, 0, 0));
Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::string& id);
~Cell();
@ -84,8 +75,6 @@ namespace CSVRender
/// \return Did this call result in a modification of the visual representation of
/// this cell?
bool referenceAdded (const QModelIndex& parent, int start, int end);
float getTerrainHeightAt(const Ogre::Vector3 &pos) const;
};
}

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

@ -1,10 +1,13 @@
#ifndef OPENCS_VIEW_LIGHTING_H
#define OPENCS_VIEW_LIGHTING_H
namespace Ogre
#include <osg/ref_ptr>
namespace osg
{
class SceneManager;
class ColourValue;
class Vec4f;
class LightSource;
class Group;
}
namespace CSVRender
@ -13,14 +16,19 @@ namespace CSVRender
{
public:
Lighting() : mRootNode(0) {}
virtual ~Lighting();
virtual void activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient = 0) = 0;
virtual void activate (osg::Group* rootNode) = 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 <OgreSceneManager.h>
#include <osg/LightSource>
CSVRender::LightingBright::LightingBright() : mSceneManager (0), mLight (0) {}
CSVRender::LightingBright::LightingBright() {}
void CSVRender::LightingBright::activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient)
void CSVRender::LightingBright::activate (osg::Group* rootNode)
{
mSceneManager = sceneManager;
mRootNode = rootNode;
mSceneManager->setAmbientLight (Ogre::ColourValue (1.0, 1.0, 1.0, 1));
mLightSource = (new osg::LightSource);
mLight = mSceneManager->createLight();
mLight->setType (Ogre::Light::LT_DIRECTIONAL);
mLight->setDirection (Ogre::Vector3 (0, 0, -1));
mLight->setDiffuseColour (Ogre::ColourValue (1.0, 1.0, 1.0));
osg::ref_ptr<osg::Light> light (new osg::Light);
light->setAmbient(osg::Vec4f(0.f, 0.f, 0.f, 1.f));
light->setPosition(osg::Vec4f(0.f, 0.f, 1.f, 0.f));
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()
{
if (mLight)
{
mSceneManager->destroyLight (mLight);
mLight = 0;
}
if (mRootNode && mLightSource.get())
mRootNode->removeChild(mLightSource);
}
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"
namespace Ogre
namespace osg
{
class Light;
class Group;
}
namespace CSVRender
{
class LightingBright : public Lighting
{
Ogre::SceneManager *mSceneManager;
Ogre::Light *mLight;
public:
LightingBright();
virtual void activate (Ogre::SceneManager *sceneManager,
const Ogre::ColourValue *defaultAmbient = 0);
virtual void activate (osg::Group* rootNode);
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