Merge branch 'master' into QtOGre

Conflicts:
	apps/opencs/model/doc/document.cpp
	apps/opencs/view/render/pagedworldspacewidget.cpp
	apps/opencs/view/render/pagedworldspacewidget.hpp
	components/nif/niffile.hpp
	libs/openengine/bullet/physic.hpp
loadfix
cc9cii 10 years ago
commit 312b7cd571

1
.gitignore vendored

@ -37,6 +37,7 @@ resources
/omwlauncher
/openmw
/opencs
/niftest
## generated objects
apps/openmw/config.hpp

@ -0,0 +1,139 @@
Adam Hogan <comrade@comrade-desktop.(none)>
Aleksandar Jovanov <ajovanov93@yahoo.com>
Alexander Olofsson <ace@haxalot.com>
Alex McKibben <mckibbenta@gmail.com>
Alex "rainChu" Haddad <alx1213@gmail.com>
Ardekantur <greystone@ardekantur.com>
Armin Preiml <b.nutzer@gmail.com>
Artem Kotsynyak <greye@carceri>
Arthur Moore <arthur@Behemoth>
Arthur Moore <Arthur.Moore.git@cd-net.net>
athile <athile@athile.net>
athile <athile.g@gmail.com>
Stefan Galowicz <bogglez@the.mind>
Bret Curtis <psi29a@gmail.com>
Britt Mathis <britt.mathis@gmail.com>
Sandy Carter <bwrsandman@gmail.com>
Sandy Carter <mr.sandy.carter@gmail.com>
Carl Maxwell <carl.maxwell@gmail.com>
cc9cii <cc9c@iinet.net.au>
Cory F. Cohen <cfcohen@verizon.net>
Chris Robinson <chris.kcat@gmail.com>
Cris Mihalache <mirceam94@hotmail.com>
darkf <lw9k123@gmail.com>
Diggory Hardy <diggory.hardy@gmail.com>
Thomas Luppi <ThomasLuppi@gmail.com>
Thomas Luppi <tluppi@thomas-GE60.(none)>
Dmitriy 'Endorph' Shkurskiy <end0rph@hotmail.com>
Dmitry Marakasov <amdmi3@amdmi3.ru>
Douglas Diniz <dgdiniz@gmail.com>
Douglas Mencken <dougmencken@gmail.com>
Edmondo Tommasina <edmondo.tommasina@gmail.com>
Eduard Cot <eduard@eduard-iMac.(none)>
Eli2 <fabian@fabian-desktop.(none)>
Emanuel Guével <guevel.emanuel@gmail.com>
Leon Saunders <LeonDavidSaunders@gmail.com>
Fil Krynicki <filipkrynicki@gmail.com>
John Blomberg <johnblo@kth.se>
Gašper Sedej <gsedej@gmail.com>
Michał Bień <michal1.bien@gmail.com>
Joel Graff <monograff76@gmail.com>
Paul McElroy <pcm1123@gmail.com>
Artem Kotsynyak <greye@carceri>
Artem Kotsynyak <greye@null.net>
gugus <gus_512@hotmail.com>
guidoj <guido@thuisbasis.net>
gus <gus_512@hotmail.com>
Hallfaer Tuilinn <gijsbertth@gmail.com>
Julian Ospald <julian.ospald@googlemail.com>
Jacob Essex <jacob@jacobessex.com>
Jan Borsodi <jborsodi@gmail.com>
Jan-Peter Nilsson <peppe@pappkartong.se>
Jason Hooks <Hooks@.(none)>
Jason Hooks <jason@Jason-ThinkPad-R61.(none)>
Jason Hooks <jhooks1@mix.wvu.edu>
Jeffrey Haines <jeffhaines@me.com>
Jeffrey Haines <jib-y@users.noreply.github.com>
Jordan Ayers <jordan.ayers@gmail.com>
Jordan Milne <jordan.milne@saynotolinux.com>
Josua Grawitter <josh@greyage.org>
Julien Voisin <pouicpouicpouic@gmail.com>
Karl-Felix Glatzer <karl.glatzer@gmx.de>
Chris Robinson <chris.kcat@gmail.com>
Kevin Poitra <pupkev@yahoo.com>
Roman Proskuryakov <humbug@deeptown.org>
Lars Söderberg <lazze_1983@hotmail.com>
lazydev <lazydev@homecomp>
lazydev <lazydev@nomail>
Lukasz Gromanowski <lgromanowski@gmail.com>
Marc Bouvier <marcrbouvier@gmail.com>
Marcin Hulist <Gohan1989@gmail.com>
Marc Zinnschlag <marc@zpages.de>
Marek Kochanowicz <herr@mikrus.pl>
Marek Kochanowicz <marek@localhost.localdomain>
Marek Kochanowicz <sirherrbatka@gmail.com>
Mark Siewert <mark.siewert@t-online.de>
Mark Siewert <ms@cerebra.localdomain>
megaton <9megaton6@gmail.com>
Michael Mc Donnell <michael@mcdonnell.dk>
Michael Papageorgiou <werdanith@yahoo.gr>
Michal Sciubidlo <michal.sciubidlo@gmail.com>
Michał Ściubidło <michal.sciubidlo@gmail.com>
Nathan Jeffords <blunted2night@gmail.com>
Nicolay Korslund <korslund@gmail.com>
Nicolay Korslund <nicolayk@met.no>
Nikolay Kasyanov <corrmage@gmail.com>
pchan3 <chantlerpeter@gmail.com>
Pieter van der Kloet <pvdkloet@gmail.com>
Mateusz Kołaczek <mateusz.kolaczek@gmail.com>
Bret Curtis <psi29a@gmail.com>
Pieter van der Kloet <pvdkloet@gmail.com>
Rohit Nirmal <rohitnirmal9@gmail.com>
Roman Melnik <kromgart@gmail.com>
Radu-Marius Popovici <rpopovici@github.com>
Sandy Carter <bwrsandman@gmail.com>
Scott Howard <showard314@gmail.com>
Jannik Heller <scrawl@baseoftrash.de>
Jannik Heller <scrawl@scrawl-laptop.(none)>
Sebastian Wick <sebastian@sebastianwick.net>
Sebastian Wick <wick.sebastian@gmail.com>
Sergey Shambir <sergey.shambir.auto@gmail.com>
sergoz <parapvr@yandex.ru>
Chris Boyce <slothlife@users.noreply.github.com>
Star-Demon <starsickle@yahoo.com>
Sylvain Thesnieres <garvek@gmail.com>
Thomas Luppi <digrules@gmail.com>
Thomas Luppi <tluppi@thomas-GE60.(none)>
Thoronador <thoronador@users.sourceforge.net>
TomKoenderink <tom_koenderink-github@omniadicta.net>
Tom Mason <wheybags@wheybags.com>
Torben Carrington <torbenlcarrington@Gmail.com>
Vincent Heuken <vincent@vincentheuken.com>
Manuel Edelmann <edelmann.manuel@gmail.com>
Manuel Edelmann <vorenon@hotmail.com>
Alexander Nadeau <wareya@gmail.com>
Michael Hogan <mr.michaelhogan@gmail.com>
Jacob Essex <github@JacobEssex.com>
Yuri Krupenin <yuri.krupenin@gmail.com>
Bret Curtis <noone@your.box>
sirherrbatka <herr@localhost.localdomain>
sirherrbatka <sirherrbatka@myopera.com>
sergei <sergei@ubuntu.(none)>
riothamus <digimars@gmail.com>
nobrakal <nobrakal@gmail.com>
nkorslund <nkorslund@ea6a568a-9f4f-0410-981a-c910a81bb256>
mrcheko <cheko@sevas.ua>
Miroslav Puda <pakanek@gmail.com>
MiroslavR <miroslavr256@gmail.com>
mckibbenta <mckibbenta@gmail.com>
jeaye <jeaye@arrownext.com>
eroen <eroen@falcon.eroen.eu>
eroen <eroen@occam.eroen.eu>
dreamer-dead <dreamer.dead@gmail.com>
crysthala <crystalsoulslayer@gmail.com>
Berulacks <beru@eml.cc>
Axujen <axujen@gmail.com>
root <root@debian>
unknown <Hooks@.(none)>

@ -10,11 +10,10 @@ before_install:
- echo "yes" | sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu `lsb_release -sc` main universe restricted multiverse"
- echo "yes" | sudo apt-add-repository ppa:openmw/openmw
- sudo apt-get update -qq
- sudo apt-get install -qq libboost-all-dev libgtest-dev google-mock
- sudo apt-get install -qq libqt4-dev
- sudo apt-get install -qq libopenal-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev
- sudo apt-get install -qq libgtest-dev google-mock
- sudo apt-get install -qq libboost-filesystem-dev libboost-program-options-dev libboost-system-dev libboost-thread-dev libboost-wave-dev
- sudo apt-get install -qq libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libavresample-dev
- sudo apt-get install -qq libbullet-dev libogre-1.9-dev libmygui-dev libsdl2-dev libunshield-dev libtinyxml-dev libopenal-dev libqt4-dev
- sudo mkdir /usr/src/gtest/build
- cd /usr/src/gtest/build
- sudo cmake .. -DBUILD_SHARED_LIBS=1
@ -25,7 +24,7 @@ before_script:
- cd -
- mkdir build
- cd build
- cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DBUILD_WITH_DPKG=1
- cmake .. -DBUILD_WITH_CODE_COVERAGE=1 -DBUILD_UNITTESTS=1 -DCMAKE_INSTALL_PREFIX=/usr -DBINDIR=/usr/games -DCMAKE_BUILD_TYPE="RelWithDebInfo" -DUSE_SYSTEM_TINYXML=TRUE
script:
- make -j4
after_script:

@ -12,7 +12,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/)
message(STATUS "Configuring OpenMW...")
set(OPENMW_VERSION_MAJOR 0)
set(OPENMW_VERSION_MINOR 31)
set(OPENMW_VERSION_MINOR 32)
set(OPENMW_VERSION_RELEASE 0)
set(OPENMW_VERSION_COMMITHASH "")
@ -54,6 +54,10 @@ endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
# Macros
include(OpenMWMacros)
if (ANDROID)
set(CMAKE_FIND_ROOT_PATH ${OPENMW_DEPENDENCIES_DIR} "${CMAKE_FIND_ROOT_PATH}")
endif (ANDROID)
# doxygen main page
configure_file ("${OpenMW_SOURCE_DIR}/docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_DIR}/docs/mainpage.hpp")
@ -66,16 +70,15 @@ option(SDL2_STATIC "Link static build of SDL into the binaries" FALSE)
option(OPENMW_UNITY_BUILD "Use fewer compilation units to speed up compile time" FALSE)
# Apps and tools
option(BUILD_BSATOOL "build BSA extractor" OFF)
option(BUILD_BSATOOL "build BSA extractor" ON)
option(BUILD_ESMTOOL "build ESM inspector" ON)
option(BUILD_LAUNCHER "build Launcher" ON)
option(BUILD_MWINIIMPORTER "build MWiniImporter" ON)
option(BUILD_OPENCS "build OpenMW Construction Set" ON)
option(BUILD_WITH_CODE_COVERAGE "Enable code coverage with gconv" OFF)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest ang GMock frameworks" OFF)
# Sound source selection
option(USE_FFMPEG "use ffmpeg for sound" ON)
option(BUILD_UNITTESTS "Enable Unittests with Google C++ Unittest and GMock frameworks" 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)
@ -101,33 +104,32 @@ cmake_minimum_required(VERSION 2.6)
# source directory: libs
set(LIBDIR ${CMAKE_SOURCE_DIR}/libs)
set(LIBS_DIR ${CMAKE_SOURCE_DIR}/libs)
set(OENGINE_OGRE
${LIBDIR}/openengine/ogre/renderer.cpp
${LIBDIR}/openengine/ogre/fader.cpp
${LIBDIR}/openengine/ogre/lights.cpp
${LIBDIR}/openengine/ogre/selectionbuffer.cpp
${LIBDIR}/openengine/ogre/imagerotate.cpp
${LIBS_DIR}/openengine/ogre/renderer.cpp
${LIBS_DIR}/openengine/ogre/lights.cpp
${LIBS_DIR}/openengine/ogre/selectionbuffer.cpp
${LIBS_DIR}/openengine/ogre/imagerotate.cpp
)
set(OENGINE_GUI
${LIBDIR}/openengine/gui/loglistener.cpp
${LIBDIR}/openengine/gui/manager.cpp
${LIBDIR}/openengine/gui/layout.hpp
${LIBS_DIR}/openengine/gui/loglistener.cpp
${LIBS_DIR}/openengine/gui/manager.cpp
${LIBS_DIR}/openengine/gui/layout.hpp
)
set(OENGINE_BULLET
${LIBDIR}/openengine/bullet/BtOgre.cpp
${LIBDIR}/openengine/bullet/BtOgreExtras.h
${LIBDIR}/openengine/bullet/BtOgreGP.h
${LIBDIR}/openengine/bullet/BtOgrePG.h
${LIBDIR}/openengine/bullet/physic.cpp
${LIBDIR}/openengine/bullet/physic.hpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.cpp
${LIBDIR}/openengine/bullet/BulletShapeLoader.h
${LIBDIR}/openengine/bullet/trace.cpp
${LIBDIR}/openengine/bullet/trace.h
${LIBS_DIR}/openengine/bullet/BtOgre.cpp
${LIBS_DIR}/openengine/bullet/BtOgreExtras.h
${LIBS_DIR}/openengine/bullet/BtOgreGP.h
${LIBS_DIR}/openengine/bullet/BtOgrePG.h
${LIBS_DIR}/openengine/bullet/physic.cpp
${LIBS_DIR}/openengine/bullet/physic.hpp
${LIBS_DIR}/openengine/bullet/BulletShapeLoader.cpp
${LIBS_DIR}/openengine/bullet/BulletShapeLoader.h
${LIBS_DIR}/openengine/bullet/trace.cpp
${LIBS_DIR}/openengine/bullet/trace.h
)
@ -138,32 +140,24 @@ set(OPENMW_LIBS ${OENGINE_ALL})
set(OPENMW_LIBS_HEADER)
# Sound setup
set(GOT_SOUND_INPUT 0)
set(SOUND_INPUT_INCLUDES "")
set(SOUND_INPUT_LIBRARY "")
set(SOUND_DEFINE "")
if (USE_FFMPEG)
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE)
find_package(FFmpeg)
if (FFMPEG_FOUND)
set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIRS})
set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES} ${SWSCALE_LIBRARIES})
set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG)
set(GOT_SOUND_INPUT 1)
endif (FFMPEG_FOUND)
endif (USE_FFMPEG)
if (NOT GOT_SOUND_INPUT)
message(WARNING "--------------------")
message(WARNING "Failed to find any sound input packages")
message(WARNING "--------------------")
endif (NOT GOT_SOUND_INPUT)
if (NOT FFMPEG_FOUND)
message(WARNING "--------------------")
message(WARNING "FFmpeg not found, video playback will be disabled")
message(WARNING "--------------------")
endif (NOT FFMPEG_FOUND)
set(FFmpeg_FIND_COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE AVRESAMPLE)
unset(FFMPEG_LIBRARIES CACHE)
find_package(FFmpeg)
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})
else()
if( AVRESAMPLE_FOUND )
set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES} ${AVRESAMPLE_LIBRARIES})
else()
message(FATAL_ERROR "Install either libswresample (FFmpeg) or libavresample (Libav).")
endif()
endif()
# TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
@ -227,7 +221,15 @@ IF(BOOST_STATIC)
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(MyGUI REQUIRED)
if (${MYGUI_VERSION} VERSION_LESS "3.2.1")
message(FATAL_ERROR "OpenMW requires MyGUI 3.2.1 or later, please install the latest version from http://mygui.info")
endif()
find_package(Boost REQUIRED COMPONENTS ${BOOST_COMPONENTS})
find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED)
@ -258,7 +260,12 @@ if(OGRE_STATIC)
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)
@ -272,7 +279,7 @@ include_directories("."
${MYGUI_INCLUDE_DIRS}
${MYGUI_PLATFORM_INCLUDE_DIRS}
${OPENAL_INCLUDE_DIR}
${LIBDIR}
${LIBS_DIR}
)
link_directories(${SDL2_LIBRARY_DIRS} ${Boost_LIBRARY_DIRS} ${OGRE_LIB_DIR} ${MYGUI_LIB_DIR})
@ -325,12 +332,14 @@ else ()
add_definitions(-DOGRE_PLUGIN_DEBUG_SUFFIX="_d")
endif()
add_definitions(-DOGRE_PLUGIN_DIR_REL="${OGRE_PLUGIN_DIR_REL}")
add_definitions(-DOGRE_PLUGIN_DIR_DBG="${OGRE_PLUGIN_DIR_DBG}")
if (APPLE AND OPENMW_OSX_DEPLOYMENT)
# 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 (NOT DEFINED ${OGRE_PLUGIN_DIR})
set(OGRE_PLUGIN_DIR ${OGRE_PLUGIN_DIR_REL})
endif()
add_definitions(-DOGRE_PLUGIN_DIR="${OGRE_PLUGIN_DIR}")
endif()
@ -342,8 +351,10 @@ add_subdirectory(files/mygui)
if (APPLE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${APP_BUNDLE_DIR}/Contents/MacOS")
else (APPLE)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${OpenMW_BINARY_DIR}")
endif (APPLE)
# Other files
@ -377,9 +388,6 @@ endif()
if (CMAKE_COMPILER_IS_GNUCC)
SET(CMAKE_CXX_FLAGS "-Wall -Wextra -Wno-unused-parameter -Wno-reorder -std=c++98 -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
# Silence warnings in OGRE headers. Remove once OGRE got fixed!
SET(CMAKE_CXX_FLAGS "-Wno-ignored-qualifiers ${CMAKE_CXX_FLAGS}")
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if ("${GCC_VERSION}" VERSION_GREATER 4.6 OR "${GCC_VERSION}" VERSION_EQUAL 4.6)
@ -391,11 +399,18 @@ IF(NOT WIN32 AND NOT APPLE)
# Linux building
# Paths
SET(BINDIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Where to install binaries")
SET(LIBDIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Where to install libraries")
SET(DATAROOTDIR "${CMAKE_INSTALL_PREFIX}/share" CACHE PATH "Sets the root of data directories to a non-default location")
SET(DATADIR "${DATAROOTDIR}/games/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
SET(GLOBAL_DATA_PATH "${DATAROOTDIR}/games/" CACHE PATH "Set data path prefix")
SET(DATADIR "${GLOBAL_DATA_PATH}/openmw" CACHE PATH "Sets the openmw data directories to a non-default location")
SET(ICONDIR "${DATAROOTDIR}/pixmaps" CACHE PATH "Set icon dir")
SET(LICDIR "${DATAROOTDIR}/licenses/openmw" CACHE PATH "Sets the openmw license directory to a non-default location.")
SET(SYSCONFDIR "/etc/openmw" CACHE PATH "Set config dir")
IF("${CMAKE_INSTALL_PREFIX}" STREQUAL "/usr")
SET(GLOBAL_CONFIG_PATH "/etc/" CACHE PATH "Set config dir prefix")
ELSE()
SET(GLOBAL_CONFIG_PATH "${CMAKE_INSTALL_PREFIX}/etc/" CACHE PATH "Set config dir prefix")
ENDIF()
SET(SYSCONFDIR "${GLOBAL_CONFIG_PATH}/openmw" CACHE PATH "Set config dir")
# Install binaries
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/openmw" DESTINATION "${BINDIR}" )
@ -414,6 +429,12 @@ IF(NOT WIN32 AND NOT APPLE)
IF(BUILD_OPENCS)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/opencs" DESTINATION "${BINDIR}" )
ENDIF(BUILD_OPENCS)
IF(BUILD_NIFTEST)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/niftest" DESTINATION "${BINDIR}" )
ENDIF(BUILD_NIFTEST)
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}" )
@ -463,6 +484,9 @@ if(WIN32)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/opencs.exe" DESTINATION ".")
INSTALL(FILES "${OpenMW_BINARY_DIR}/opencs.ini" DESTINATION ".")
ENDIF(BUILD_OPENCS)
if(BUILD_MYGUI_PLUGIN)
INSTALL(PROGRAMS "${OpenMW_BINARY_DIR}/Release/Plugin_MyGUI_OpenMW_Resources.dll" DESTINATION ".")
ENDIF(BUILD_MYGUI_PLUGIN)
INSTALL(DIRECTORY "${OpenMW_BINARY_DIR}/resources" DESTINATION ".")
@ -492,8 +516,8 @@ if(WIN32)
SET(CPACK_NSIS_HELP_LINK "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_URL_INFO_ABOUT "http:\\\\\\\\www.openmw.org")
SET(CPACK_NSIS_INSTALLED_ICON_NAME "omwlauncher.exe")
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico")
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/launcher/images/openmw.ico")
SET(CPACK_NSIS_MUI_ICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
SET(CPACK_NSIS_MUI_UNIICON "${OpenMW_SOURCE_DIR}/files/windows/openmw.ico")
SET(CPACK_PACKAGE_ICON "${OpenMW_SOURCE_DIR}\\\\files\\\\openmw.bmp")
SET(VCREDIST32 "${OpenMW_BINARY_DIR}/vcredist_x86.exe")
@ -530,6 +554,16 @@ 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)
# Apps and tools
add_subdirectory( apps/openmw )
@ -567,6 +601,16 @@ endif()
if (WIN32)
if (MSVC)
if (MULTITHREADED_BUILD)
set( MT_BUILD "/MP")
endif (MULTITHREADED_BUILD)
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(SolutionDir)$(Configuration)" )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "$(ProjectDir)$(Configuration)" )
endforeach( OUTPUTCONFIG )
if (USE_DEBUG_CONSOLE)
set_target_properties(openmw PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE")
set_target_properties(openmw PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE")
@ -607,6 +651,9 @@ if (WIN32)
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'
# caused by boost
4191 # 'type cast' : unsafe conversion (1.56, thread_primitives.hpp, normally off)
# OpenMW specific warnings
4099 # Type mismatch, declared class or struct is defined with other type
4100 # Unreferenced formal parameter (-Wunused-parameter)
@ -630,30 +677,32 @@ if (WIN32)
# 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})
set_target_properties(shiny PROPERTIES COMPILE_FLAGS "${SHINY_WARNINGS} ${MT_BUILD}")
# there's an unreferenced local variable in the ogre platform, suppress it
set(SHINY_OGRE_WARNINGS "${WARNINGS} /wd4101")
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS ${SHINY_OGRE_WARNINGS})
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(shiny.OgrePlatform PROPERTIES COMPILE_FLAGS "${SHINY_OGRE_WARNINGS} ${MT_BUILD}")
set_target_properties(sdl4ogre PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
# oics uses tinyxml, which has an initialized but unused variable
set(OICS_WARNINGS "${WARNINGS} /wd4189")
set_target_properties(oics PROPERTIES COMPILE_FLAGS ${OICS_WARNINGS})
set_target_properties(components PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(oics PROPERTIES COMPILE_FLAGS "${OICS_WARNINGS} ${MT_BUILD}")
set_target_properties(components PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
if (BUILD_LAUNCHER)
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(omwlauncher PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_LAUNCHER)
set_target_properties(openmw PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(openmw PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
if (BUILD_BSATOOL)
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(bsatool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_BSATOOL)
if (BUILD_ESMTOOL)
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(esmtool PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_ESMTOOL)
if (BUILD_OPENCS)
set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${WARNINGS})
# QT triggers an informational warning that the object layout may differ when compiled with /vd2
set(OPENCS_WARNINGS "${WARNINGS} ${MT_BUILD} /wd4435")
set_target_properties(opencs PROPERTIES COMPILE_FLAGS ${OPENCS_WARNINGS})
endif (BUILD_OPENCS)
if (BUILD_MWINIIMPORTER)
set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS ${WARNINGS})
set_target_properties(mwiniimport PROPERTIES COMPILE_FLAGS "${WARNINGS} ${MT_BUILD}")
endif (BUILD_MWINIIMPORTER)
endif(MSVC)

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

File diff suppressed because it is too large Load Diff

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

@ -15,7 +15,7 @@ set(LAUNCHER
utils/textinputdialog.cpp
utils/lineedit.cpp
${CMAKE_SOURCE_DIR}/files/launcher/launcher.rc
${CMAKE_SOURCE_DIR}/files/windows/launcher.rc
)
if(NOT WIN32)
LIST(APPEND LAUNCHER unshieldthread.cpp)

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

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

@ -1,15 +1,17 @@
set (OPENCS_SRC main.cpp)
set (OPENCS_SRC main.cpp
${CMAKE_SOURCE_DIR}/files/windows/opencs.rc
)
opencs_units (. editor)
set (CMAKE_BUILD_TYPE DEBUG)
opencs_units (model/doc
document operation saving documentmanager loader
document operation saving documentmanager loader runner
)
opencs_units_noqt (model/doc
stage savingstate savingstages
stage savingstate savingstages blacklist
)
opencs_hdrs_noqt (model/doc
@ -24,7 +26,7 @@ opencs_units (model/world
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
refidadapter refiddata refidadapterimp ref collectionbase refcollection columns infocollection tablemimedata cellcoordinates cellselection resources resourcesmanager scope
)
opencs_hdrs_noqt (model/world
@ -38,13 +40,13 @@ opencs_units (model/tools
opencs_units_noqt (model/tools
mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck spellcheck referenceablecheck scriptcheck
birthsigncheck spellcheck referenceablecheck scriptcheck bodypartcheck
)
opencs_units (view/doc
viewmanager view operations operation subview startup filedialog newgame
filewidget adjusterwidget loader
filewidget adjusterwidget loader globaldebugprofilemenu runlogsubview
)
@ -69,7 +71,7 @@ opencs_units_noqt (view/world
)
opencs_units (view/widget
scenetoolbar scenetool scenetoolmode pushbutton
scenetoolbar scenetool scenetoolmode pushbutton scenetooltoggle scenetoolrun
)
opencs_units (view/render
@ -82,6 +84,10 @@ opencs_units_noqt (view/render
lightingbright object cell
)
opencs_hdrs_noqt (view/render
elements
)
opencs_units (view/tools
reportsubview
@ -122,12 +128,8 @@ opencs_units_noqt (model/filter
node unarynode narynode leafnode booleannode parser andnode ornode notnode textnode valuenode
)
opencs_hdrs_noqt (model/filter
filter
)
opencs_units (view/filter
filtercreator filterbox recordfilterbox editwidget
filterbox recordfilterbox editwidget
)
set (OPENCS_US

@ -80,13 +80,17 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
boost::program_options::options_description desc("Syntax: opencs <options>\nAllowed options");
desc.add_options()
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken())
("data", boost::program_options::value<Files::PathContainer>()->default_value(Files::PathContainer(), "data")->multitoken()->composing())
("data-local", boost::program_options::value<std::string>()->default_value(""))
("fs-strict", boost::program_options::value<bool>()->implicit_value(true)->default_value(false))
("encoding", boost::program_options::value<std::string>()->default_value("win1252"))
("resources", boost::program_options::value<std::string>()->default_value("resources"))
("fallback-archive", boost::program_options::value<std::vector<std::string> >()->
default_value(std::vector<std::string>(), "fallback-archive")->multitoken());
default_value(std::vector<std::string>(), "fallback-archive")->multitoken())
("script-blacklist", boost::program_options::value<std::vector<std::string> >()->default_value(std::vector<std::string>(), "")
->multitoken(), "exclude specified script from the verifier (if the use of the blacklist is enabled)")
("script-blacklist-use", boost::program_options::value<bool>()->implicit_value(true)
->default_value(true), "enable script blacklisting");
boost::program_options::notify(variables);
@ -97,6 +101,10 @@ std::pair<Files::PathContainer, std::vector<std::string> > CS::Editor::readConfi
mDocumentManager.setResourceDir (mResources = variables["resources"].as<std::string>());
if (variables["script-blacklist-use"].as<bool>())
mDocumentManager.setBlacklistedScripts (
variables["script-blacklist"].as<std::vector<std::string> >());
mFsStrict = variables["fs-strict"].as<bool>();
Files::PathContainer dataDirs, dataLocal;
@ -181,7 +189,7 @@ void CS::Editor::createNewFile (const boost::filesystem::path &savePath)
files.push_back(path.toUtf8().constData());
}
files.push_back(mFileDialog.filename().toUtf8().constData());
files.push_back (savePath);
mDocumentManager.addDocument (files, savePath, true);

@ -16,6 +16,8 @@
#include <components/files/multidircollection.hpp>
#include <components/nifcache/nifcache.hpp>
#include "model/settings/usersettings.hpp"
#include "model/doc/documentmanager.hpp"
@ -37,6 +39,7 @@ namespace CS
{
Q_OBJECT
Nif::Cache mNifCache;
Files::ConfigurationManager mCfgMgr;
CSMSettings::UserSettings mUserSettings;
CSMDoc::DocumentManager mDocumentManager;

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

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

@ -1,6 +1,7 @@
#include "document.hpp"
#include <cassert>
#include <fstream>
#include <iostream>
#include <boost/filesystem.hpp>
@ -2206,28 +2207,32 @@ void CSMDoc::Document::createBase()
CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager)
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts)
: mSavePath (savePath), mContentFiles (files), mNew (new_), mData (encoding, resourcesManager),
mTools (mData), mResDir(resDir),
mTools (*this), mResDir(resDir),
mProjectPath ((configuration.getUserDataPath() / "projects") /
(savePath.filename().string() + ".project")),
mSaving (*this, mProjectPath, encoding)
mSaving (*this, mProjectPath, encoding),
mRunner (mProjectPath)
{
if (mContentFiles.empty())
throw std::runtime_error ("Empty content file sequence");
if (!boost::filesystem::exists (mProjectPath))
{
boost::filesystem::path locCustomFiltersPath (configuration.getUserDataPath());
locCustomFiltersPath /= "defaultfilters";
boost::filesystem::path customFiltersPath (configuration.getUserDataPath());
customFiltersPath /= "defaultfilters";
if (boost::filesystem::exists (locCustomFiltersPath))
std::ofstream destination (mProjectPath.string().c_str(), std::ios::binary);
if (boost::filesystem::exists (customFiltersPath))
{
boost::filesystem::copy_file (locCustomFiltersPath, mProjectPath);
destination << std::ifstream(customFiltersPath.c_str(), std::ios::binary).rdbuf();
}
else
{
boost::filesystem::copy_file (mResDir / "defaultfilters", mProjectPath);
destination << std::ifstream(std::string(mResDir.string() + "/defaultfilters").c_str(), std::ios::binary).rdbuf();
}
}
@ -2240,20 +2245,24 @@ CSMDoc::Document::Document (const Files::ConfigurationManager& configuration,
createBase();
}
mBlacklist.add (CSMWorld::UniversalId::Type_Script, blacklistedScripts);
addOptionalGmsts();
addOptionalGlobals();
connect (&mUndoStack, SIGNAL (cleanChanged (bool)), this, SLOT (modificationStateChanged (bool)));
connect (&mTools, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mTools, SIGNAL (done (int)), this, SLOT (operationDone (int)));
connect (&mTools, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (&mSaving, SIGNAL (progress (int, int, int)), this, SLOT (progress (int, int, int)));
connect (&mSaving, SIGNAL (done (int)), this, SLOT (operationDone (int)));
connect (&mSaving, SIGNAL (done (int, bool)), this, SLOT (operationDone (int, bool)));
connect (
&mSaving, SIGNAL (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)),
this, SLOT (reportMessage (const CSMWorld::UniversalId&, const std::string&, int)));
connect (&mRunner, SIGNAL (runStateChanged()), this, SLOT (runStateChanged()));
}
CSMDoc::Document::~Document()
@ -2275,6 +2284,9 @@ int CSMDoc::Document::getState() const
if (mSaving.isRunning())
state |= State_Locked | State_Saving | State_Operation;
if (mRunner.isRunning())
state |= State_Locked | State_Running;
if (int operations = mTools.getRunningOperations())
state |= State_Locked | State_Operation | operations;
@ -2339,7 +2351,7 @@ void CSMDoc::Document::reportMessage (const CSMWorld::UniversalId& id, const std
std::cout << message << std::endl;
}
void CSMDoc::Document::operationDone (int type)
void CSMDoc::Document::operationDone (int type, bool failed)
{
emit stateChanged (getState(), this);
}
@ -2359,6 +2371,55 @@ CSMTools::ReportModel *CSMDoc::Document::getReport (const CSMWorld::UniversalId&
return mTools.getReport (id);
}
bool CSMDoc::Document::isBlacklisted (const CSMWorld::UniversalId& id)
const
{
return mBlacklist.isBlacklisted (id);
}
void CSMDoc::Document::startRunning (const std::string& profile,
const std::string& startupInstruction)
{
std::vector<std::string> contentFiles;
for (std::vector<boost::filesystem::path>::const_iterator iter (mContentFiles.begin());
iter!=mContentFiles.end(); ++iter)
contentFiles.push_back (iter->filename().string());
mRunner.configure (getData().getDebugProfiles().getRecord (profile).get(), contentFiles,
startupInstruction);
int state = getState();
if (state & State_Modified)
{
// need to save first
mRunner.start (true);
new SaveWatcher (&mRunner, &mSaving); // no, that is not a memory leak. Qt is weird.
if (!(state & State_Saving))
save();
}
else
mRunner.start();
}
void CSMDoc::Document::stopRunning()
{
mRunner.stop();
}
QTextDocument *CSMDoc::Document::getRunLog()
{
return mRunner.getLog();
}
void CSMDoc::Document::runStateChanged()
{
emit stateChanged (getState(), this);
}
void CSMDoc::Document::progress (int current, int max, int type)
{
emit progress (current, max, type, 1, this);

@ -17,6 +17,8 @@
#include "state.hpp"
#include "saving.hpp"
#include "blacklist.hpp"
#include "runner.hpp"
class QAbstractItemModel;
@ -52,6 +54,8 @@ namespace CSMDoc
boost::filesystem::path mProjectPath;
Saving mSaving;
boost::filesystem::path mResDir;
Blacklist mBlacklist;
Runner mRunner;
// It is important that the undo stack is declared last, because on desctruction it fires a signal, that is connected to a slot, that is
// using other member variables. Unfortunately this connection is cut only in the QObject destructor, which is way too late.
@ -78,7 +82,8 @@ namespace CSMDoc
Document (const Files::ConfigurationManager& configuration,
const std::vector< boost::filesystem::path >& files, bool new_,
const boost::filesystem::path& savePath, const boost::filesystem::path& resDir,
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager);
ToUTF8::FromType encoding, const CSMWorld::ResourcesManager& resourcesManager,
const std::vector<std::string>& blacklistedScripts);
~Document();
@ -110,6 +115,15 @@ namespace CSMDoc
CSMTools::ReportModel *getReport (const CSMWorld::UniversalId& id);
///< The ownership of the returned report is not transferred.
bool isBlacklisted (const CSMWorld::UniversalId& id) const;
void startRunning (const std::string& profile,
const std::string& startupInstruction = "");
void stopRunning();
QTextDocument *getRunLog();
signals:
void stateChanged (int state, CSMDoc::Document *document);
@ -123,7 +137,9 @@ namespace CSMDoc
void reportMessage (const CSMWorld::UniversalId& id, const std::string& message,
int type);
void operationDone (int type);
void operationDone (int type, bool failed);
void runStateChanged();
public slots:

@ -52,7 +52,7 @@ CSMDoc::DocumentManager::~DocumentManager()
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);
Document *document = new Document (mConfiguration, files, new_, savePath, mResDir, mEncoding, mResourcesManager, mBlacklistedScripts);
mDocuments.push_back (document);
@ -85,6 +85,11 @@ void CSMDoc::DocumentManager::setEncoding (ToUTF8::FromType encoding)
mEncoding = encoding;
}
void CSMDoc::DocumentManager::setBlacklistedScripts (const std::vector<std::string>& scriptIds)
{
mBlacklistedScripts = scriptIds;
}
void CSMDoc::DocumentManager::listResources()
{
mResourcesManager.listResources();

@ -34,6 +34,7 @@ namespace CSMDoc
Loader mLoader;
ToUTF8::FromType mEncoding;
CSMWorld::ResourcesManager mResourcesManager;
std::vector<std::string> mBlacklistedScripts;
DocumentManager (const DocumentManager&);
DocumentManager& operator= (const DocumentManager&);
@ -53,6 +54,8 @@ namespace CSMDoc
void setEncoding (ToUTF8::FromType encoding);
void setBlacklistedScripts (const std::vector<std::string>& scriptIds);
/// Ask OGRE for a list of available resources.
void listResources();

@ -119,5 +119,5 @@ void CSMDoc::Operation::executeStage()
void CSMDoc::Operation::operationDone()
{
emit done (mType);
emit done (mType, mError);
}

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

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

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

@ -17,7 +17,14 @@ CSMDoc::Saving::Saving (Document& document, const boost::filesystem::path& proje
appendStage (new WriteHeaderStage (mDocument, mState, true));
appendStage (new WriteFilterStage (mDocument, mState, CSMFilter::Filter::Scope_Project));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Filter> > (
mDocument.getData().getFilters(), mState, CSMWorld::Scope_Project));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::DebugProfile> > (
mDocument.getData().getDebugProfiles(), mState, CSMWorld::Scope_Project));
appendStage (new WriteCollectionStage<CSMWorld::IdCollection<ESM::Script> > (
mDocument.getData().getScripts(), mState, CSMWorld::Scope_Project));
appendStage (new CloseSaveStage (mState));

@ -201,23 +201,6 @@ void CSMDoc::WriteRefIdCollectionStage::perform (int stage, Messages& messages)
}
CSMDoc::WriteFilterStage::WriteFilterStage (Document& document, SavingState& state,
CSMFilter::Filter::Scope scope)
: WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> > (document.getData().getFilters(),
state),
mDocument (document), mScope (scope)
{}
void CSMDoc::WriteFilterStage::perform (int stage, Messages& messages)
{
const CSMWorld::Record<CSMFilter::Filter>& record =
mDocument.getData().getFilters().getRecord (stage);
if (record.get().mScope==mScope)
WriteCollectionStage<CSMWorld::IdCollection<CSMFilter::Filter> >::perform (stage, messages);
}
CSMDoc::CollectionReferencesStage::CollectionReferencesStage (Document& document,
SavingState& state)
: mDocument (document), mState (state)
@ -301,20 +284,6 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
// write references
if (references!=mState.getSubRecords().end())
{
// first pass: find highest RefNum
int lastRefNum = -1;
for (std::vector<int>::const_iterator iter (references->second.begin());
iter!=references->second.end(); ++iter)
{
const CSMWorld::Record<CSMWorld::CellRef>& ref =
mDocument.getData().getReferences().getRecord (*iter);
if (ref.get().mRefNum.mContentFile==0 && ref.get().mRefNum.mIndex>lastRefNum)
lastRefNum = ref.get().mRefNum.mIndex;
}
// second pass: write
for (std::vector<int>::const_iterator iter (references->second.begin());
iter!=references->second.end(); ++iter)
{
@ -324,20 +293,7 @@ void CSMDoc::WriteCellCollectionStage::perform (int stage, Messages& messages)
if (ref.mState==CSMWorld::RecordBase::State_Modified ||
ref.mState==CSMWorld::RecordBase::State_ModifiedOnly)
{
if (ref.get().mRefNum.mContentFile==-2)
{
if (lastRefNum>=0xffffff)
throw std::runtime_error (
"RefNums exhausted in cell: " + cell.get().mId);
ESM::CellRef ref2 = ref.get();
ref2.mRefNum.mContentFile = 0;
ref2.mRefNum.mIndex = ++lastRefNum;
ref2.save (mState.getWriter());
}
else
ref.get().save (mState.getWriter());
ref.get().save (mState.getWriter());
}
else if (ref.mState==CSMWorld::RecordBase::State_Deleted)
{

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

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

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

@ -596,7 +596,7 @@ bool CSMFilter::Parser::parse (const std::string& filter, bool allowPredefined)
return false;
}
const CSMWorld::Record<CSMFilter::Filter>& record = mData.getFilters().getRecord (index);
const CSMWorld::Record<ESM::Filter>& record = mData.getFilters().getRecord (index);
if (record.isDeleted())
{

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

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

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

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

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

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

@ -68,6 +68,7 @@ namespace CSMWorld
Display_TopicInfo,
Display_JournalInfo,
Display_Scene,
Display_GlobalVariable,
//CONCRETE TYPES ENDS HERE
Display_Integer,
@ -99,7 +100,8 @@ namespace CSMWorld
Display_SoundRes,
Display_Texture,
Display_Video,
Display_Colour
Display_Colour,
Display_ScriptLines // console context
};
int mColumnId;

@ -500,6 +500,47 @@ namespace CSMWorld
}
};
template<typename ESXRecordT>
struct FlagColumn2 : public Column<ESXRecordT>
{
int mMask;
bool mInverted;
FlagColumn2 (int columnId, int mask, bool inverted = false)
: Column<ESXRecordT> (columnId, ColumnBase::Display_Boolean), mMask (mask),
mInverted (inverted)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
bool flag = (record.get().mFlags & mMask)!=0;
if (mInverted)
flag = !flag;
return flag;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
int flags = record2.mFlags & ~mMask;
if ((data.toInt()!=0)!=mInverted)
flags |= mMask;
record2.mFlags = flags;
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct WeightHeightColumn : public Column<ESXRecordT>
{
@ -766,8 +807,18 @@ namespace CSMWorld
template<typename ESXRecordT>
struct ScriptColumn : public Column<ESXRecordT>
{
ScriptColumn()
: Column<ESXRecordT> (Columns::ColumnId_ScriptText, ColumnBase::Display_Script, 0) {}
enum Type
{
Type_File, // regular script record
Type_Lines, // console context
Type_Info // dialogue context (not implemented yet)
};
ScriptColumn (Type type)
: Column<ESXRecordT> (Columns::ColumnId_ScriptText,
type==Type_File ? ColumnBase::Display_Script : ColumnBase::Display_ScriptLines,
type==Type_File ? 0 : ColumnBase::Flag_Dialogue)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
@ -977,13 +1028,13 @@ namespace CSMWorld
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mFactIndex;
return record.get().mFactionRank;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mFactIndex = data.toInt();
record2.mFactionRank = data.toInt();
record.setModified (record2);
}
@ -1224,36 +1275,6 @@ namespace CSMWorld
}
};
template<typename ESXRecordT>
struct ScopeColumn : public Column<ESXRecordT>
{
ScopeColumn()
: Column<ESXRecordT> (Columns::ColumnId_Scope, ColumnBase::Display_Integer, 0)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mScope);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mScope = static_cast<CSMFilter::Filter::Scope> (data.toInt());
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct PosColumn : public Column<ESXRecordT>
@ -1870,6 +1891,97 @@ namespace CSMWorld
return true;
}
};
template<typename ESXRecordT>
struct OwnerGlobalColumn : public Column<ESXRecordT>
{
OwnerGlobalColumn()
: Column<ESXRecordT> (Columns::ColumnId_OwnerGlobal, ColumnBase::Display_GlobalVariable)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return QString::fromUtf8 (record.get().mGlobalVariable.c_str());
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mGlobalVariable = data.toString().toUtf8().constData();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct RefNumCounterColumn : public Column<ESXRecordT>
{
RefNumCounterColumn()
: Column<ESXRecordT> (Columns::ColumnId_RefNumCounter, ColumnBase::Display_Integer, 0)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mRefNumCounter);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mRefNumCounter = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
template<typename ESXRecordT>
struct RefNumColumn : public Column<ESXRecordT>
{
RefNumColumn()
: Column<ESXRecordT> (Columns::ColumnId_RefNum, ColumnBase::Display_Integer, 0)
{}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return static_cast<int> (record.get().mRefNum.mIndex);
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mRefNum.mIndex = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
virtual bool isUserEditable() const
{
return false;
}
};
}
#endif

@ -172,7 +172,6 @@ namespace CSMWorld
{ ColumnId_Rank, "Rank" },
{ ColumnId_Gender, "Gender" },
{ ColumnId_PcRank, "PC Rank" },
{ ColumnId_Scope, "Scope" },
{ ColumnId_ReferenceableId, "Referenceable ID" },
{ ColumnId_CombatState, "Combat" },
{ ColumnId_MagicState, "Magic" },
@ -181,6 +180,12 @@ namespace CSMWorld
{ ColumnId_Vampire, "Vampire" },
{ ColumnId_BodyPartType, "Bodypart Type" },
{ ColumnId_MeshType, "Mesh Type" },
{ ColumnId_OwnerGlobal, "Owner Global" },
{ ColumnId_DefaultProfile, "Default Profile" },
{ ColumnId_BypassNewGame, "Bypass New Game" },
{ ColumnId_GlobalProfile, "Global Profile" },
{ ColumnId_RefNumCounter, "RefNum Counter" },
{ ColumnId_RefNum, "RefNum" },
{ ColumnId_UseValue1, "Use value 1" },
{ ColumnId_UseValue2, "Use value 2" },

@ -165,7 +165,6 @@ namespace CSMWorld
ColumnId_Rank = 152,
ColumnId_Gender = 153,
ColumnId_PcRank = 154,
ColumnId_Scope = 155,
ColumnId_ReferenceableId = 156,
ColumnId_CombatState = 157,
ColumnId_MagicState = 158,
@ -174,6 +173,12 @@ namespace CSMWorld
ColumnId_Vampire = 161,
ColumnId_BodyPartType = 162,
ColumnId_MeshType = 163,
ColumnId_OwnerGlobal = 164,
ColumnId_DefaultProfile = 165,
ColumnId_BypassNewGame = 166,
ColumnId_GlobalProfile = 167,
ColumnId_RefNumCounter = 168,
ColumnId_RefNum = 169,
// Allocated to a separate value range, so we don't get a collision should we ever need
// to extend the number of use values.

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

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

@ -131,7 +131,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mScripts.addColumn (new StringIdColumn<ESM::Script>);
mScripts.addColumn (new RecordStateColumn<ESM::Script>);
mScripts.addColumn (new FixedRecordTypeColumn<ESM::Script> (UniversalId::Type_Script));
mScripts.addColumn (new ScriptColumn<ESM::Script>);
mScripts.addColumn (new ScriptColumn<ESM::Script> (ScriptColumn<ESM::Script>::Type_File));
mRegions.addColumn (new StringIdColumn<ESM::Region>);
mRegions.addColumn (new RecordStateColumn<ESM::Region>);
@ -186,7 +186,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mJournalInfos.addColumn (new StringIdColumn<Info> (true));
mJournalInfos.addColumn (new RecordStateColumn<Info>);
mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_Journal));
mJournalInfos.addColumn (new FixedRecordTypeColumn<Info> (UniversalId::Type_JournalInfo));
mJournalInfos.addColumn (new TopicColumn<Info> (true));
mJournalInfos.addColumn (new QuestStatusTypeColumn<Info>);
mJournalInfos.addColumn (new QuestIndexColumn<Info>);
@ -200,6 +200,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorWater, ESM::Cell::HasWater));
mCells.addColumn (new FlagColumn<Cell> (Columns::ColumnId_InteriorSky, ESM::Cell::QuasiEx));
mCells.addColumn (new RegionColumn<Cell>);
mCells.addColumn (new RefNumCounterColumn<Cell>);
mEnchantments.addColumn (new StringIdColumn<ESM::Enchantment>);
mEnchantments.addColumn (new RecordStateColumn<ESM::Enchantment>);
@ -250,13 +251,27 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
mRefs.addColumn (new LockLevelColumn<CellRef>);
mRefs.addColumn (new KeyColumn<CellRef>);
mRefs.addColumn (new TrapColumn<CellRef>);
mFilters.addColumn (new StringIdColumn<CSMFilter::Filter>);
mFilters.addColumn (new RecordStateColumn<CSMFilter::Filter>);
mFilters.addColumn (new FixedRecordTypeColumn<CSMFilter::Filter> (UniversalId::Type_Filter));
mFilters.addColumn (new FilterColumn<CSMFilter::Filter>);
mFilters.addColumn (new DescriptionColumn<CSMFilter::Filter>);
mFilters.addColumn (new ScopeColumn<CSMFilter::Filter>);
mRefs.addColumn (new OwnerGlobalColumn<CellRef>);
mRefs.addColumn (new RefNumColumn<CellRef>);
mFilters.addColumn (new StringIdColumn<ESM::Filter>);
mFilters.addColumn (new RecordStateColumn<ESM::Filter>);
mFilters.addColumn (new FixedRecordTypeColumn<ESM::Filter> (UniversalId::Type_Filter));
mFilters.addColumn (new FilterColumn<ESM::Filter>);
mFilters.addColumn (new DescriptionColumn<ESM::Filter>);
mDebugProfiles.addColumn (new StringIdColumn<ESM::DebugProfile>);
mDebugProfiles.addColumn (new RecordStateColumn<ESM::DebugProfile>);
mDebugProfiles.addColumn (new FixedRecordTypeColumn<ESM::DebugProfile> (UniversalId::Type_DebugProfile));
mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
Columns::ColumnId_DefaultProfile, ESM::DebugProfile::Flag_Default));
mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
Columns::ColumnId_BypassNewGame, ESM::DebugProfile::Flag_BypassNewGame));
mDebugProfiles.addColumn (new FlagColumn2<ESM::DebugProfile> (
Columns::ColumnId_GlobalProfile, ESM::DebugProfile::Flag_Global));
mDebugProfiles.addColumn (new DescriptionColumn<ESM::DebugProfile>);
mDebugProfiles.addColumn (new ScriptColumn<ESM::DebugProfile> (
ScriptColumn<ESM::DebugProfile>::Type_Lines));
addModel (new IdTable (&mGlobals), UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmst);
@ -280,17 +295,18 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, const ResourcesManager& resourc
UniversalId::Type_Referenceable);
addModel (new IdTable (&mRefs, IdTable::Feature_ViewCell | IdTable::Feature_Preview), UniversalId::Type_Reference);
addModel (new IdTable (&mFilters), UniversalId::Type_Filter);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Mesh)),
addModel (new IdTable (&mDebugProfiles), UniversalId::Type_DebugProfile);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Meshes)),
UniversalId::Type_Mesh);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Icon)),
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Icons)),
UniversalId::Type_Icon);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Music)),
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Musics)),
UniversalId::Type_Music);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_SoundRes)),
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_SoundsRes)),
UniversalId::Type_SoundRes);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Texture)),
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Textures)),
UniversalId::Type_Texture);
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Video)),
addModel (new ResourceTable (&mResourcesManager.get (UniversalId::Type_Videos)),
UniversalId::Type_Video);
}
@ -483,12 +499,12 @@ CSMWorld::RefCollection& CSMWorld::Data::getReferences()
return mRefs;
}
const CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters() const
const CSMWorld::IdCollection<ESM::Filter>& CSMWorld::Data::getFilters() const
{
return mFilters;
}
CSMWorld::IdCollection<CSMFilter::Filter>& CSMWorld::Data::getFilters()
CSMWorld::IdCollection<ESM::Filter>& CSMWorld::Data::getFilters()
{
return mFilters;
}
@ -513,9 +529,19 @@ CSMWorld::IdCollection<ESM::BodyPart>& CSMWorld::Data::getBodyParts()
return mBodyParts;
}
const CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles() const
{
return mDebugProfiles;
}
CSMWorld::IdCollection<ESM::DebugProfile>& CSMWorld::Data::getDebugProfiles()
{
return mDebugProfiles;
}
const CSMWorld::Resources& CSMWorld::Data::getResources (const UniversalId& id) const
{
return mResourcesManager.get (UniversalId::getParentType (id.getType()));
return mResourcesManager.get (id.getType());
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const CSMWorld::UniversalId& id)
@ -582,6 +608,8 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
ESM::NAME n = mReader->getRecName();
mReader->getRecHeader();
bool unhandledRecord = false;
switch (n.val)
{
case ESM::REC_GLOB: mGlobals.load (*mReader, mBase); break;
@ -692,23 +720,37 @@ bool CSMWorld::Data::continueLoading (CSMDoc::Stage::Messages& messages)
case ESM::REC_FILT:
if (mProject)
if (!mProject)
{
mFilters.load (*mReader, mBase);
mFilters.setData (mFilters.getSize()-1,
mFilters.findColumnIndex (CSMWorld::Columns::ColumnId_Scope),
static_cast<int> (CSMFilter::Filter::Scope_Project));
unhandledRecord = true;
break;
}
// fall through (filter record in a content file is an error with format 0)
mFilters.load (*mReader, mBase);
break;
case ESM::REC_DBGP:
if (!mProject)
{
unhandledRecord = true;
break;
}
mDebugProfiles.load (*mReader, mBase);
break;
default:
messages.push_back (std::make_pair (UniversalId::Type_None,
"Unsupported record type: " + n.toString()));
unhandledRecord = true;
}
if (unhandledRecord)
{
messages.push_back (std::make_pair (UniversalId::Type_None,
"Unsupported record type: " + n.toString()));
mReader->skipRecord();
mReader->skipRecord();
}
return false;

@ -23,11 +23,11 @@
#include <components/esm/loaddial.hpp>
#include <components/esm/loadench.hpp>
#include <components/esm/loadbody.hpp>
#include <components/esm/debugprofile.hpp>
#include <components/esm/filter.hpp>
#include <components/to_utf8/to_utf8.hpp>
#include "../filter/filter.hpp"
#include "../doc/stage.hpp"
#include "idcollection.hpp"
@ -70,12 +70,13 @@ namespace CSMWorld
IdCollection<ESM::Dialogue> mJournals;
IdCollection<ESM::Enchantment> mEnchantments;
IdCollection<ESM::BodyPart> mBodyParts;
IdCollection<ESM::DebugProfile> mDebugProfiles;
InfoCollection mTopicInfos;
InfoCollection mJournalInfos;
IdCollection<Cell> mCells;
RefIdCollection mReferenceables;
RefCollection mRefs;
IdCollection<CSMFilter::Filter> mFilters;
IdCollection<ESM::Filter> mFilters;
const ResourcesManager& mResourcesManager;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
@ -178,9 +179,9 @@ namespace CSMWorld
RefCollection& getReferences();
const IdCollection<CSMFilter::Filter>& getFilters() const;
const IdCollection<ESM::Filter>& getFilters() const;
IdCollection<CSMFilter::Filter>& getFilters();
IdCollection<ESM::Filter>& getFilters();
const IdCollection<ESM::Enchantment>& getEnchantments() const;
@ -190,6 +191,10 @@ namespace CSMWorld
IdCollection<ESM::BodyPart>& getBodyParts();
const IdCollection<ESM::DebugProfile>& getDebugProfiles() const;
IdCollection<ESM::DebugProfile>& getDebugProfiles();
/// Throws an exception, if \a id does not match a resources list.
const Resources& getResources (const UniversalId& id) const;

@ -4,7 +4,5 @@
CSMWorld::CellRef::CellRef()
{
mRefNum.mIndex = 0;
// special marker: This reference does not have a RefNum assign to it yet.
mRefNum.mContentFile = -2;
mRefNum.mContentFile = 0;
}

@ -12,12 +12,12 @@ void CSMWorld::ResourcesManager::listResources()
{
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 ("meshes", UniversalId::Type_Meshes, sMeshTypes));
addResources (Resources ("icons", UniversalId::Type_Icons));
addResources (Resources ("music", UniversalId::Type_Musics));
addResources (Resources ("sound", UniversalId::Type_SoundsRes));
addResources (Resources ("textures", UniversalId::Type_Textures));
addResources (Resources ("videos", UniversalId::Type_Videos));
}
const CSMWorld::Resources& CSMWorld::ResourcesManager::get (UniversalId::Type type) const

@ -50,7 +50,7 @@ QVariant CSMWorld::ResourceTable::headerData (int section, Qt::Orientation orien
return QVariant();
if (role==ColumnBase::Role_Flags)
return ColumnBase::Flag_Table;
return section==0 ? ColumnBase::Flag_Table : 0;
switch (section)
{
@ -86,7 +86,7 @@ bool CSMWorld::ResourceTable::setData ( const QModelIndex &index, const QVariant
Qt::ItemFlags CSMWorld::ResourceTable::flags (const QModelIndex & index) const
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;;
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
QModelIndex CSMWorld::ResourceTable::index (int row, int column, const QModelIndex& parent)

@ -0,0 +1,25 @@
#include "scope.hpp"
#include <stdexcept>
#include <components/misc/stringops.hpp>
CSMWorld::Scope CSMWorld::getScopeFromId (const std::string& id)
{
// get root namespace
std::string namespace_;
std::string::size_type i = id.find ("::");
if (i!=std::string::npos)
namespace_ = Misc::StringUtils::lowerCase (id.substr (0, i));
if (namespace_=="project")
return Scope_Project;
if (namespace_=="session")
return Scope_Session;
return Scope_Content;
}

@ -0,0 +1,23 @@
#ifndef CSM_WOLRD_SCOPE_H
#define CSM_WOLRD_SCOPE_H
#include <string>
namespace CSMWorld
{
enum Scope
{
// record stored in content file
Scope_Content = 1,
// record stored in project file
Scope_Project = 2,
// record that exists only for the duration of one editing session
Scope_Session = 4
};
Scope getScopeFromId (const std::string& id);
}
#endif

@ -91,7 +91,7 @@ return ( type == CSMWorld::ColumnBase::Display_Activator
|| type == CSMWorld::ColumnBase::Display_Static
|| type == CSMWorld::ColumnBase::Display_Weapon);
}
bool CSMWorld::TableMimeData::isReferencable(CSMWorld::UniversalId::Type type) const
bool CSMWorld::TableMimeData::isReferencable(CSMWorld::UniversalId::Type type)
{
return ( type == CSMWorld::UniversalId::Type_Activator
|| type == CSMWorld::UniversalId::Type_Potion
@ -222,7 +222,6 @@ namespace
{ CSMWorld::UniversalId::Type_Race, CSMWorld::ColumnBase::Display_Race },
{ CSMWorld::UniversalId::Type_Skill, CSMWorld::ColumnBase::Display_Skill },
{ CSMWorld::UniversalId::Type_Class, CSMWorld::ColumnBase::Display_Class },
{ CSMWorld::UniversalId::Type_Class, CSMWorld::ColumnBase::Display_Class },
{ CSMWorld::UniversalId::Type_Faction, CSMWorld::ColumnBase::Display_Faction },
{ CSMWorld::UniversalId::Type_Sound, CSMWorld::ColumnBase::Display_Sound },
{ CSMWorld::UniversalId::Type_Region, CSMWorld::ColumnBase::Display_Region },
@ -264,6 +263,7 @@ namespace
{ CSMWorld::UniversalId::Type_SoundRes, CSMWorld::ColumnBase::Display_SoundRes },
{ 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_None, CSMWorld::ColumnBase::Display_None } // end marker
};

@ -59,10 +59,10 @@ namespace CSMWorld
static CSMWorld::ColumnBase::Display convertEnums(CSMWorld::UniversalId::Type type);
static bool isReferencable(CSMWorld::UniversalId::Type type);
private:
bool isReferencable(CSMWorld::UniversalId::Type type) const;
bool isReferencable(CSMWorld::ColumnBase::Display type) const;
};
}
#endif // TABLEMIMEDATA_H
#endif // TABLEMIMEDATA_H

@ -46,10 +46,12 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Filters, "Filters", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Meshes, "Meshes", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Icons, "Icons", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Musics", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Musics, "Music Files", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_SoundsRes, "Sound Files", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Textures, "Textures", 0 },
{ CSMWorld::UniversalId::Class_ResourceList, CSMWorld::UniversalId::Type_Videos, "Videos", 0 },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_DebugProfiles, "Debug Profiles", 0 },
{ CSMWorld::UniversalId::Class_Transient, CSMWorld::UniversalId::Type_RunLog, "Run Log", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};
@ -109,6 +111,7 @@ namespace
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_SoundRes, "Sound File", 0 },
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Texture, "Texture", 0 },
{ CSMWorld::UniversalId::Class_Resource, CSMWorld::UniversalId::Type_Video, "Video", 0 },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_DebugProfile, "Debug Profile", 0 },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0, 0 } // end marker
};

@ -119,10 +119,13 @@ namespace CSMWorld
Type_Textures,
Type_Texture,
Type_Videos,
Type_Video
Type_Video,
Type_DebugProfiles,
Type_DebugProfile,
Type_RunLog
};
enum { NumberOfTypes = Type_BodyPart+1 };
enum { NumberOfTypes = Type_DebugProfile+1 };
private:

@ -18,7 +18,7 @@
#include "adjusterwidget.hpp"
CSVDoc::FileDialog::FileDialog(QWidget *parent) :
QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0)
QDialog(parent), mSelector (0), mFileWidget (0), mAdjusterWidget (0), mDialogBuilt(false)
{
ui.setupUi (this);
resize(400, 400);
@ -70,11 +70,15 @@ void CSVDoc::FileDialog::showDialog (ContentAction action)
mAdjusterWidget->setFilenameCheck (mAction == ContentAction_New);
//connections common to both dialog view flavors
connect (mSelector, SIGNAL (signalCurrentGamefileIndexChanged (int)),
this, SLOT (slotUpdateAcceptButton (int)));
if(!mDialogBuilt)
{
//connections common to both dialog view flavors
connect (mSelector, SIGNAL (signalCurrentGamefileIndexChanged (int)),
this, SLOT (slotUpdateAcceptButton (int)));
connect (ui.projectButtonBox, SIGNAL (rejected()), this, SLOT (slotRejected()));
connect (ui.projectButtonBox, SIGNAL (rejected()), this, SLOT (slotRejected()));
mDialogBuilt = true;
}
show();
raise();
@ -85,22 +89,26 @@ void CSVDoc::FileDialog::buildNewFileView()
{
setWindowTitle(tr("Create a new addon"));
QPushButton* createButton = ui.projectButtonBox->button (QDialogButtonBox::Ok);
createButton->setText ("Create");
createButton->setEnabled (false);
QPushButton* createButton = ui.projectButtonBox->button (QDialogButtonBox::Ok);
createButton->setText ("Create");
createButton->setEnabled (false);
mFileWidget = new FileWidget (this);
if(!mFileWidget)
{
mFileWidget = new FileWidget (this);
mFileWidget->setType (true);
mFileWidget->extensionLabelIsVisible(true);
mFileWidget->setType (true);
mFileWidget->extensionLabelIsVisible(true);
ui.projectGroupBoxLayout->insertWidget (0, mFileWidget);
connect (mFileWidget, SIGNAL (nameChanged (const QString&, bool)),
mAdjusterWidget, SLOT (setName (const QString&, bool)));
connect (mFileWidget, SIGNAL (nameChanged (const QString&, bool)),
mAdjusterWidget, SLOT (setName (const QString&, bool)));
connect (mFileWidget, SIGNAL (nameChanged(const QString &, bool)),
this, SLOT (slotUpdateAcceptButton(const QString &, bool)));
connect (mFileWidget, SIGNAL (nameChanged(const QString &, bool)),
this, SLOT (slotUpdateAcceptButton(const QString &, bool)));
}
ui.projectGroupBoxLayout->insertWidget (0, mFileWidget);
connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotNewFile()));
}
@ -109,13 +117,18 @@ void CSVDoc::FileDialog::buildOpenFileView()
{
setWindowTitle(tr("Open"));
ui.projectGroupBox->setTitle (QString(""));
ui.projectButtonBox->button(QDialogButtonBox::Ok)->setText ("Open");
if(mSelector->isGamefileSelected())
ui.projectButtonBox->button(QDialogButtonBox::Ok)->setEnabled (true);
else
ui.projectButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
ui.projectButtonBox->button(QDialogButtonBox::Ok)->setEnabled (false);
connect (mSelector, SIGNAL (signalAddonFileSelected (int)), this, SLOT (slotUpdateAcceptButton (int)));
connect (mSelector, SIGNAL (signalAddonFileUnselected (int)), this, SLOT (slotUpdateAcceptButton (int)));
connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile()));
if(!mDialogBuilt)
{
connect (mSelector, SIGNAL (signalAddonFileSelected (int)), this, SLOT (slotUpdateAcceptButton (int)));
connect (mSelector, SIGNAL (signalAddonFileUnselected (int)), this, SLOT (slotUpdateAcceptButton (int)));
}
connect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile()));
}
void CSVDoc::FileDialog::slotUpdateAcceptButton (int)
@ -156,12 +169,26 @@ QString CSVDoc::FileDialog::filename() const
void CSVDoc::FileDialog::slotRejected()
{
emit rejected();
disconnect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotNewFile()));
disconnect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile()));
if(mFileWidget)
{
delete mFileWidget;
mFileWidget = NULL;
}
close();
}
void CSVDoc::FileDialog::slotNewFile()
{
emit signalCreateNewFile (mAdjusterWidget->getPath());
if(mFileWidget)
{
delete mFileWidget;
mFileWidget = NULL;
}
disconnect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotNewFile()));
close();
}
void CSVDoc::FileDialog::slotOpenFile()
@ -171,4 +198,6 @@ void CSVDoc::FileDialog::slotOpenFile()
mAdjusterWidget->setName (file->filePath(), !file->isGameFile());
emit signalOpenFiles (mAdjusterWidget->getPath());
disconnect (ui.projectButtonBox, SIGNAL (accepted()), this, SLOT (slotOpenFile()));
close();
}

@ -37,6 +37,7 @@ namespace CSVDoc
ContentAction mAction;
FileWidget *mFileWidget;
AdjusterWidget *mAdjusterWidget;
bool mDialogBuilt;
public:

@ -17,7 +17,7 @@ CSVDoc::FileWidget::FileWidget (QWidget *parent) : QWidget (parent), mAddon (fal
QHBoxLayout *layout = new QHBoxLayout (this);
mInput = new QLineEdit (this);
mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9\\s]*$")));
mInput->setValidator (new QRegExpValidator(QRegExp("^[a-zA-Z0-9_-\\s]*$")));
layout->addWidget (mInput, 1);

@ -0,0 +1,93 @@
#include "globaldebugprofilemenu.hpp"
#include <vector>
#include <algorithm>
#include <QActionGroup>
#include "../../model/world/idtable.hpp"
#include "../../model/world/record.hpp"
void CSVDoc::GlobalDebugProfileMenu::rebuild()
{
clear();
delete mActions;
mActions = 0;
int idColumn = mDebugProfiles->findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int stateColumn = mDebugProfiles->findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
int globalColumn = mDebugProfiles->findColumnIndex (
CSMWorld::Columns::ColumnId_GlobalProfile);
int size = mDebugProfiles->rowCount();
std::vector<QString> ids;
for (int i=0; i<size; ++i)
{
int state = mDebugProfiles->data (mDebugProfiles->index (i, stateColumn)).toInt();
bool global = mDebugProfiles->data (mDebugProfiles->index (i, globalColumn)).toInt();
if (state!=CSMWorld::RecordBase::State_Deleted && global)
ids.push_back (
mDebugProfiles->data (mDebugProfiles->index (i, idColumn)).toString());
}
mActions = new QActionGroup (this);
connect (mActions, SIGNAL (triggered (QAction *)), this, SLOT (actionTriggered (QAction *)));
std::sort (ids.begin(), ids.end());
for (std::vector<QString>::const_iterator iter (ids.begin()); iter!=ids.end(); ++iter)
{
mActions->addAction (addAction (*iter));
}
}
CSVDoc::GlobalDebugProfileMenu::GlobalDebugProfileMenu (CSMWorld::IdTable *debugProfiles,
QWidget *parent)
: QMenu (parent), mDebugProfiles (debugProfiles), mActions (0)
{
rebuild();
connect (mDebugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (profileAboutToBeRemoved (const QModelIndex&, int, int)));
connect (mDebugProfiles, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (profileInserted (const QModelIndex&, int, int)));
connect (mDebugProfiles, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (profileChanged (const QModelIndex&, const QModelIndex&)));
}
void CSVDoc::GlobalDebugProfileMenu::updateActions (bool running)
{
if (mActions)
mActions->setEnabled (!running);
}
void CSVDoc::GlobalDebugProfileMenu::profileAboutToBeRemoved (const QModelIndex& parent,
int start, int end)
{
rebuild();
}
void CSVDoc::GlobalDebugProfileMenu::profileInserted (const QModelIndex& parent, int start,
int end)
{
rebuild();
}
void CSVDoc::GlobalDebugProfileMenu::profileChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
rebuild();
}
void CSVDoc::GlobalDebugProfileMenu::actionTriggered (QAction *action)
{
emit triggered (std::string (action->text().toUtf8().constData()));
}

@ -0,0 +1,49 @@
#ifndef CSV_DOC_GLOBALDEBUGPROFILEMENU_H
#define CSV_DOC_GLOBALDEBUGPROFILEMENU_H
#include <QMenu>
class QModelIndex;
class QActionGroup;
namespace CSMWorld
{
class IdTable;
}
namespace CSVDoc
{
class GlobalDebugProfileMenu : public QMenu
{
Q_OBJECT
CSMWorld::IdTable *mDebugProfiles;
QActionGroup *mActions;
private:
void rebuild();
public:
GlobalDebugProfileMenu (CSMWorld::IdTable *debugProfiles, QWidget *parent = 0);
void updateActions (bool running);
private slots:
void profileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
void profileInserted (const QModelIndex& parent, int start, int end);
void profileChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);
void actionTriggered (QAction *action);
signals:
void triggered (const std::string& profile);
};
}
#endif

@ -0,0 +1,20 @@
#include "runlogsubview.hpp"
#include <QTextEdit>
CSVDoc::RunLogSubView::RunLogSubView (const CSMWorld::UniversalId& id,
CSMDoc::Document& document)
: SubView (id)
{
QTextEdit *edit = new QTextEdit (this);
edit->setDocument (document.getRunLog());
edit->setReadOnly (true);
setWidget (edit);
}
void CSVDoc::RunLogSubView::setEditLock (bool locked)
{
// ignored since this SubView does not have editing
}

@ -0,0 +1,20 @@
#ifndef CSV_DOC_RUNLOGSUBVIEW_H
#define CSV_DOC_RUNLOGSUBVIEW_H
#include "subview.hpp"
namespace CSVDoc
{
class RunLogSubView : public SubView
{
Q_OBJECT
public:
RunLogSubView (const CSMWorld::UniversalId& id, CSMDoc::Document& document);
virtual void setEditLock (bool locked);
};
}
#endif

@ -5,6 +5,7 @@ CSVDoc::SubView::SubView (const CSMWorld::UniversalId& id) : mUniversalId (id)
/// \todo add a button to the title bar that clones this sub view
setWindowTitle (QString::fromUtf8 (mUniversalId.toString().c_str()));
setAttribute(Qt::WA_DeleteOnClose);
}
CSMWorld::UniversalId CSVDoc::SubView::getUniversalId() const

@ -12,6 +12,8 @@
#include "../../model/doc/document.hpp"
#include "../../model/settings/usersettings.hpp"
#include "../../model/world/idtable.hpp"
#include "../world/subviews.hpp"
#include "../tools/subviews.hpp"
@ -19,11 +21,19 @@
#include "viewmanager.hpp"
#include "operations.hpp"
#include "subview.hpp"
#include "globaldebugprofilemenu.hpp"
#include "runlogsubview.hpp"
#include "subviewfactoryimp.hpp"
void CSVDoc::View::closeEvent (QCloseEvent *event)
{
if (!mViewManager.closeRequest (this))
event->ignore();
else
{
// closeRequest() returns true if last document
mViewManager.removeDocAndView(mDocument);
}
}
void CSVDoc::View::setupFileMenu()
@ -232,6 +242,35 @@ void CSVDoc::View::setupAssetsMenu()
assets->addAction (videos);
}
void CSVDoc::View::setupDebugMenu()
{
QMenu *debug = menuBar()->addMenu (tr ("Debug"));
QAction *profiles = new QAction (tr ("Debug Profiles"), this);
connect (profiles, SIGNAL (triggered()), this, SLOT (addDebugProfilesSubView()));
debug->addAction (profiles);
debug->addSeparator();
mGlobalDebugProfileMenu = new GlobalDebugProfileMenu (
&dynamic_cast<CSMWorld::IdTable&> (*mDocument->getData().getTableModel (
CSMWorld::UniversalId::Type_DebugProfiles)), this);
connect (mGlobalDebugProfileMenu, SIGNAL (triggered (const std::string&)),
this, SLOT (run (const std::string&)));
QAction *runDebug = debug->addMenu (mGlobalDebugProfileMenu);
runDebug->setText (tr ("Run OpenMW"));
mStopDebug = new QAction (tr ("Shutdown OpenMW"), this);
connect (mStopDebug, SIGNAL (triggered()), this, SLOT (stop()));
debug->addAction (mStopDebug);
QAction *runLog = new QAction (tr ("Run Log"), this);
connect (runLog, SIGNAL (triggered()), this, SLOT (addRunLogSubView()));
debug->addAction (runLog);
}
void CSVDoc::View::setupUi()
{
setupFileMenu();
@ -241,6 +280,7 @@ void CSVDoc::View::setupUi()
setupMechanicsMenu();
setupCharacterMenu();
setupAssetsMenu();
setupDebugMenu();
}
void CSVDoc::View::updateTitle()
@ -261,6 +301,7 @@ void CSVDoc::View::updateTitle()
void CSVDoc::View::updateActions()
{
bool editing = !(mDocument->getState() & CSMDoc::State_Locked);
bool running = mDocument->getState() & CSMDoc::State_Running;
for (std::vector<QAction *>::iterator iter (mEditingActions.begin()); iter!=mEditingActions.end(); ++iter)
(*iter)->setEnabled (editing);
@ -268,8 +309,11 @@ void CSVDoc::View::updateActions()
mUndo->setEnabled (editing & mDocument->getUndoStack().canUndo());
mRedo->setEnabled (editing & mDocument->getUndoStack().canRedo());
mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving));
mSave->setEnabled (!(mDocument->getState() & CSMDoc::State_Saving) && !running);
mVerify->setEnabled (!(mDocument->getState() & CSMDoc::State_Verifying));
mGlobalDebugProfileMenu->updateActions (running);
mStopDebug->setEnabled (running);
}
CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews)
@ -295,9 +339,13 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to
setupUi();
updateActions();
CSVWorld::addSubViewFactories (mSubViewFactory);
CSVTools::addSubViewFactories (mSubViewFactory);
mSubViewFactory.add (CSMWorld::UniversalId::Type_RunLog, new SubViewFactory<RunLogSubView>);
connect (mOperations, SIGNAL (abortOperation (int)), this, SLOT (abortOperation (int)));
}
@ -543,6 +591,16 @@ void CSVDoc::View::addVideosSubView()
addSubView (CSMWorld::UniversalId::Type_Videos);
}
void CSVDoc::View::addDebugProfilesSubView()
{
addSubView (CSMWorld::UniversalId::Type_DebugProfiles);
}
void CSVDoc::View::addRunLogSubView()
{
addSubView (CSMWorld::UniversalId::Type_RunLog);
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);
@ -588,3 +646,13 @@ void CSVDoc::View::loadErrorLog()
{
addSubView (CSMWorld::UniversalId (CSMWorld::UniversalId::Type_LoadErrorLog, 0));
}
void CSVDoc::View::run (const std::string& profile, const std::string& startupInstruction)
{
mDocument->startRunning (profile, startupInstruction);
}
void CSVDoc::View::stop()
{
mDocument->stopRunning();
}

@ -25,6 +25,7 @@ namespace CSVDoc
{
class ViewManager;
class Operations;
class GlobalDebugProfileMenu;
class View : public QMainWindow
{
@ -39,10 +40,12 @@ namespace CSVDoc
QAction *mSave;
QAction *mVerify;
QAction *mShowStatusBar;
QAction *mStopDebug;
std::vector<QAction *> mEditingActions;
Operations *mOperations;
SubViewFactoryManager mSubViewFactory;
QMainWindow mSubViewWindow;
GlobalDebugProfileMenu *mGlobalDebugProfileMenu;
// not implemented
@ -67,6 +70,8 @@ namespace CSVDoc
void setupAssetsMenu();
void setupDebugMenu();
void setupUi();
void updateTitle();
@ -194,9 +199,17 @@ namespace CSVDoc
void addVideosSubView();
void addDebugProfilesSubView();
void addRunLogSubView();
void toggleShowStatusBar (bool show);
void loadErrorLog();
void run (const std::string& profile, const std::string& startupInstruction = "");
void stop();
};
}

@ -172,7 +172,7 @@ bool CSVDoc::ViewManager::closeRequest (View *view)
{
std::vector<View *>::iterator iter = std::find (mViews.begin(), mViews.end(), view);
bool continueWithClose = true;
bool continueWithClose = false;
if (iter!=mViews.end())
{
@ -192,6 +192,24 @@ bool CSVDoc::ViewManager::closeRequest (View *view)
return continueWithClose;
}
// NOTE: This method assumes that it is called only if the last document
void CSVDoc::ViewManager::removeDocAndView (CSMDoc::Document *document)
{
for (std::vector<View *>::iterator iter (mViews.begin()); iter!=mViews.end(); ++iter)
{
// the first match should also be the only match
if((*iter)->getDocument() == document)
{
mDocumentManager.removeDocument(document);
(*iter)->deleteLater();
mViews.erase (iter);
updateIndices();
return;
}
}
}
bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view)
{
bool result = true;
@ -210,13 +228,19 @@ bool CSVDoc::ViewManager::notifySaveOnClose (CSVDoc::View *view)
bool CSVDoc::ViewManager::showModifiedDocumentMessageBox (CSVDoc::View *view)
{
QMessageBox messageBox;
emit closeMessageBox();
QMessageBox messageBox(view);
CSMDoc::Document *document = view->getDocument();
messageBox.setWindowTitle (document->getSavePath().filename().string().c_str());
messageBox.setText ("The document has been modified.");
messageBox.setInformativeText ("Do you want to save your changes?");
messageBox.setStandardButtons (QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
messageBox.setDefaultButton (QMessageBox::Save);
messageBox.setWindowModality (Qt::NonModal);
messageBox.hide();
messageBox.show();
bool retVal = true;
@ -341,8 +365,40 @@ void CSVDoc::ViewManager::onExitWarningHandler (int state, CSMDoc::Document *doc
}
}
bool CSVDoc::ViewManager::removeDocument (CSVDoc::View *view)
{
if(!notifySaveOnClose(view))
return false;
else
{
// don't bother closing views or updating indicies, but remove from mViews
CSMDoc::Document * document = view->getDocument();
std::vector<View *> remainingViews;
std::vector<View *>::const_iterator iter = mViews.begin();
for (; iter!=mViews.end(); ++iter)
{
if(document == (*iter)->getDocument())
(*iter)->setVisible(false);
else
remainingViews.push_back(*iter);
}
mDocumentManager.removeDocument(document);
mViews = remainingViews;
}
return true;
}
void CSVDoc::ViewManager::exitApplication (CSVDoc::View *view)
{
if (notifySaveOnClose (view))
QApplication::instance()->exit();
if(!removeDocument(view)) // close the current document first
return;
while(!mViews.empty()) // attempt to close all other documents
{
mViews.back()->activateWindow();
mViews.back()->raise(); // raise the window to alert the user
if(!removeDocument(mViews.back()))
return;
}
// Editor exits (via a signal) when the last document is deleted
}

@ -41,6 +41,7 @@ namespace CSVDoc
bool notifySaveOnClose (View *view = 0);
bool showModifiedDocumentMessageBox (View *view);
bool showSaveInProgressMessageBox (View *view);
bool removeDocument(View *view);
public:
@ -55,6 +56,7 @@ namespace CSVDoc
///< Return number of views for \a document.
bool closeRequest (View *view);
void removeDocAndView (CSMDoc::Document *document);
signals:

@ -1,77 +0,0 @@
#include "filtercreator.hpp"
#include <QComboBox>
#include <QLabel>
#include "../../model/filter/filter.hpp"
#include "../../model/world/data.hpp"
#include "../../model/world/commands.hpp"
#include "../../model/world/columns.hpp"
#include "../../model/world/idtable.hpp"
std::string CSVFilter::FilterCreator::getNamespace() const
{
switch (mScope->currentIndex())
{
case CSMFilter::Filter::Scope_Project: return "project::";
case CSMFilter::Filter::Scope_Session: return "session::";
}
return "";
}
void CSVFilter::FilterCreator::update()
{
mNamespace->setText (QString::fromUtf8 (getNamespace().c_str()));
GenericCreator::update();
}
std::string CSVFilter::FilterCreator::getId() const
{
return getNamespace() + GenericCreator::getId();
}
void CSVFilter::FilterCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const
{
int index =
dynamic_cast<CSMWorld::IdTable&> (*getData().getTableModel (getCollectionId())).
findColumnIndex (CSMWorld::Columns::ColumnId_Scope);
command.addValue (index, mScope->currentIndex());
}
CSVFilter::FilterCreator::FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id)
: GenericCreator (data, undoStack, id)
{
mNamespace = new QLabel ("::", this);
insertAtBeginning (mNamespace, false);
mScope = new QComboBox (this);
mScope->addItem ("Project");
mScope->addItem ("Session");
/// \todo re-enable for OpenMW 1.1
// mScope->addItem ("Content");
connect (mScope, SIGNAL (currentIndexChanged (int)), this, SLOT (setScope (int)));
insertAtBeginning (mScope, false);
QLabel *label = new QLabel ("Scope", this);
insertAtBeginning (label, false);
mScope->setCurrentIndex (1);
}
void CSVFilter::FilterCreator::reset()
{
GenericCreator::reset();
}
void CSVFilter::FilterCreator::setScope (int index)
{
update();
}

@ -1,43 +0,0 @@
#ifndef CSV_FILTER_FILTERCREATOR_H
#define CSV_FILTER_FILTERCREATOR_H
class QComboBox;
class QLabel;
#include "../world/genericcreator.hpp"
namespace CSVFilter
{
class FilterCreator : public CSVWorld::GenericCreator
{
Q_OBJECT
QComboBox *mScope;
QLabel *mNamespace;
private:
std::string getNamespace() const;
protected:
void update();
virtual std::string getId() const;
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
public:
FilterCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id);
virtual void reset();
private slots:
void setScope (int index);
};
}
#endif

@ -13,7 +13,9 @@ CSVFilter::RecordFilterBox::RecordFilterBox (CSMWorld::Data& data, QWidget *pare
layout->setContentsMargins (0, 0, 0, 0);
layout->addWidget (new QLabel ("Record Filter", this));
QLabel *label = new QLabel("Record Filter", this);
label->setIndent(2);
layout->addWidget (label);
mEdit = new EditWidget (data, this);

@ -0,0 +1,23 @@
#ifndef CSV_RENDER_ELEMENTS_H
#define CSV_RENDER_ELEMENTS_H
namespace CSVRender
{
/// Visual elements in a scene
enum Elements
{
// elements that are part of the actual scene
Element_Reference = 0x1,
Element_Terrain = 0x2,
Element_Water = 0x4,
Element_Pathgrid = 0x8,
Element_Fog = 0x10,
// control elements
Element_CellMarker = 0x10000,
Element_CellArrow = 0x20000,
Element_CellBorder = 0x40000
};
}
#endif

@ -11,9 +11,14 @@ float CSVRender::Navigation::getFactor (bool mouse) const
return factor;
}
CSVRender::Navigation::Navigation()
: mFastModeFactor(1)
{
}
CSVRender::Navigation::~Navigation() {}
void CSVRender::Navigation::setFastModeFactor (float factor)
{
mFastModeFactor = factor;
}
}

@ -20,6 +20,7 @@ namespace CSVRender
public:
Navigation();
virtual ~Navigation();
void setFastModeFactor (float factor);

@ -9,6 +9,8 @@
#include "../../model/world/ref.hpp"
#include "../../model/world/refidcollection.hpp"
#include "elements.hpp"
void CSVRender::Object::clearSceneNode (Ogre::SceneNode *node)
{
for (Ogre::SceneNode::ObjectIterator iter = node->getAttachedObjectIterator();
@ -63,12 +65,14 @@ void CSVRender::Object::update()
{
Ogre::Entity* entity = mBase->getCreator()->createEntity (Ogre::SceneManager::PT_CUBE);
entity->setMaterialName("BaseWhite"); /// \todo adjust material according to error
entity->setVisibilityFlags (Element_Reference);
mBase->attachObject (entity);
}
else
{
mObject = NifOgre::Loader::createObjects (mBase, "Meshes\\" + model);
mObject->setVisibilityFlags (Element_Reference);
}
}

@ -19,6 +19,10 @@
#include "../../model/world/tablemimedata.hpp"
#include "../../model/world/idtable.hpp"
#include "../widget/scenetooltoggle.hpp"
#include "elements.hpp"
void CSVRender::PagedWorldspaceWidget::displayCellCoord(bool display)
{
mDisplayCellCoord = display;
@ -210,6 +214,20 @@ void CSVRender::PagedWorldspaceWidget::referenceAdded (const QModelIndex& parent
flagAsModified();
}
std::string CSVRender::PagedWorldspaceWidget::getStartupInstruction()
{
Ogre::Vector3 position = getCamera()->getPosition();
std::ostringstream stream;
stream
<< "player->position "
<< position.x << ", " << position.y << ", " << position.z
<< ", 0";
return stream.str();
}
CSVRender::PagedWorldspaceWidget::PagedWorldspaceWidget (QWidget* parent, CSMDoc::Document& document)
: WorldspaceWidget(document, parent), mDocument(document), mWorldspace("std::default"), mDisplayCellCoord(true)
{
@ -283,8 +301,15 @@ std::pair< int, int > CSVRender::PagedWorldspaceWidget::getCoordinatesFromId (co
return std::make_pair(x, y);
}
void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data)
bool CSVRender::PagedWorldspaceWidget::handleDrop (
const std::vector< CSMWorld::UniversalId >& data, DropType type)
{
if (WorldspaceWidget::handleDrop (data, type))
return true;
if (type!=Type_CellsExterior)
return false;
bool selectionChanged = false;
for (unsigned i = 0; i < data.size(); ++i)
{
@ -301,16 +326,23 @@ void CSVRender::PagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::
emit cellSelectionChanged(mSelection);
}
return true;
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const
CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const
{
dropRequirments requirements = WorldspaceWidget::getDropRequirements (type);
if (requirements!=ignored)
return requirements;
switch (type)
{
case cellsExterior:
case Type_CellsExterior:
return canHandle;
case cellsInterior:
case Type_CellsInterior:
return needUnpaged;
default:
@ -318,6 +350,31 @@ CSVRender::WorldspaceWidget::dropRequirments CSVRender::PagedWorldspaceWidget::g
}
}
unsigned int CSVRender::PagedWorldspaceWidget::getElementMask() const
{
return WorldspaceWidget::getElementMask() | mControlElements->getSelection();
}
CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibilitySelector (
CSVWidget::SceneToolbar *parent)
{
mControlElements = new CSVWidget::SceneToolToggle (parent,
"Controls & Guides Visibility", ":door.png");
mControlElements->addButton (":activator.png", Element_CellMarker, ":activator.png",
"Cell marker");
mControlElements->addButton (":armor.png", Element_CellArrow, ":armor.png", "Cell arrows");
mControlElements->addButton (":armor.png", Element_CellBorder, ":armor.png", "Cell border");
mControlElements->setSelection (0xffffffff);
connect (mControlElements, SIGNAL (selectionChanged()),
this, SLOT (elementSelectionChanged()));
return mControlElements;
}
void CSVRender::PagedWorldspaceWidget::cellDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{

@ -18,6 +18,7 @@ namespace CSVRender
CSMWorld::CellSelection mSelection;
std::map<CSMWorld::CellCoordinates, Cell *> mCells;
std::string mWorldspace;
CSVWidget::SceneToolToggle *mControlElements;
bool mDisplayCellCoord;
private:
@ -42,6 +43,8 @@ namespace CSVRender
virtual void referenceAdded (const QModelIndex& index, int start, int end);
virtual std::string getStartupInstruction();
public:
PagedWorldspaceWidget (QWidget *parent, CSMDoc::Document& document);
@ -57,9 +60,19 @@ namespace CSVRender
void displayCellCoord(bool display);
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
virtual dropRequirments getDropRequirements(dropType type) const;
/// \return Drop handled?
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type);
virtual dropRequirments getDropRequirements(DropType type) const;
/// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function.
virtual CSVWidget::SceneToolToggle *makeControlVisibilitySelector (
CSVWidget::SceneToolbar *parent);
virtual unsigned int getElementMask() const;
signals:

@ -64,19 +64,19 @@ namespace CSVRender
CSVWidget::SceneToolMode *tool = new CSVWidget::SceneToolMode (parent, "Lighting Mode");
/// \todo replace icons
tool->addButton (":door.png", "day",
tool->addButton (":scenetoolbar/day", "day",
"Day"
"<ul><li>Cell specific ambient in interiors</li>"
"<li>Low ambient in exteriors</li>"
"<li>Strong directional light source/lir>"
"<li>This mode closely resembles day time in-game</li></ul>");
tool->addButton (":GMST.png", "night",
tool->addButton (":scenetoolbar/night", "night",
"Night"
"<ul><li>Cell specific ambient in interiors</li>"
"<li>Low ambient in exteriors</li>"
"<li>Weak directional light source</li>"
"<li>This mode closely resembles night time in-game</li></ul>");
tool->addButton (":Info.png", "bright",
tool->addButton (":scenetoolbar/bright", "bright",
"Bright"
"<ul><li>Maximum ambient</li>"
"<li>Strong directional light source</li></ul>");
@ -126,7 +126,9 @@ namespace CSVRender
#endif
mWindow = Ogre::Root::getSingleton().createRenderWindow(windowTitle.str(), this->width(), this->height(), false, &params);
mWindow->addViewport(mCamera)->setBackgroundColour(Ogre::ColourValue(0.3,0.3,0.3,1));
mViewport = mWindow->addViewport (mCamera);
mViewport->setBackgroundColour (Ogre::ColourValue (0.3,0.3,0.3,1));
Ogre::Real aspectRatio = Ogre::Real(width()) / Ogre::Real(height());
mCamera->setAspectRatio(aspectRatio);
@ -141,6 +143,11 @@ namespace CSVRender
Ogre::Root::getSingleton().destroySceneManager (mSceneMgr);
}
void SceneWidget::setVisibilityMask (unsigned int mask)
{
mViewport->setVisibilityMask (mask);
}
void SceneWidget::setNavigation (Navigation *navigation)
{
if ((mNavigation = navigation))
@ -354,11 +361,6 @@ namespace CSVRender
}
}
int SceneWidget::getFastFactor() const
{
return mFast ? mFastFactor : 1;
}
void SceneWidget::setLighting (Lighting *lighting)
{
if (mLighting)

@ -14,6 +14,7 @@ namespace Ogre
class Camera;
class SceneManager;
class RenderWindow;
class Viewport;
}
namespace CSVWidget
@ -42,6 +43,8 @@ namespace CSVRender
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
/// is the responsibility of the calling function.
virtual void setVisibilityMask (unsigned int mask);
protected:
void setNavigation (Navigation *navigation);
@ -77,14 +80,13 @@ namespace CSVRender
void updateOgreWindow();
int getFastFactor() const;
void setLighting (Lighting *lighting);
///< \attention The ownership of \a lighting is not transferred to *this.
Ogre::Camera* mCamera;
Ogre::SceneManager* mSceneMgr;
Ogre::RenderWindow* mWindow;
Ogre::Viewport *mViewport;
Navigation *mNavigation;
Lighting *mLighting;

@ -1,7 +1,10 @@
#include "unpagedworldspacewidget.hpp"
#include <sstream>
#include <OgreColourValue.h>
#include <OgreCamera.h>
#include <QtGui/qevent.h>
@ -11,6 +14,10 @@
#include "../../model/world/idtable.hpp"
#include "../../model/world/tablemimedata.hpp"
#include "../widget/scenetooltoggle.hpp"
#include "elements.hpp"
void CSVRender::UnpagedWorldspaceWidget::update()
{
const CSMWorld::Record<CSMWorld::Cell>& record =
@ -25,6 +32,14 @@ void CSVRender::UnpagedWorldspaceWidget::update()
flagAsModified();
}
void CSVRender::UnpagedWorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle *tool)
{
WorldspaceWidget::addVisibilitySelectorButtons (tool);
tool->addButton (":armor.png", Element_Fog, ":armor.png", "Fog");
}
CSVRender::UnpagedWorldspaceWidget::UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document, QWidget* parent)
: WorldspaceWidget (document, parent), mCellId (cellId)
{
@ -74,13 +89,21 @@ void CSVRender::UnpagedWorldspaceWidget::cellRowsAboutToBeRemoved (const QModelI
emit closeRequest();
}
void CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector< CSMWorld::UniversalId >& data)
bool CSVRender::UnpagedWorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& data, DropType type)
{
if (WorldspaceWidget::handleDrop (data, type))
return true;
if (type!=Type_CellsInterior)
return false;
mCellId = data.begin()->getId();
mCell.reset (new Cell (getDocument().getData(), getSceneManager(), mCellId));
update();
emit cellChanged(*data.begin());
/// \todo replace mCell
return true;
}
void CSVRender::UnpagedWorldspaceWidget::referenceableDataChanged (const QModelIndex& topLeft,
@ -137,14 +160,33 @@ void CSVRender::UnpagedWorldspaceWidget::referenceAdded (const QModelIndex& pare
flagAsModified();
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::dropType type) const
std::string CSVRender::UnpagedWorldspaceWidget::getStartupInstruction()
{
Ogre::Vector3 position = getCamera()->getPosition();
std::ostringstream stream;
stream
<< "player->positionCell "
<< position.x << ", " << position.y << ", " << position.z
<< ", 0, \"" << mCellId << "\"";
return stream.str();
}
CSVRender::WorldspaceWidget::dropRequirments CSVRender::UnpagedWorldspaceWidget::getDropRequirements (CSVRender::WorldspaceWidget::DropType type) const
{
dropRequirments requirements = WorldspaceWidget::getDropRequirements (type);
if (requirements!=ignored)
return requirements;
switch(type)
{
case cellsInterior:
case Type_CellsInterior:
return canHandle;
case cellsExterior:
case Type_CellsExterior:
return needPaged;
default:

@ -32,14 +32,20 @@ namespace CSVRender
void update();
protected:
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool);
public:
UnpagedWorldspaceWidget (const std::string& cellId, CSMDoc::Document& document,
QWidget *parent);
virtual dropRequirments getDropRequirements(dropType type) const;
virtual dropRequirments getDropRequirements(DropType type) const;
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data);
/// \return Drop handled?
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type);
private:
@ -56,6 +62,8 @@ namespace CSVRender
virtual void referenceAdded (const QModelIndex& index, int start, int end);
virtual std::string getStartupInstruction();
private slots:
void cellDataChanged (const QModelIndex& topLeft, const QModelIndex& bottomRight);

@ -1,6 +1,8 @@
#include "worldspacewidget.hpp"
#include <algorithm>
#include <OgreSceneNode.h>
#include <OgreSceneManager.h>
#include <OgreEntity.h>
@ -8,11 +10,16 @@
#include <QtGui/qevent.h>
#include "../../model/world/universalid.hpp"
#include "../../model/world/idtable.hpp"
#include "../widget/scenetoolmode.hpp"
#include "../widget/scenetooltoggle.hpp"
#include "../widget/scenetoolrun.hpp"
#include "elements.hpp"
CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidget* parent)
: SceneWidget (parent), mDocument(document)
: SceneWidget (parent), mDocument(document), mRun (0)
{
setAcceptDrops(true);
@ -35,6 +42,14 @@ CSVRender::WorldspaceWidget::WorldspaceWidget (CSMDoc::Document& document, QWidg
this, SLOT (referenceAboutToBeRemoved (const QModelIndex&, int, int)));
connect (references, SIGNAL (rowsInserted (const QModelIndex&, int, int)),
this, SLOT (referenceAdded (const QModelIndex&, int, int)));
QAbstractItemModel *debugProfiles =
document.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles);
connect (debugProfiles, SIGNAL (dataChanged (const QModelIndex&, const QModelIndex&)),
this, SLOT (debugProfileDataChanged (const QModelIndex&, const QModelIndex&)));
connect (debugProfiles, SIGNAL (rowsAboutToBeRemoved (const QModelIndex&, int, int)),
this, SLOT (debugProfileAboutToBeRemoved (const QModelIndex&, int, int)));
}
void CSVRender::WorldspaceWidget::selectNavigationMode (const std::string& mode)
@ -61,7 +76,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
/// \todo replace icons
/// \todo consider user-defined button-mapping
tool->addButton (":door.png", "1st",
tool->addButton (":scenetoolbar/1st-person", "1st",
"First Person"
"<ul><li>Mouse-Look while holding the left button</li>"
"<li>WASD movement keys</li>"
@ -70,7 +85,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
"<li>Camera is held upright</li>"
"<li>Hold shift to speed up movement</li>"
"</ul>");
tool->addButton (":GMST.png", "free",
tool->addButton (":scenetoolbar/free-camera", "free",
"Free Camera"
"<ul><li>Mouse-Look while holding the left button</li>"
"<li>Stafing (also vertically) via WASD or by holding the left mouse button and control</li>"
@ -78,7 +93,7 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
"<li>Roll camera with Q and E keys</li>"
"<li>Hold shift to speed up movement</li>"
"</ul>");
tool->addButton (":Info.png", "orbit",
tool->addButton (":scenetoolbar/orbiting-camera", "orbit",
"Orbiting Camera"
"<ul><li>Always facing the centre point</li>"
"<li>Rotate around the centre point via WASD or by moving the mouse while holding the left button</li>"
@ -94,59 +109,132 @@ CSVWidget::SceneToolMode *CSVRender::WorldspaceWidget::makeNavigationSelector (
return tool;
}
CSVRender::WorldspaceWidget::dropType CSVRender::WorldspaceWidget::getDropType (
CSVWidget::SceneToolToggle *CSVRender::WorldspaceWidget::makeSceneVisibilitySelector (CSVWidget::SceneToolbar *parent)
{
mSceneElements= new CSVWidget::SceneToolToggle (parent,
"Scene Element Visibility", ":door.png");
addVisibilitySelectorButtons (mSceneElements);
mSceneElements->setSelection (0xffffffff);
connect (mSceneElements, SIGNAL (selectionChanged()),
this, SLOT (elementSelectionChanged()));
return mSceneElements;
}
CSVWidget::SceneToolRun *CSVRender::WorldspaceWidget::makeRunTool (
CSVWidget::SceneToolbar *parent)
{
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
std::vector<std::string> profiles;
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int stateColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
int defaultColumn = debugProfiles.findColumnIndex (
CSMWorld::Columns::ColumnId_DefaultProfile);
int size = debugProfiles.rowCount();
for (int i=0; i<size; ++i)
{
int state = debugProfiles.data (debugProfiles.index (i, stateColumn)).toInt();
bool default_ = debugProfiles.data (debugProfiles.index (i, defaultColumn)).toInt();
if (state!=CSMWorld::RecordBase::State_Deleted && default_)
profiles.push_back (
debugProfiles.data (debugProfiles.index (i, idColumn)).
toString().toUtf8().constData());
}
std::sort (profiles.begin(), profiles.end());
mRun = new CSVWidget::SceneToolRun (parent, "Run OpenMW from the current camera position",
":door.png", ":faction.png", profiles);
connect (mRun, SIGNAL (runRequest (const std::string&)),
this, SLOT (runRequest (const std::string&)));
return mRun;
}
CSVRender::WorldspaceWidget::DropType CSVRender::WorldspaceWidget::getDropType (
const std::vector< CSMWorld::UniversalId >& data)
{
dropType output = notCells;
bool firstIteration = true;
DropType output = Type_Other;
for (unsigned i = 0; i < data.size(); ++i)
for (std::vector<CSMWorld::UniversalId>::const_iterator iter (data.begin());
iter!=data.end(); ++iter)
{
if (data[i].getType() == CSMWorld::UniversalId::Type_Cell ||
data[i].getType() == CSMWorld::UniversalId::Type_Cell_Missing)
DropType type = Type_Other;
if (iter->getType()==CSMWorld::UniversalId::Type_Cell ||
iter->getType()==CSMWorld::UniversalId::Type_Cell_Missing)
{
if (*(data[i].getId().begin()) == '#') //exterior
{
if (firstIteration)
{
output = cellsExterior;
firstIteration = false;
continue;
}
if (output == cellsInterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
} else //interior
{
if (firstIteration)
{
output = cellsInterior;
firstIteration = false;
continue;
}
if (output == cellsExterior)
{
output = cellsMixed;
break;
} else {
output = cellsInterior;
}
}
} else {
output = notCells;
break;
type = iter->getId().substr (0, 1)=="#" ? Type_CellsExterior : Type_CellsInterior;
}
else if (iter->getType()==CSMWorld::UniversalId::Type_DebugProfile)
type = Type_DebugProfile;
if (iter==data.begin())
output = type;
else if (output!=type) // mixed types -> ignore
return Type_Other;
}
return output;
}
CSVRender::WorldspaceWidget::dropRequirments
CSVRender::WorldspaceWidget::getDropRequirements (DropType type) const
{
if (type==Type_DebugProfile)
return canHandle;
return ignored;
}
bool CSVRender::WorldspaceWidget::handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type)
{
if (type==Type_DebugProfile)
{
if (mRun)
{
for (std::vector<CSMWorld::UniversalId>::const_iterator iter (data.begin());
iter!=data.end(); ++iter)
mRun->addProfile (iter->getId());
}
return true;
}
return false;
}
unsigned int CSVRender::WorldspaceWidget::getElementMask() const
{
return mSceneElements->getSelection();
}
void CSVRender::WorldspaceWidget::addVisibilitySelectorButtons (
CSVWidget::SceneToolToggle *tool)
{
tool->addButton (":activator.png", Element_Reference, ":activator.png", "References");
tool->addButton (":armor.png", Element_Terrain, ":armor.png", "Terrain");
tool->addButton (":armor.png", Element_Water, ":armor.png", "Water");
tool->addButton (":armor.png", Element_Pathgrid, ":armor.png", "Pathgrid");
}
CSMDoc::Document& CSVRender::WorldspaceWidget::getDocument()
{
return mDocument;
}
void CSVRender::WorldspaceWidget::dragEnterEvent (QDragEnterEvent* event)
{
event->accept();
@ -157,7 +245,6 @@ void CSVRender::WorldspaceWidget::dragMoveEvent(QDragMoveEvent *event)
event->accept();
}
void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
{
const CSMWorld::TableMimeData* mime = dynamic_cast<const CSMWorld::TableMimeData*> (event->mimeData());
@ -169,3 +256,61 @@ void CSVRender::WorldspaceWidget::dropEvent (QDropEvent* event)
emit dataDropped(mime->getData());
} //not handling drops from different documents at the moment
}
void CSVRender::WorldspaceWidget::runRequest (const std::string& profile)
{
mDocument.startRunning (profile, getStartupInstruction());
}
void CSVRender::WorldspaceWidget::debugProfileDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight)
{
if (!mRun)
return;
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
int stateColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Modification);
for (int i=topLeft.row(); i<=bottomRight.row(); ++i)
{
int state = debugProfiles.data (debugProfiles.index (i, stateColumn)).toInt();
// As of version 0.33 this case can not happen because debug profiles exist only in
// project or session scope, which means they will never be in deleted state. But we
// are adding the code for the sake of completeness and to avoid surprises if debug
// profile ever get extended to content scope.
if (state==CSMWorld::RecordBase::State_Deleted)
mRun->removeProfile (debugProfiles.data (
debugProfiles.index (i, idColumn)).toString().toUtf8().constData());
}
}
void CSVRender::WorldspaceWidget::debugProfileAboutToBeRemoved (const QModelIndex& parent,
int start, int end)
{
if (parent.isValid())
return;
if (!mRun)
return;
CSMWorld::IdTable& debugProfiles = dynamic_cast<CSMWorld::IdTable&> (
*mDocument.getData().getTableModel (CSMWorld::UniversalId::Type_DebugProfiles));
int idColumn = debugProfiles.findColumnIndex (CSMWorld::Columns::ColumnId_Id);
for (int i=start; i<=end; ++i)
{
mRun->removeProfile (debugProfiles.data (
debugProfiles.index (i, idColumn)).toString().toUtf8().constData());
}
}
void CSVRender::WorldspaceWidget::elementSelectionChanged()
{
setVisibilityMask (getElementMask());
flagAsModified();
}

@ -16,7 +16,9 @@ namespace CSMWorld
namespace CSVWidget
{
class SceneToolMode;
class SceneToolToggle;
class SceneToolbar;
class SceneToolRun;
}
namespace CSVRender
@ -28,15 +30,18 @@ namespace CSVRender
CSVRender::Navigation1st m1st;
CSVRender::NavigationFree mFree;
CSVRender::NavigationOrbit mOrbit;
CSVWidget::SceneToolToggle *mSceneElements;
CSVWidget::SceneToolRun *mRun;
CSMDoc::Document& mDocument;
public:
enum dropType
enum DropType
{
cellsMixed,
cellsInterior,
cellsExterior,
notCells
Type_CellsInterior,
Type_CellsExterior,
Type_Other,
Type_DebugProfile
};
enum dropRequirments
@ -53,19 +58,35 @@ namespace CSVRender
///< \attention The created tool is not added to the toolbar (via addTool). Doing that
/// is the responsibility of the calling function.
/// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function.
CSVWidget::SceneToolToggle *makeSceneVisibilitySelector (
CSVWidget::SceneToolbar *parent);
/// \attention The created tool is not added to the toolbar (via addTool). Doing
/// that is the responsibility of the calling function.
CSVWidget::SceneToolRun *makeRunTool (CSVWidget::SceneToolbar *parent);
void selectDefaultNavigationMode();
static dropType getDropType(const std::vector<CSMWorld::UniversalId>& data);
static DropType getDropType(const std::vector<CSMWorld::UniversalId>& data);
virtual dropRequirments getDropRequirements(dropType type) const = 0;
virtual dropRequirments getDropRequirements(DropType type) const;
virtual void useViewHint (const std::string& hint);
///< Default-implementation: ignored.
virtual void handleDrop(const std::vector<CSMWorld::UniversalId>& data) = 0;
/// \return Drop handled?
virtual bool handleDrop (const std::vector<CSMWorld::UniversalId>& data,
DropType type);
virtual unsigned int getElementMask() const;
protected:
const CSMDoc::Document& mDocument; //for checking if drop comes from same document
virtual void addVisibilitySelectorButtons (CSVWidget::SceneToolToggle *tool);
CSMDoc::Document& getDocument();
private:
@ -75,6 +96,8 @@ namespace CSVRender
void dragMoveEvent(QDragMoveEvent *event);
virtual std::string getStartupInstruction() = 0;
private slots:
void selectNavigationMode (const std::string& mode);
@ -92,6 +115,18 @@ namespace CSVRender
virtual void referenceAdded (const QModelIndex& index, int start, int end) = 0;
virtual void runRequest (const std::string& profile);
void debugProfileDataChanged (const QModelIndex& topLeft,
const QModelIndex& bottomRight);
void debugProfileAboutToBeRemoved (const QModelIndex& parent, int start, int end);
protected slots:
void elementSelectionChanged();
signals:
void closeRequest();

@ -114,8 +114,20 @@ void CSVSettings::Dialog::show()
setViewValues();
}
QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move (screenCenter - geometry().center());
QWidget *currView = QApplication::activeWindow();
if(currView)
{
// place at the center of the window with focus
QSize size = currView->size();
move(currView->geometry().x()+(size.width() - frameGeometry().width())/2,
currView->geometry().y()+(size.height() - frameGeometry().height())/2);
}
else
{
// something's gone wrong, place at the center of the screen
QPoint screenCenter = QApplication::desktop()->screenGeometry().center();
move(screenCenter - QPoint(frameGeometry().width()/2,
frameGeometry().height()/2));
}
QWidget::show();
}

@ -21,7 +21,7 @@ CSVTools::ReportSubView::ReportSubView (const CSMWorld::UniversalId& id, CSMDoc:
mTable->setSelectionMode (QAbstractItemView::ExtendedSelection);
mIdTypeDelegate = CSVWorld::IdTypeDelegateFactory().makeDelegate (
document.getUndoStack(), this);
document, this);
mTable->setItemDelegateForColumn (0, mIdTypeDelegate);

@ -4,9 +4,9 @@
#include <QMouseEvent>
#include <QKeyEvent>
void CSVWidget::PushButton::setExtendedToolTip (const QString& text)
void CSVWidget::PushButton::setExtendedToolTip()
{
QString tooltip = text;
QString tooltip = mToolTip;
if (tooltip.isEmpty())
tooltip = "(Tool tip not implemented yet)";
@ -20,6 +20,10 @@ void CSVWidget::PushButton::setExtendedToolTip (const QString& text)
break;
case Type_TopAction:
break;
case Type_Mode:
tooltip +=
@ -27,6 +31,16 @@ void CSVWidget::PushButton::setExtendedToolTip (const QString& text)
"<br>shift-left click to activate and keep panel open)";
break;
case Type_Toggle:
tooltip += "<p>(left click to ";
tooltip += isChecked() ? "disable" : "enable";
tooltip += "<p>shift-left click to ";
tooltip += isChecked() ? "disable" : "enable";
tooltip += " and keep panel open)";
break;
}
setToolTip (tooltip);
@ -42,11 +56,8 @@ void CSVWidget::PushButton::keyPressEvent (QKeyEvent *event)
void CSVWidget::PushButton::keyReleaseEvent (QKeyEvent *event)
{
if (event->key()==Qt::Key_Return || event->key()==Qt::Key_Enter)
{
if (event->key()==Qt::Key_Space)
mKeepOpen = event->modifiers() & Qt::ShiftModifier;
emit clicked();
}
QPushButton::keyReleaseEvent (event);
}
@ -61,15 +72,15 @@ CSVWidget::PushButton::PushButton (const QIcon& icon, Type type, const QString&
QWidget *parent)
: QPushButton (icon, "", parent), mKeepOpen (false), mType (type), mToolTip (tooltip)
{
setCheckable (type==Type_Mode);
setExtendedToolTip (tooltip);
setCheckable (type==Type_Mode || type==Type_Toggle);
setExtendedToolTip();
}
CSVWidget::PushButton::PushButton (Type type, const QString& tooltip, QWidget *parent)
: QPushButton (parent), mKeepOpen (false), mType (type), mToolTip (tooltip)
{
setCheckable (type==Type_Mode);
setExtendedToolTip (tooltip);
setCheckable (type==Type_Mode || type==Type_Toggle);
setExtendedToolTip();
}
bool CSVWidget::PushButton::hasKeepOpen() const
@ -80,4 +91,9 @@ bool CSVWidget::PushButton::hasKeepOpen() const
QString CSVWidget::PushButton::getBaseToolTip() const
{
return mToolTip;
}
CSVWidget::PushButton::Type CSVWidget::PushButton::getType() const
{
return mType;
}

@ -14,7 +14,9 @@ namespace CSVWidget
enum Type
{
Type_TopMode, // top level button for mode selector panel
Type_Mode // mode button
Type_TopAction, // top level button that triggers an action
Type_Mode, // mode button
Type_Toggle
};
private:
@ -25,7 +27,7 @@ namespace CSVWidget
private:
void setExtendedToolTip (const QString& text);
void setExtendedToolTip();
protected:
@ -49,6 +51,8 @@ namespace CSVWidget
/// Return tooltip used at construction (without any button-specific modifications)
QString getBaseToolTip() const;
Type getType() const;
};
}

@ -1,10 +1,12 @@
#include "scenetool.hpp"
#include <QMouseEvent>
#include "scenetoolbar.hpp"
CSVWidget::SceneTool::SceneTool (SceneToolbar *parent)
: PushButton (PushButton::Type_TopMode, "", parent)
CSVWidget::SceneTool::SceneTool (SceneToolbar *parent, Type type)
: PushButton (type, "", parent)
{
setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
setIconSize (QSize (parent->getIconSize(), parent->getIconSize()));
@ -13,7 +15,20 @@ CSVWidget::SceneTool::SceneTool (SceneToolbar *parent)
connect (this, SIGNAL (clicked()), this, SLOT (openRequest()));
}
void CSVWidget::SceneTool::activate() {}
void CSVWidget::SceneTool::mouseReleaseEvent (QMouseEvent *event)
{
if (getType()==Type_TopAction && event->button()==Qt::RightButton)
showPanel (parentWidget()->mapToGlobal (pos()));
else
PushButton::mouseReleaseEvent (event);
}
void CSVWidget::SceneTool::openRequest()
{
showPanel (parentWidget()->mapToGlobal (pos()));
if (getType()==Type_TopAction)
activate();
else
showPanel (parentWidget()->mapToGlobal (pos()));
}

@ -14,10 +14,18 @@ namespace CSVWidget
public:
SceneTool (SceneToolbar *parent);
SceneTool (SceneToolbar *parent, Type type = Type_TopMode);
virtual void showPanel (const QPoint& position) = 0;
/// This function will only called for buttons of type Type_TopAction. The default
/// implementation is empty.
virtual void activate();
protected:
void mouseReleaseEvent (QMouseEvent *event);
private slots:
void openRequest();

@ -0,0 +1,151 @@
#include "scenetoolrun.hpp"
#include <iterator>
#include <QFrame>
#include <QTableWidget>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QApplication>
void CSVWidget::SceneToolRun::adjustToolTips()
{
QString toolTip = mToolTip;
if (mSelected==mProfiles.end())
toolTip += "<p>No debug profile selected (function disabled)";
else
{
toolTip += "<p>Debug profile: " + QString::fromUtf8 (mSelected->c_str());
toolTip += "<p>(right click to switch to a different profile)";
}
setToolTip (toolTip);
}
void CSVWidget::SceneToolRun::updateIcon()
{
setIcon (QIcon (mSelected==mProfiles.end() ? mIconDisabled : mIcon));
}
void CSVWidget::SceneToolRun::updatePanel()
{
mTable->setRowCount (mProfiles.size());
int i = 0;
for (std::set<std::string>::const_iterator iter (mProfiles.begin()); iter!=mProfiles.end();
++iter, ++i)
{
mTable->setItem (i, 0, new QTableWidgetItem (QString::fromUtf8 (iter->c_str())));
mTable->setItem (i, 1, new QTableWidgetItem (
QApplication::style()->standardIcon (QStyle::SP_TitleBarCloseButton), ""));
}
}
CSVWidget::SceneToolRun::SceneToolRun (SceneToolbar *parent, const QString& toolTip,
const QString& icon, const QString& iconDisabled, const std::vector<std::string>& profiles)
: SceneTool (parent, Type_TopAction), mProfiles (profiles.begin(), profiles.end()),
mSelected (mProfiles.begin()), mToolTip (toolTip), mIcon (icon),
mIconDisabled (iconDisabled)
{
updateIcon();
adjustToolTips();
mPanel = new QFrame (this, Qt::Popup);
QHBoxLayout *layout = new QHBoxLayout (mPanel);
layout->setContentsMargins (QMargins (0, 0, 0, 0));
mTable = new QTableWidget (0, 2, this);
mTable->setShowGrid (false);
mTable->verticalHeader()->hide();
mTable->horizontalHeader()->hide();
mTable->horizontalHeader()->setResizeMode (0, QHeaderView::Stretch);
mTable->horizontalHeader()->setResizeMode (1, QHeaderView::ResizeToContents);
mTable->setSelectionMode (QAbstractItemView::NoSelection);
layout->addWidget (mTable);
connect (mTable, SIGNAL (clicked (const QModelIndex&)),
this, SLOT (clicked (const QModelIndex&)));
}
void CSVWidget::SceneToolRun::showPanel (const QPoint& position)
{
updatePanel();
mPanel->move (position);
mPanel->show();
}
void CSVWidget::SceneToolRun::activate()
{
if (mSelected!=mProfiles.end())
emit runRequest (*mSelected);
}
void CSVWidget::SceneToolRun::removeProfile (const std::string& profile)
{
std::set<std::string>::iterator iter = mProfiles.find (profile);
if (iter!=mProfiles.end())
{
if (iter==mSelected)
{
if (iter!=mProfiles.begin())
--mSelected;
else
++mSelected;
}
mProfiles.erase (iter);
if (mSelected==mProfiles.end())
updateIcon();
adjustToolTips();
}
}
void CSVWidget::SceneToolRun::addProfile (const std::string& profile)
{
std::set<std::string>::iterator iter = mProfiles.find (profile);
if (iter==mProfiles.end())
{
mProfiles.insert (profile);
if (mSelected==mProfiles.end())
{
mSelected = mProfiles.begin();
updateIcon();
}
adjustToolTips();
}
}
void CSVWidget::SceneToolRun::clicked (const QModelIndex& index)
{
if (index.column()==0)
{
// select profile
mSelected = mProfiles.begin();
std::advance (mSelected, index.row());
mPanel->hide();
adjustToolTips();
}
else if (index.column()==1)
{
// remove profile from list
std::set<std::string>::iterator iter = mProfiles.begin();
std::advance (iter, index.row());
removeProfile (*iter);
updatePanel();
}
}

@ -0,0 +1,64 @@
#ifndef CSV_WIDGET_SCENETOOLRUN_H
#define CSV_WIDGET_SCENETOOLRUN_H
#include <set>
#include <string>
#include "scenetool.hpp"
class QFrame;
class QTableWidget;
class QModelIndex;
namespace CSVWidget
{
class SceneToolRun : public SceneTool
{
Q_OBJECT
std::set<std::string> mProfiles;
std::set<std::string>::iterator mSelected;
QString mToolTip;
QString mIcon;
QString mIconDisabled;
QFrame *mPanel;
QTableWidget *mTable;
private:
void adjustToolTips();
void updateIcon();
void updatePanel();
public:
SceneToolRun (SceneToolbar *parent, const QString& toolTip, const QString& icon,
const QString& iconDisabled, const std::vector<std::string>& profiles);
virtual void showPanel (const QPoint& position);
virtual void activate();
/// \attention This function does not remove the profile from the profile selection
/// panel.
void removeProfile (const std::string& profile);
/// \attention This function doe not add the profile to the profile selection
/// panel. This only happens when the panel is re-opened.
///
/// \note Adding profiles that are already listed is a no-op.
void addProfile (const std::string& profile);
private slots:
void clicked (const QModelIndex& index);
signals:
void runRequest (const std::string& profile);
};
}
#endif

@ -0,0 +1,205 @@
#include "scenetooltoggle.hpp"
#include <stdexcept>
#include <QHBoxLayout>
#include <QFrame>
#include <QIcon>
#include <QPainter>
#include "scenetoolbar.hpp"
#include "pushbutton.hpp"
void CSVWidget::SceneToolToggle::adjustToolTip()
{
QString toolTip = mToolTip;
toolTip += "<p>Currently enabled: ";
bool first = true;
for (std::map<PushButton *, ButtonDesc>::const_iterator iter (mButtons.begin());
iter!=mButtons.end(); ++iter)
if (iter->first->isChecked())
{
if (!first)
toolTip += ", ";
else
first = false;
toolTip += iter->second.mName;
}
if (first)
toolTip += "none";
toolTip += "<p>(left click to alter selection)";
setToolTip (toolTip);
}
void CSVWidget::SceneToolToggle::adjustIcon()
{
unsigned int selection = getSelection();
if (!selection)
setIcon (QIcon (QString::fromUtf8 (mEmptyIcon.c_str())));
else
{
QPixmap pixmap (48, 48);
pixmap.fill (QColor (0, 0, 0, 0));
{
QPainter painter (&pixmap);
for (std::map<PushButton *, ButtonDesc>::const_iterator iter (mButtons.begin());
iter!=mButtons.end(); ++iter)
if (iter->first->isChecked())
{
painter.drawImage (getIconBox (iter->second.mIndex),
QImage (QString::fromUtf8 (iter->second.mSmallIcon.c_str())));
}
}
setIcon (pixmap);
}
}
QRect CSVWidget::SceneToolToggle::getIconBox (int index) const
{
// layout for a 3x3 grid
int xMax = 3;
int yMax = 3;
// icon size
int xBorder = 1;
int yBorder = 1;
int iconXSize = (mIconSize-xBorder*(xMax+1))/xMax;
int iconYSize = (mIconSize-yBorder*(yMax+1))/yMax;
int y = index / xMax;
int x = index % xMax;
int total = mButtons.size();
int actualYIcons = total/xMax;
if (total % xMax)
++actualYIcons;
if (actualYIcons!=yMax)
{
// space out icons vertically, if there aren't enough to populate all rows
int diff = yMax - actualYIcons;
yBorder += (diff*(yBorder+iconXSize)) / (actualYIcons+1);
}
if (y==actualYIcons-1)
{
// generating the last row of icons
int actualXIcons = total % xMax;
if (actualXIcons)
{
// space out icons horizontally, if there aren't enough to fill the last row
int diff = xMax - actualXIcons;
xBorder += (diff*(xBorder+iconXSize)) / (actualXIcons+1);
}
}
return QRect ((iconXSize+xBorder)*x+xBorder, (iconYSize+yBorder)*y+yBorder,
iconXSize, iconYSize);
}
CSVWidget::SceneToolToggle::SceneToolToggle (SceneToolbar *parent, const QString& toolTip,
const std::string& emptyIcon)
: SceneTool (parent), mEmptyIcon (emptyIcon), mButtonSize (parent->getButtonSize()),
mIconSize (parent->getIconSize()), mToolTip (toolTip), mFirst (0)
{
mPanel = new QFrame (this, Qt::Popup);
mLayout = new QHBoxLayout (mPanel);
mLayout->setContentsMargins (QMargins (0, 0, 0, 0));
mPanel->setLayout (mLayout);
}
void CSVWidget::SceneToolToggle::showPanel (const QPoint& position)
{
mPanel->move (position);
mPanel->show();
if (mFirst)
mFirst->setFocus (Qt::OtherFocusReason);
}
void CSVWidget::SceneToolToggle::addButton (const std::string& icon, unsigned int id,
const std::string& smallIcon, const QString& name, const QString& tooltip)
{
if (mButtons.size()>=9)
throw std::runtime_error ("Exceeded number of buttons in toggle type tool");
PushButton *button = new PushButton (QIcon (QPixmap (icon.c_str())),
PushButton::Type_Toggle, tooltip.isEmpty() ? name: tooltip, mPanel);
button->setSizePolicy (QSizePolicy (QSizePolicy::Fixed, QSizePolicy::Fixed));
button->setIconSize (QSize (mIconSize, mIconSize));
button->setFixedSize (mButtonSize, mButtonSize);
mLayout->addWidget (button);
ButtonDesc desc;
desc.mId = id;
desc.mSmallIcon = smallIcon;
desc.mName = name;
desc.mIndex = mButtons.size();
mButtons.insert (std::make_pair (button, desc));
connect (button, SIGNAL (clicked()), this, SLOT (selected()));
if (mButtons.size()==1)
mFirst = button;
}
unsigned int CSVWidget::SceneToolToggle::getSelection() const
{
unsigned int selection = 0;
for (std::map<PushButton *, ButtonDesc>::const_iterator iter (mButtons.begin());
iter!=mButtons.end(); ++iter)
if (iter->first->isChecked())
selection |= iter->second.mId;
return selection;
}
void CSVWidget::SceneToolToggle::setSelection (unsigned int selection)
{
for (std::map<PushButton *, ButtonDesc>::iterator iter (mButtons.begin());
iter!=mButtons.end(); ++iter)
iter->first->setChecked (selection & iter->second.mId);
adjustToolTip();
adjustIcon();
}
void CSVWidget::SceneToolToggle::selected()
{
std::map<PushButton *, ButtonDesc>::const_iterator iter =
mButtons.find (dynamic_cast<PushButton *> (sender()));
if (iter!=mButtons.end())
{
if (!iter->first->hasKeepOpen())
mPanel->hide();
adjustToolTip();
adjustIcon();
emit selectionChanged();
}
}

@ -0,0 +1,75 @@
#ifndef CSV_WIDGET_SCENETOOL_TOGGLE_H
#define CSV_WIDGET_SCENETOOL_TOGGLE_H
#include "scenetool.hpp"
#include <map>
class QHBoxLayout;
class QRect;
namespace CSVWidget
{
class SceneToolbar;
class PushButton;
///< \brief Multi-Toggle tool
class SceneToolToggle : public SceneTool
{
Q_OBJECT
struct ButtonDesc
{
unsigned int mId;
std::string mSmallIcon;
QString mName;
int mIndex;
};
std::string mEmptyIcon;
QWidget *mPanel;
QHBoxLayout *mLayout;
std::map<PushButton *, ButtonDesc> mButtons; // widget, id
int mButtonSize;
int mIconSize;
QString mToolTip;
PushButton *mFirst;
void adjustToolTip();
void adjustIcon();
QRect getIconBox (int index) const;
public:
SceneToolToggle (SceneToolbar *parent, const QString& toolTip,
const std::string& emptyIcon);
virtual void showPanel (const QPoint& position);
/// \attention After the last button has been added, setSelection must be called at
/// least once to finalise the layout.
///
/// \note The layout algorithm can not handle more than 9 buttons. To prevent this An
/// attempt to add more will result in an exception being thrown.
/// The small icons will be sized at (x-4)/3 (where x is the main icon size).
void addButton (const std::string& icon, unsigned int id,
const std::string& smallIcon, const QString& name, const QString& tooltip = "");
unsigned int getSelection() const;
/// \param or'ed button IDs. IDs that do not exist will be ignored.
void setSelection (unsigned int selection);
signals:
void selectionChanged();
private slots:
void selected();
};
}
#endif

@ -1,7 +1,16 @@
#include "creator.hpp"
CSVWorld::Creator:: ~Creator() {}
#include <stdexcept>
CSVWorld::Creator::~Creator() {}
void CSVWorld::Creator::setScope (unsigned int scope)
{
if (scope!=CSMWorld::Scope_Content)
throw std::logic_error ("Invalid scope in creator");
}
CSVWorld::CreatorFactoryBase::~CreatorFactoryBase() {}

@ -1,9 +1,14 @@
#ifndef CSV_WORLD_CREATOR_H
#define CSV_WORLD_CREATOR_H
#include <memory>
#include <QWidget>
#include "../../model/world/universalid.hpp"
#include "../../model/world/scope.hpp"
class QUndoStack;
namespace CSMWorld
@ -32,6 +37,9 @@ namespace CSVWorld
virtual void toggleWidgets(bool active = true) = 0;
/// Default implementation: Throw an exception if scope!=Scope_Content.
virtual void setScope (unsigned int scope);
signals:
void done();
@ -68,7 +76,7 @@ namespace CSVWorld
/// \note The function always returns 0.
};
template<class CreatorT>
template<class CreatorT, unsigned int scope = CSMWorld::Scope_Content>
class CreatorFactory : public CreatorFactoryBase
{
public:
@ -81,11 +89,15 @@ namespace CSVWorld
/// records should be provided.
};
template<class CreatorT>
Creator *CreatorFactory<CreatorT>::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
template<class CreatorT, unsigned int scope>
Creator *CreatorFactory<CreatorT, scope>::makeCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id) const
{
return new CreatorT (data, undoStack, id);
std::auto_ptr<CreatorT> creator (new CreatorT (data, undoStack, id));
creator->setScope (scope);
return creator.release();
}
}

@ -6,11 +6,11 @@
CSVWorld::DataDisplayDelegate::DataDisplayDelegate(const ValueList &values,
const IconList &icons,
QUndoStack &undoStack,
CSMDoc::Document& document,
const QString &pageName,
const QString &settingName,
QObject *parent)
: EnumDelegate (values, undoStack, parent), mDisplayMode (Mode_TextOnly),
: EnumDelegate (values, document, parent), mDisplayMode (Mode_TextOnly),
mIcons (icons), mIconSize (QSize(16, 16)), mIconLeftOffset(3),
mTextLeftOffset(8), mSettingKey (pageName + '/' + settingName)
{
@ -38,7 +38,7 @@ void CSVWorld::DataDisplayDelegate::buildPixmaps ()
}
}
void CSVWorld::DataDisplayDelegate::setIconSize(const QSize size)
void CSVWorld::DataDisplayDelegate::setIconSize(const QSize& size)
{
mIconSize = size;
buildPixmaps();
@ -126,8 +126,6 @@ void CSVWorld::DataDisplayDelegate::updateDisplayMode (const QString &mode)
CSVWorld::DataDisplayDelegate::~DataDisplayDelegate()
{
mIcons.clear();
mPixmaps.clear();
}
void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName, QString iconFilename)
@ -137,11 +135,10 @@ void CSVWorld::DataDisplayDelegateFactory::add (int enumValue, QString enumName,
}
CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (QUndoStack& undoStack,
QObject *parent) const
CSVWorld::CommandDelegate *CSVWorld::DataDisplayDelegateFactory::makeDelegate (
CSMDoc::Document& document, QObject *parent) const
{
return new DataDisplayDelegate (mValues, mIcons, undoStack, "", "", parent);
return new DataDisplayDelegate (mValues, mIcons, document, "", "", parent);
}

@ -40,7 +40,7 @@ namespace CSVWorld
public:
explicit DataDisplayDelegate (const ValueList & values,
const IconList & icons,
QUndoStack& undoStack,
CSMDoc::Document& document,
const QString &pageName,
const QString &settingName,
QObject *parent);
@ -50,7 +50,7 @@ namespace CSVWorld
virtual void paint (QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
/// pass a QSize defining height / width of icon. Default is QSize (16,16).
void setIconSize (const QSize icon);
void setIconSize (const QSize& icon);
/// offset the horizontal position of the icon from the left edge of the cell. Default is 3 pixels.
void setIconLeftOffset (int offset);
@ -82,7 +82,7 @@ namespace CSVWorld
public:
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
protected:

@ -167,10 +167,10 @@ void CSVWorld::DialogueDelegateDispatcherProxy::tableMimeDataDropped(const std::
==============================DialogueDelegateDispatcher==========================================
*/
CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack) :
CSVWorld::DialogueDelegateDispatcher::DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document) :
mParent(parent),
mTable(table),
mUndoStack(undoStack),
mDocument (document),
mNotEditableDelegate(table, parent)
{
}
@ -182,7 +182,7 @@ CSVWorld::CommandDelegate* CSVWorld::DialogueDelegateDispatcher::makeDelegate(CS
if (delegateIt == mDelegates.end())
{
delegate = CommandDelegateFactoryCollection::get().makeDelegate (
display, mUndoStack, mParent);
display, mDocument, mParent);
mDelegates.insert(std::make_pair(display, delegate));
} else
{
@ -266,7 +266,6 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
editor = delegateIt->second->createEditor(qobject_cast<QWidget*>(mParent), QStyleOptionViewItem(), index, display);
DialogueDelegateDispatcherProxy* proxy = new DialogueDelegateDispatcherProxy(editor, display);
bool skip = false;
if (qobject_cast<DropLineEdit*>(editor))
{
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
@ -274,27 +273,22 @@ QWidget* CSVWorld::DialogueDelegateDispatcher::makeEditor(CSMWorld::ColumnBase::
proxy, SLOT(tableMimeDataDropped(const std::vector<CSMWorld::UniversalId>&, const CSMDoc::Document*)));
connect(proxy, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));
skip = true;
}
if(!skip && qobject_cast<QCheckBox*>(editor))
else if (qobject_cast<QCheckBox*>(editor))
{
connect(editor, SIGNAL(stateChanged(int)), proxy, SLOT(editorDataCommited()));
skip = true;
}
if(!skip && qobject_cast<QPlainTextEdit*>(editor))
else if (qobject_cast<QPlainTextEdit*>(editor))
{
connect(editor, SIGNAL(textChanged()), proxy, SLOT(editorDataCommited()));
skip = true;
}
if(!skip && qobject_cast<QComboBox*>(editor))
else if (qobject_cast<QComboBox*>(editor))
{
connect(editor, SIGNAL(currentIndexChanged (int)), proxy, SLOT(editorDataCommited()));
skip = true;
}
if(!skip && qobject_cast<QAbstractSpinBox*>(editor))
else if (qobject_cast<QAbstractSpinBox*>(editor))
{
connect(editor, SIGNAL(editingFinished()), proxy, SLOT(editorDataCommited()));
skip = true;
}
connect(proxy, SIGNAL(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)), this, SLOT(editorDataCommited(QWidget*, const QModelIndex&, CSMWorld::ColumnBase::Display)));
@ -315,12 +309,12 @@ CSVWorld::DialogueDelegateDispatcher::~DialogueDelegateDispatcher()
=============================================================EditWidget=====================================================
*/
CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete) :
mDispatcher(this, table, undoStack),
CSVWorld::EditWidget::EditWidget(QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete) :
mDispatcher(this, table, document),
QScrollArea(parent),
mWidgetMapper(NULL),
mMainWidget(NULL),
mUndoStack(undoStack),
mDocument (document),
mTable(table)
{
remake (row);
@ -478,7 +472,7 @@ CSVWorld::DialogueSubView::DialogueSubView (const CSMWorld::UniversalId& id, CSM
mMainLayout = new QVBoxLayout(mainWidget);
mEditWidget = new EditWidget(mainWidget, mRow, mTable, mUndoStack, false);
mEditWidget = new EditWidget(mainWidget, mRow, mTable, document, false);
connect(mEditWidget, SIGNAL(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)),
this, SLOT(tableMimeDataDropped(QWidget*, const QModelIndex&, const CSMWorld::UniversalId&, const CSMDoc::Document*)));

@ -101,14 +101,14 @@ namespace CSVWorld
CSMWorld::IdTable* mTable;
QUndoStack& mUndoStack;
CSMDoc::Document& mDocument;
NotEditableSubDelegate mNotEditableDelegate;
std::vector<DialogueDelegateDispatcherProxy*> mProxys; //once we move to the C++11 we should use unique_ptr
public:
DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, QUndoStack& undoStack);
DialogueDelegateDispatcher(QObject* parent, CSMWorld::IdTable* table, CSMDoc::Document& document);
~DialogueDelegateDispatcher();
@ -145,11 +145,11 @@ namespace CSVWorld
DialogueDelegateDispatcher mDispatcher;
QWidget* mMainWidget;
CSMWorld::IdTable* mTable;
QUndoStack& mUndoStack;
CSMDoc::Document& mDocument;
public:
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, QUndoStack& undoStack, bool createAndDelete = false);
EditWidget (QWidget *parent, int row, CSMWorld::IdTable* table, CSMDoc::Document& document, bool createAndDelete = false);
void remake(int row);

@ -35,8 +35,8 @@ void CSVWorld::EnumDelegate::addCommands (QAbstractItemModel *model,
CSVWorld::EnumDelegate::EnumDelegate (const std::vector<std::pair<int, QString> >& values,
QUndoStack& undoStack, QObject *parent)
: CommandDelegate (undoStack, parent), mValues (values)
CSMDoc::Document& document, QObject *parent)
: CommandDelegate (document, parent), mValues (values)
{
}
@ -140,10 +140,10 @@ CSVWorld::EnumDelegateFactory::EnumDelegateFactory (const std::vector<std::strin
add (i, names[i].c_str());
}
CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (QUndoStack& undoStack,
QObject *parent) const
CSVWorld::CommandDelegate *CSVWorld::EnumDelegateFactory::makeDelegate (
CSMDoc::Document& document, QObject *parent) const
{
return new EnumDelegate (mValues, undoStack, parent);
return new EnumDelegate (mValues, document, parent);
}
void CSVWorld::EnumDelegateFactory::add (int value, const QString& name)

@ -30,7 +30,7 @@ namespace CSVWorld
public:
EnumDelegate (const std::vector<std::pair<int, QString> >& values,
QUndoStack& undoStack, QObject *parent);
CSMDoc::Document& document, QObject *parent);
virtual QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem& option,
@ -64,7 +64,7 @@ namespace CSVWorld
EnumDelegateFactory (const std::vector<std::string>& names, bool allowNone = false);
/// \param allowNone Use value of -1 for "none selected" (empty string)
virtual CommandDelegate *makeDelegate (QUndoStack& undoStack, QObject *parent) const;
virtual CommandDelegate *makeDelegate (CSMDoc::Document& document, QObject *parent) const;
///< The ownership of the returned CommandDelegate is transferred to the caller.
void add (int value, const QString& name);

@ -7,6 +7,10 @@
#include <QPushButton>
#include <QLineEdit>
#include <QUndoStack>
#include <QLabel>
#include <QComboBox>
#include <components/misc/stringops.hpp>
#include "../../model/world/commands.hpp"
#include "../../model/world/data.hpp"
@ -46,32 +50,87 @@ std::string CSVWorld::GenericCreator::getId() const
void CSVWorld::GenericCreator::configureCreateCommand (CSMWorld::CreateCommand& command) const {}
void CSVWorld::GenericCreator::pushCommand (std::auto_ptr<CSMWorld::CreateCommand> command,
const std::string& id)
{
mUndoStack.push (command.release());
}
CSMWorld::Data& CSVWorld::GenericCreator::getData() const
{
return mData;
}
QUndoStack& CSVWorld::GenericCreator::getUndoStack()
{
return mUndoStack;
}
const CSMWorld::UniversalId& CSVWorld::GenericCreator::getCollectionId() const
{
return mListId;
}
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id, bool relaxedIdRules):
std::string CSVWorld::GenericCreator::getNamespace() const
{
CSMWorld::Scope scope = CSMWorld::Scope_Content;
if (mScope)
{
scope = static_cast<CSMWorld::Scope> (mScope->itemData (mScope->currentIndex()).toInt());
}
else
{
if (mScopes & CSMWorld::Scope_Project)
scope = CSMWorld::Scope_Project;
else if (mScopes & CSMWorld::Scope_Session)
scope = CSMWorld::Scope_Session;
}
switch (scope)
{
case CSMWorld::Scope_Content: return "";
case CSMWorld::Scope_Project: return "project::";
case CSMWorld::Scope_Session: return "session::";
}
return "";
}
void CSVWorld::GenericCreator::updateNamespace()
{
std::string namespace_ = getNamespace();
mValidator->setNamespace (namespace_);
int index = mId->text().indexOf ("::");
if (index==-1)
{
// no namespace in old text
mId->setText (QString::fromUtf8 (namespace_.c_str()) + mId->text());
}
else
{
std::string oldNamespace =
Misc::StringUtils::lowerCase (mId->text().left (index).toUtf8().constData());
mData (data),
mUndoStack (undoStack),
mListId (id),
mLocked (false),
mCloneMode(false),
mClonedType(CSMWorld::UniversalId::Type_None)
if (oldNamespace=="project" || oldNamespace=="session")
mId->setText (QString::fromUtf8 (namespace_.c_str()) + mId->text().mid (index+2));
}
}
CSVWorld::GenericCreator::GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
const CSMWorld::UniversalId& id, bool relaxedIdRules)
: mData (data), mUndoStack (undoStack), mListId (id), mLocked (false), mCloneMode (false),
mClonedType (CSMWorld::UniversalId::Type_None), mScopes (CSMWorld::Scope_Content), mScope (0),
mScopeLabel (0)
{
mLayout = new QHBoxLayout;
mLayout->setContentsMargins (0, 0, 0, 0);
mId = new QLineEdit;
mId->setValidator (new IdValidator (relaxedIdRules, this));
mId->setValidator (mValidator = new IdValidator (relaxedIdRules, this));
mLayout->addWidget (mId, 1);
mCreate = new QPushButton ("Create");
@ -99,22 +158,17 @@ void CSVWorld::GenericCreator::reset()
mCloneMode = false;
mId->setText ("");
update();
updateNamespace();
}
std::string CSVWorld::GenericCreator::getErrors() const
{
std::string errors;
std::string id = getId();
if (id.empty())
{
errors = "Missing ID";
}
else if (mData.hasId (id))
{
if (!mId->hasAcceptableInput())
errors = mValidator->getError();
else if (mData.hasId (getId()))
errors = "ID is already in use";
}
return errors;
}
@ -128,29 +182,27 @@ void CSVWorld::GenericCreator::create()
{
if (!mLocked)
{
std::string id = getId();
std::auto_ptr<CSMWorld::CreateCommand> command;
if (mCloneMode)
{
std::string id = getId();
std::auto_ptr<CSMWorld::CloneCommand> command (new CSMWorld::CloneCommand (
command.reset (new CSMWorld::CloneCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel(mListId)), mClonedId, id, mClonedType));
}
else
{
command.reset (new CSMWorld::CreateCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id));
mUndoStack.push(command.release());
emit done();
emit requestFocus(id);
} else {
std::string id = getId();
std::auto_ptr<CSMWorld::CreateCommand> command (new CSMWorld::CreateCommand (
dynamic_cast<CSMWorld::IdTable&> (*mData.getTableModel (mListId)), id));
configureCreateCommand (*command);
}
mUndoStack.push (command.release());
configureCreateCommand (*command);
pushCommand (command, id);
emit done();
emit requestFocus (id);
}
emit done();
emit requestFocus(id);
}
}
@ -165,3 +217,49 @@ void CSVWorld::GenericCreator::cloneMode(const std::string& originId,
void CSVWorld::GenericCreator::toggleWidgets(bool active)
{
}
void CSVWorld::GenericCreator::setScope (unsigned int scope)
{
mScopes = scope;
int count = (mScopes & CSMWorld::Scope_Content) + (mScopes & CSMWorld::Scope_Project) +
(mScopes & CSMWorld::Scope_Session);
// scope selector widget
if (count>1)
{
mScope = new QComboBox (this);
insertAtBeginning (mScope, false);
if (mScopes & CSMWorld::Scope_Content)
mScope->addItem ("Content", static_cast<int> (CSMWorld::Scope_Content));
if (mScopes & CSMWorld::Scope_Project)
mScope->addItem ("Project", static_cast<int> (CSMWorld::Scope_Project));
if (mScopes & CSMWorld::Scope_Session)
mScope->addItem ("Session", static_cast<int> (CSMWorld::Scope_Session));
connect (mScope, SIGNAL (currentIndexChanged (int)), this, SLOT (scopeChanged (int)));
mScopeLabel = new QLabel ("Scope", this);
insertAtBeginning (mScopeLabel, false);
mScope->setCurrentIndex (0);
}
else
{
delete mScope;
mScope = 0;
delete mScopeLabel;
mScopeLabel = 0;
}
updateNamespace();
}
void CSVWorld::GenericCreator::scopeChanged (int index)
{
update();
updateNamespace();
}

@ -1,14 +1,18 @@
#ifndef CSV_WORLD_GENERICCREATOR_H
#define CSV_WORLD_GENERICCREATOR_H
#include <memory>
#include "../../model/world/universalid.hpp"
#include "creator.hpp"
class QString;
class QPushButton;
class QLineEdit;
class QHBoxLayout;
#include "creator.hpp"
#include "../../model/world/universalid.hpp"
class QComboBox;
class QLabel;
namespace CSMWorld
{
@ -17,6 +21,8 @@ namespace CSMWorld
namespace CSVWorld
{
class IdValidator;
class GenericCreator : public Creator
{
Q_OBJECT
@ -31,6 +37,10 @@ namespace CSVWorld
bool mLocked;
std::string mClonedId;
CSMWorld::UniversalId::Type mClonedType;
unsigned int mScopes;
QComboBox *mScope;
QLabel *mScopeLabel;
IdValidator *mValidator;
protected:
bool mCloneMode;
@ -48,12 +58,26 @@ namespace CSVWorld
virtual std::string getId() const;
/// Allow subclasses to add additional data to \a command.
virtual void configureCreateCommand (CSMWorld::CreateCommand& command) const;
/// Allow subclasses to wrap the create command together with additional commands
/// into a macro.
virtual void pushCommand (std::auto_ptr<CSMWorld::CreateCommand> command,
const std::string& id);
CSMWorld::Data& getData() const;
QUndoStack& getUndoStack();
const CSMWorld::UniversalId& getCollectionId() const;
std::string getNamespace() const;
private:
void updateNamespace();
public:
GenericCreator (CSMWorld::Data& data, QUndoStack& undoStack,
@ -65,18 +89,22 @@ namespace CSVWorld
virtual void toggleWidgets (bool active = true);
virtual void cloneMode(const std::string& originId,
virtual void cloneMode(const std::string& originId,
const CSMWorld::UniversalId::Type type);
virtual std::string getErrors() const;
///< Return formatted error descriptions for the current state of the creator. if an empty
/// string is returned, there is no error.
virtual void setScope (unsigned int scope);
private slots:
void textChanged (const QString& text);
void create();
void scopeChanged (int index);
};
}

@ -3,8 +3,8 @@
#include "../../model/world/universalid.hpp"
CSVWorld::IdTypeDelegate::IdTypeDelegate
(const ValueList &values, const IconList &icons, QUndoStack& undoStack, QObject *parent)
: DataDisplayDelegate (values, icons, undoStack,
(const ValueList &values, const IconList &icons, CSMDoc::Document& document, QObject *parent)
: DataDisplayDelegate (values, icons, document,
"Display Format", "Referenceable ID Type Display",
parent)
{}
@ -20,8 +20,8 @@ CSVWorld::IdTypeDelegateFactory::IdTypeDelegateFactory()
}
}
CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate (QUndoStack& undoStack,
QObject *parent) const
CSVWorld::CommandDelegate *CSVWorld::IdTypeDelegateFactory::makeDelegate (
CSMDoc::Document& document, QObject *parent) const
{
return new IdTypeDelegate (mValues, mIcons, undoStack, parent);
return new IdTypeDelegate (mValues, mIcons, document, parent);
}

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

Loading…
Cancel
Save